File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\maven-plugin\src\main\java\hudson\maven\MavenBuild.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Olivier Lamy
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.maven;
25
26 import hudson.EnvVars;
27 import hudson.FilePath;
28 import hudson.maven.reporters.MavenArtifactRecord;
29 import hudson.maven.reporters.SurefireArchiver;
30 import hudson.maven.reporters.TestFailureDetector;
31 import hudson.slaves.WorkspaceList;
32 import hudson.slaves.WorkspaceList.Lease;
33 import hudson.maven.agent.AbortException;
34 import hudson.model.AbstractBuild;
35 import hudson.model.BuildListener;
36 import hudson.model.Computer;
37 import hudson.model.Descriptor;
38 import hudson.model.Environment;
39 import hudson.model.Executor;
40 import hudson.model.Node;
41 import hudson.model.Result;
42 import hudson.model.Run;
43 import hudson.model.TaskListener;
44 import hudson.remoting.Channel;
45 import hudson.scm.ChangeLogSet;
46 import hudson.scm.ChangeLogSet.Entry;
47 import hudson.tasks.BuildWrapper;
48 import hudson.tasks.Maven.MavenInstallation;
49 import hudson.tasks.Publisher;
50 import hudson.util.ArgumentListBuilder;
51 import hudson.util.DescribableList;
52 import org.apache.maven.BuildFailureException;
53 import org.apache.maven.execution.MavenSession;
54 import org.apache.maven.execution.ReactorManager;
55 import org.apache.maven.lifecycle.LifecycleExecutionException;
56 import org.apache.maven.monitor.event.EventDispatcher;
57 import org.apache.maven.project.MavenProject;
58 import org.kohsuke.stapler.Ancestor;
59 import org.kohsuke.stapler.Stapler;
60 import org.kohsuke.stapler.StaplerRequest;
61 import org.kohsuke.stapler.export.Exported;
62
63 import java.io.File;
64 import java.io.FileNotFoundException;
65 import java.io.FileOutputStream;
66 import java.io.IOException;
67 import java.io.OutputStream;
68 import java.io.Serializable;
69 import java.util.ArrayList;
70 import java.util.Calendar;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.concurrent.atomic.AtomicBoolean;
76 import java.util.logging.Logger;
77
78 import jenkins.mvn.SettingsProvider;
79
80 /**
81 * {@link Run} for {@link MavenModule}.
82 *
83 * @author Kohsuke Kawaguchi
84 */
85 @SuppressWarnings("deprecation") // as we're restricted to Maven 2.x API here, but compile against Maven 3.x we cannot avoid deprecations
86 public class MavenBuild extends AbstractMavenBuild<MavenModule,MavenBuild> {
87 /**
88 * {@link MavenReporter}s that will contribute project actions.
89 * Can be null if there's none.
90 */
91 /*package*/ List<MavenProjectActionBuilder> projectActionReporters;
92
93 /**
94 * {@link ExecutedMojo}s that record what was run.
95 * Null until some time before the build completes,
96 * or if this build is performed in earlier versions of Hudson.
97 * @since 1.98.
98 */
99 private List<ExecutedMojo> executedMojos;
100
101 public MavenBuild(MavenModule job) throws IOException {
102 super(job);
103 }
104
105 public MavenBuild(MavenModule job, Calendar timestamp) {
106 super(job, timestamp);
107 }
108
109 public MavenBuild(MavenModule project, File buildDir) throws IOException {
110 super(project, buildDir);
111 SurefireArchiver.fixUp(projectActionReporters);
112 }
113
114 @Override
115 public String getUpUrl() {
116 StaplerRequest req = Stapler.getCurrentRequest();
117 if(req!=null) {
118 List<Ancestor> ancs = req.getAncestors();
119 for( int i=1; i<ancs.size(); i++) {
120 if(ancs.get(i).getObject()==this) {
121 if(ancs.get(i-1).getObject() instanceof MavenModuleSetBuild) {
122 // if under MavenModuleSetBuild, "up" means MMSB
123 return ancs.get(i-1).getUrl()+'/';
124 }
125 }
126 }
127 }
128 return super.getUpUrl();
129 }
130
131 @Override
132 public String getDisplayName() {
133 StaplerRequest req = Stapler.getCurrentRequest();
134 if(req!=null) {
135 List<Ancestor> ancs = req.getAncestors();
136 for( int i=1; i<ancs.size(); i++) {
137 if(ancs.get(i).getObject()==this) {
138 if(ancs.get(i-1).getObject() instanceof MavenModuleSetBuild) {
139 // if under MavenModuleSetBuild, display the module name
140 return getParent().getDisplayName();
141 }
142 }
143 }
144 }
145 return super.getDisplayName();
146 }
147
148 /**
149 * Gets the {@link MavenModuleSetBuild} that has the same build number.
150 *
151 * @return
152 * null if no such build exists, which happens when the module build
153 * is manually triggered.
154 * @see #getModuleSetBuild()
155 */
156 public MavenModuleSetBuild getParentBuild() {
157 return getParent().getParent().getBuildByNumber(getNumber());
158 }
159
160 /**
161 * The same as {@link #getParentBuild()}.
162 */
163 @Override
164 public AbstractBuild<?, ?> getRootBuild() {
165 return getParentBuild();
166 }
167
168 /**
169 * Gets the "governing" {@link MavenModuleSet} that has set
170 * the workspace for this build.
171 *
172 * @return
173 * null if no such build exists, which happens if the build
174 * is manually removed.
175 * @see #getParentBuild()
176 */
177 public MavenModuleSetBuild getModuleSetBuild() {
178 return getParent().getParent().getNearestOldBuild(getNumber());
179 }
180
181 @Override
182 public ChangeLogSet<? extends Entry> getChangeSet() {
183 return new FilteredChangeLogSet(this);
184 }
185
186 /**
187 * We always get the changeset from {@link MavenModuleSetBuild}.
188 */
189 @Override
190 public boolean hasChangeSetComputed() {
191 return true;
192 }
193
194 /**
195 * Information about artifacts produced by Maven.
196 */
197 @Exported
198 public MavenArtifactRecord getMavenArtifacts() {
199 return getAction(MavenArtifactRecord.class);
200 }
201
202 /**
203 * Exposes {@code MAVEN_OPTS} to forked processes.
204 *
205 * <p>
206 * See {@link MavenModuleSetBuild#getEnvironment(TaskListener)} for discussion.
207 */
208 @Override
209 public EnvVars getEnvironment(TaskListener log) throws IOException, InterruptedException {
210 EnvVars envs = super.getEnvironment(log);
211
212 // We need to add M2_HOME and the mvn binary to the PATH so if Maven
213 // needs to run Maven it will pick the correct one.
214 // This can happen if maven calls ANT which itself calls Maven
215 // or if Maven calls itself e.g. maven-release-plugin
216 MavenInstallation mvn = project.getParent().getMaven();
217 if (mvn == null)
218 throw new hudson.AbortException(Messages.MavenModuleSetBuild_NoMavenConfigured());
219 mvn = mvn.forEnvironment(envs).forNode(Computer.currentComputer().getNode(), log);
220 mvn.buildEnvVars(envs);
221 return envs;
222 }
223
224 public void registerAsProjectAction(MavenReporter reporter) {
225 if(projectActionReporters==null)
226 projectActionReporters = new ArrayList<MavenProjectActionBuilder>();
227 projectActionReporters.add(reporter);
228 }
229
230 public void registerAsProjectAction(MavenProjectActionBuilder builder) {
231 if(projectActionReporters==null)
232 projectActionReporters = new ArrayList<MavenProjectActionBuilder>();
233 projectActionReporters.add(builder);
234 }
235
236 public List<MavenProjectActionBuilder> getProjectActionBuilders() {
237 if(projectActionReporters==null)
238 return Collections.emptyList();
239 return Collections.unmodifiableList(projectActionReporters);
240 }
241
242 public List<ExecutedMojo> getExecutedMojos() {
243 if(executedMojos==null)
244 return Collections.emptyList();
245 else
246 return Collections.unmodifiableList(executedMojos);
247 }
248
249 @Override
250 public void run() {
251 execute(new MavenBuildExecution());
252
253 getProject().updateTransientActions();
254
255 MavenModuleSetBuild parentBuild = getModuleSetBuild();
256 if(parentBuild!=null)
257 parentBuild.notifyModuleBuild(this);
258 }
259
260 /**
261 * If the parent {@link MavenModuleSetBuild} is kept, keep this record, too.
262 */
263 @Override
264 public String getWhyKeepLog() {
265 MavenModuleSetBuild pb = getParentBuild();
266 if(pb!=null && pb.getWhyKeepLog()!=null)
267 return Messages.MavenBuild_KeptBecauseOfParent(pb);
268 return super.getWhyKeepLog();
269 }
270
271
272 // used by executedMojos.jelly
273 public static ExecutedMojo.Cache createExecutedMojoCache() {
274 return new ExecutedMojo.Cache();
275 }
276
277 /**
278 * Backdoor for {@link MavenModuleSetBuild} to assign workspaces for modules.
279 */
280 @Override
281 protected void setWorkspace(FilePath path) {
282 super.setWorkspace(path);
283 }
284
285 @Override
286 public MavenModule getParent() {// don't know why, but javac wants this
287 return super.getParent();
288 }
289
290 // allow MavenModuleSetBuild to set this.
291 @Override
292 protected void setBuiltOnStr(String builtOn) {
293 super.setBuiltOnStr(builtOn);
294 }
295
296 /**
297 * Runs Maven and builds the project.
298 */
299 private static final class Builder extends MavenBuilder {
300 private final MavenBuildProxy buildProxy;
301 private final AtomicBoolean hasTestFailures = new AtomicBoolean();
302
303 /**
304 * Records of what was executed.
305 */
306 private final List<ExecutedMojo> executedMojos = new ArrayList<ExecutedMojo>();
307 private final ModuleName moduleName;
308
309 private long startTime;
310
311 public Builder(BuildListener listener,MavenBuildProxy buildProxy,MavenModule module, List<String> goals, Map<String,String> systemProps) {
312 super(listener,Collections.singleton(module),goals,systemProps);
313 this.buildProxy = new FilterImpl(buildProxy);
314 this.moduleName = module.getModuleName();
315 }
316
317 private class FilterImpl extends MavenBuildProxy.Filter<MavenBuildProxy> implements Serializable {
318 public FilterImpl(MavenBuildProxy buildProxy) {
319 super(buildProxy);
320 }
321
322 @Override
323 public void executeAsync(final BuildCallable<?,?> program) throws IOException {
324 recordAsynchronousExecution(Channel.current().callAsync(new AsyncInvoker(core,program)));
325 }
326
327 private static final long serialVersionUID = 1L;
328 }
329
330 @Override
331 void preBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
332 for (MavenReporter r : reporters.get(moduleName))
333 r.preBuild(buildProxy,rm.getTopLevelProject(),listener);
334 }
335
336 @Override
337 void postBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
338 buildProxy.setExecutedMojos(executedMojos);
339 for (MavenReporter r : reporters.get(moduleName))
340 r.postBuild(buildProxy,rm.getTopLevelProject(),listener);
341 }
342
343 @Override
344 void preExecute(MavenProject project, MojoInfo info) throws IOException, InterruptedException, AbortException {
345 for (MavenReporter r : reporters.get(moduleName))
346 if(!r.preExecute(buildProxy,project,info,listener))
347 throw new AbortException(r+" failed");
348
349 startTime = System.currentTimeMillis();
350 }
351
352 @Override
353 void postExecute(MavenProject project, MojoInfo info, Exception exception) throws IOException, InterruptedException, AbortException {
354 executedMojos.add(new ExecutedMojo(info,System.currentTimeMillis()-startTime));
355
356 for (MavenReporter r : reporters.get(moduleName)){
357 if(!r.postExecute(buildProxy,project,info,listener,exception)) {
358 throw new AbortException(r+" failed");
359 } else if (r instanceof TestFailureDetector) {
360 if(((TestFailureDetector) r).hasTestFailures()) {
361 hasTestFailures.compareAndSet(false, true);
362 }
363 }
364 }
365 }
366
367 @Override
368 void onReportGenerated(MavenProject project, MavenReportInfo report) throws IOException, InterruptedException, AbortException {
369 for (MavenReporter r : reporters.get(moduleName))
370 if(!r.reportGenerated(buildProxy,project,report,listener))
371 throw new AbortException(r+" failed");
372 }
373
374 @Override
375 void preModule(MavenProject project) throws InterruptedException, IOException, AbortException {
376 for (MavenReporter r : reporters.get(moduleName))
377 if(!r.enterModule(buildProxy,project,listener))
378 throw new AbortException(r+" failed");
379 }
380
381 @Override
382 void postModule(MavenProject project) throws InterruptedException, IOException, AbortException {
383 for (MavenReporter r : reporters.get(moduleName))
384 if(!r.leaveModule(buildProxy,project,listener))
385 throw new AbortException(r+" failed");
386 }
387
388 @Override
389 public boolean hasBuildFailures() {
390 return hasTestFailures.get();
391 }
392
393 private static final long serialVersionUID = 1L;
394 }
395
396 /**
397 * {@link MavenBuildProxy} implementation.
398 */
399 class ProxyImpl implements MavenBuildProxy, Serializable {
400 private static final long serialVersionUID = 8865133776526671879L;
401
402 public <V, T extends Throwable> V execute(BuildCallable<V, T> program) throws T, IOException, InterruptedException {
403 return program.call(MavenBuild.this);
404 }
405
406 /**
407 * This method is implemented by the remote proxy before the invocation
408 * gets to this. So correct code shouldn't be invoking this method on the master ever.
409 *
410 * @deprecated
411 * This helps IDE find coding mistakes when someone tries to call this method.
412 */
413 public final void executeAsync(BuildCallable<?,?> program) throws IOException {
414 throw new AssertionError();
415 }
416
417 public FilePath getRootDir() {
418 return new FilePath(MavenBuild.this.getRootDir());
419 }
420
421 public FilePath getProjectRootDir() {
422 return new FilePath(MavenBuild.this.getParent().getRootDir());
423 }
424
425 public FilePath getModuleSetRootDir() {
426 return new FilePath(MavenBuild.this.getParent().getParent().getRootDir());
427 }
428
429 public FilePath getArtifactsDir() {
430 return new FilePath(MavenBuild.this.getArtifactsDir());
431 }
432
433 public void setResult(Result result) {
434 MavenBuild.this.setResult(result);
435 }
436
437 public Calendar getTimestamp() {
438 return MavenBuild.this.getTimestamp();
439 }
440
441 public long getMilliSecsSinceBuildStart() {
442 return System.currentTimeMillis()-getTimestamp().getTimeInMillis();
443 }
444
445 public boolean isArchivingDisabled() {
446 return MavenBuild.this.getParent().getParent().isArchivingDisabled();
447 }
448
449 public void registerAsProjectAction(MavenReporter reporter) {
450 MavenBuild.this.registerAsProjectAction(reporter);
451 }
452
453 public void registerAsProjectAction(MavenProjectActionBuilder builder) {
454 MavenBuild.this.registerAsProjectAction(builder);
455 }
456
457 public void registerAsAggregatedProjectAction(MavenReporter reporter) {
458 MavenModuleSetBuild pb = getParentBuild();
459 if(pb!=null)
460 pb.registerAsProjectAction(reporter);
461 }
462
463 public void setExecutedMojos(List<ExecutedMojo> executedMojos) {
464 MavenBuild.this.executedMojos = executedMojos;
465 }
466
467 private Object writeReplace() {
468 return Channel.current().export(MavenBuildProxy.class,this);
469 }
470
471 public MavenBuildInformation getMavenBuildInformation() {
472 return new MavenBuildInformation( MavenBuild.this.getModuleSetBuild().getMavenVersionUsed());
473 }
474 }
475
476 public class ProxyImpl2 extends ProxyImpl implements MavenBuildProxy2 {
477 private static final long serialVersionUID = -3377221864644014218L;
478
479 private final SplittableBuildListener listener;
480 long startTime;
481 private final OutputStream log;
482 private final MavenModuleSetBuild parentBuild;
483
484 ProxyImpl2(MavenModuleSetBuild parentBuild,SplittableBuildListener listener) throws FileNotFoundException {
485 this.parentBuild = parentBuild;
486 this.listener = listener;
487 log = new FileOutputStream(getLogFile()); // no buffering so that AJAX clients can see the log live
488 }
489
490 public void start() {
491 onStartBuilding();
492 startTime = System.currentTimeMillis();
493 try {
494 sync();
495 listener.setSideOutputStream(log);
496 } catch (IOException e) {
497 e.printStackTrace();
498 }
499 }
500
501 public void end() {
502 if(result==null)
503 setResult(Result.SUCCESS);
504 onEndBuilding();
505 duration += System.currentTimeMillis()- startTime;
506 parentBuild.notifyModuleBuild(MavenBuild.this);
507 try {
508 sync();
509 listener.setSideOutputStream(null);
510 save();
511 } catch (IOException e) {
512 e.printStackTrace();
513 }
514 }
515
516 /**
517 * Sends the accumulated log in {@link SplittableBuildListener} to the log of this build.
518 */
519 public void appendLastLog() {
520 try {
521 sync();
522 listener.setSideOutputStream(log);
523 listener.setSideOutputStream(null);
524 } catch (IOException e) {
525 e.printStackTrace();
526 }
527 }
528
529 /**
530 * Before we touch I/O streams, we need to make sure all the remote I/O operations are locally completed,
531 * or else we end up switching the log traffic at unaligned moments.
532 */
533 private void sync() throws IOException {
534 try {
535 Channel ch = Channel.current();
536 if (ch!=null)
537 listener.synchronizeOnMark(ch);
538 } catch (InterruptedException e) {
539 // our signature doesn't allow us to throw InterruptedException, so we process it later
540 Thread.currentThread().interrupt();
541 }
542 }
543
544 /**
545 * Performs final clean up. Invoked after the entire aggregator build is completed.
546 */
547 protected void close() {
548 try {
549 sync();
550 log.close();
551 } catch (IOException e) {
552 e.printStackTrace();
553 }
554
555 if(hasntStartedYet()) {
556 // Mark the build as not_built. This method is used when the aggregated build
557 // failed before it didn't even get to this module
558 // OR if the aggregated build is an incremental one and this
559 // module needn't be build.
560 MavenBuild.this.execute(new RunExecution() {
561 public Result run(BuildListener listener) {
562 listener.getLogger().println(Messages.MavenBuild_FailedEarlier());
563 return Result.NOT_BUILT;
564 }
565
566 public void post(BuildListener listener) {
567 }
568
569 public void cleanUp(BuildListener listener) {
570 }
571 });
572 }
573
574 rememberModulesToBuildAgainNextTime();
575 }
576
577 private void rememberModulesToBuildAgainNextTime() {
578 MavenModuleSetBuild moduleSetBuild = getModuleSetBuild();
579
580 if (moduleSetBuild == null) {
581 // ModuleSetBuild is gone, for whatever reason JENKINS-9822
582 return;
583 }
584
585 if(hasntStartedYet()) {
586 // record modules which have not been build though they should have - i.e. because they
587 // have SCM changes.
588 // see JENKINS-5764
589 if (moduleSetBuild.getParent().isIncrementalBuild()
590 && moduleSetBuild.getResult() != Result.SUCCESS
591 && moduleSetBuild.getResult() != Result.UNSTABLE) {
592 UnbuiltModuleAction action = moduleSetBuild.getAction(UnbuiltModuleAction.class);
593 if (action == null) {
594 action = new UnbuiltModuleAction();
595 moduleSetBuild.getActions().add(action);
596 }
597 action.addUnbuiltModule(getParent().getModuleName());
598 }
599 } else {
600 // mark that this module has been built now, if it has previously been remembered as unbuilt
601 // JENKINS-5764
602 MavenModuleSetBuild previousParentBuild = moduleSetBuild.getPreviousBuild();
603 if (previousParentBuild != null) {
604 UnbuiltModuleAction unbuiltModuleAction = previousParentBuild.getAction(UnbuiltModuleAction.class);
605 if (unbuiltModuleAction != null) {
606 unbuiltModuleAction.removeUnbuildModule(getParent().getModuleName());
607 try {
608 previousParentBuild.save();
609 } catch (IOException e) {
610 e.printStackTrace();
611 }
612 }
613 }
614
615 if (moduleSetBuild.getParent().isIncrementalBuild() &&
616 (moduleSetBuild.getResult() != Result.SUCCESS)) {
617
618 // JENKINS-5121: maybe module needs to be deployed on next build over the deployment threshold
619 MavenModuleSet mavenModuleSet = moduleSetBuild.getParent();
620 boolean isDeploying = false;
621 Result deploymentThreshold = Result.SUCCESS;
622 DescribableList<Publisher,Descriptor<Publisher>> publishers = mavenModuleSet.getPublishersList();
623 for (Publisher publisher : publishers) {
624 if (publisher instanceof RedeployPublisher) {
625 isDeploying = true;
626 deploymentThreshold = ((RedeployPublisher)publisher).getTreshold();
627 break;
628 }
629 }
630
631 if (isDeploying && moduleSetBuild.getResult().isWorseThan(deploymentThreshold)) {
632 UnbuiltModuleAction action = moduleSetBuild.getAction(UnbuiltModuleAction.class);
633 if (action == null) {
634 action = new UnbuiltModuleAction();
635 moduleSetBuild.getActions().add(action);
636 }
637 action.addUnbuiltModule(getParent().getModuleName());
638 }
639 }
640 }
641 }
642
643 /**
644 * Gets the build for which this proxy is created.
645 */
646 public MavenBuild owner() {
647 return MavenBuild.this;
648 }
649
650 private Object writeReplace() {
651 // when called from remote, methods need to be executed in the proper Executor's context.
652 return Channel.current().export(MavenBuildProxy2.class,
653 Executor.currentExecutor().newImpersonatingProxy(MavenBuildProxy2.class,this));
654 }
655 }
656
657
658
659 private class MavenBuildExecution extends AbstractBuildExecution {
660 private List<MavenReporter> reporters;
661
662 @Override
663 public MavenBuild getBuild() {
664 return (MavenBuild)super.getBuild();
665 }
666
667 @Override
668 public MavenModule getProject() {
669 return (MavenModule)super.getProject();
670 }
671
672 @Override
673 protected Lease decideWorkspace(Node n, WorkspaceList wsl) throws InterruptedException, IOException {
674 return wsl.allocate(getModuleSetBuild().getModuleRoot().child(getProject().getRelativePath()));
675 }
676
677 protected Result doRun(BuildListener listener) throws Exception {
678 // pick up a list of reporters to run
679 reporters = getProject().createReporters();
680 MavenModuleSet mms = getProject().getParent();
681 if(debug)
682 listener.getLogger().println("Reporters="+reporters);
683
684 for (BuildWrapper w : mms.getBuildWrappersList()) {
685 Environment e = w.setUp(MavenBuild.this, launcher, listener);
686 if (e == null) {
687 return Result.FAILURE;
688 }
689 buildEnvironments.add(e);
690 }
691
692 EnvVars envVars = getEnvironment(listener); // buildEnvironments should be set up first
693
694 MavenInstallation mvn = getProject().getParent().getMaven();
695
696 mvn = mvn.forEnvironment(envVars).forNode(Computer.currentComputer().getNode(), listener);
697
698 MavenInformation mavenInformation = getModuleRoot().act( new MavenVersionCallable( mvn.getHome() ));
699
700 String mavenVersion = mavenInformation.getVersion();
701
702 LOGGER.fine(getFullDisplayName()+" is building with mavenVersion " + mavenVersion + " from file " + mavenInformation.getVersionResourcePath());
703
704
705 boolean maven3orLater = MavenUtil.maven3orLater(mavenVersion);
706
707 ProcessCache.MavenProcess process = MavenBuild.mavenProcessCache.get( launcher.getChannel(), listener, maven3orLater
708 ? new Maven3ProcessFactory(
709 getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null )
710 : new MavenProcessFactory(
711 getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null ));
712
713 ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B");
714 FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this);
715 if(localRepo!=null)
716 // the workspace must be on this node, so getRemote() is safe.
717 margs.add("-Dmaven.repo.local="+localRepo.getRemote());
718
719 String settingsPath = SettingsProvider.getSettingsRemotePath(mms.getSettings(), MavenBuild.this, listener);
720 if (settingsPath != null) {
721 margs.add("-s").add(settingsPath);
722 }
723
724 margs.add("-f",getModuleRoot().child("pom.xml").getRemote());
725 margs.addTokenized(getProject().getGoals());
726
727 Map<String,String> systemProps = new HashMap<String, String>(envVars);
728 // backward compatibility
729 systemProps.put("hudson.build.number",String.valueOf(getNumber()));
730
731 if (maven3orLater)
732 {
733 // FIXME here for maven 3 builds
734 listener.getLogger().println("Building single Maven modules is not implemented for Maven 3, yet!");
735 return Result.ABORTED;
736 }
737 else
738 {
739 boolean normalExit = false;
740 try {
741 Result r = process.call(new Builder(
742 listener,new ProxyImpl(),
743 getProject(), margs.toList(), systemProps));
744 normalExit = true;
745 return r;
746 } finally {
747 if(normalExit) process.recycle();
748 else process.discard();
749
750 // tear down in reverse order
751 boolean failed=false;
752 for( int i=buildEnvironments.size()-1; i>=0; i-- ) {
753 if (!buildEnvironments.get(i).tearDown(MavenBuild.this,listener)) {
754 failed=true;
755 }
756 }
757 // WARNING The return in the finally clause will trump any return before
758 if (failed) return Result.FAILURE;
759 }
760 }
761 }
762
763 public void post2(BuildListener listener) throws Exception {
764 if (reporters != null) {
765 for (MavenReporter reporter : reporters) {
766 reporter.end(MavenBuild.this,launcher,listener);
767 }
768 }
769 }
770
771 }
772
773 public String getMavenOpts(TaskListener listener, EnvVars envVars) {
774 return envVars.expand(expandTokens(listener, getProject().getParent().getMavenOpts()));
775 }
776
777 private static final int MAX_PROCESS_CACHE = 5;
778
779 protected static final ProcessCache mavenProcessCache = new ProcessCache(MAX_PROCESS_CACHE);
780
781 /**
782 * Set true to produce debug output.
783 */
784 public static boolean debug = false;
785
786 private static final Logger LOGGER = Logger.getLogger(MavenBuild.class.getName());
787 }
788