1 package org.apache.maven.lifecycle;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.BuildFailureException;
23 import org.apache.maven.artifact.handler.ArtifactHandler;
24 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
25 import org.apache.maven.artifact.repository.ArtifactRepository;
26 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
27 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
28 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
29 import org.apache.maven.execution.MavenSession;
30 import org.apache.maven.execution.ReactorManager;
31 import org.apache.maven.extension.ExtensionManager;
32 import org.apache.maven.lifecycle.mapping.LifecycleMapping;
33 import org.apache.maven.model.Extension;
34 import org.apache.maven.model.Plugin;
35 import org.apache.maven.model.PluginExecution;
36 import org.apache.maven.model.ReportPlugin;
37 import org.apache.maven.model.ReportSet;
38 import org.apache.maven.monitor.event.EventDispatcher;
39 import org.apache.maven.monitor.event.MavenEvents;
40 import org.apache.maven.plugin.InvalidPluginException;
41 import org.apache.maven.plugin.MojoExecution;
42 import org.apache.maven.plugin.MojoExecutionException;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.apache.maven.plugin.PluginConfigurationException;
45 import org.apache.maven.plugin.PluginManager;
46 import org.apache.maven.plugin.PluginManagerException;
47 import org.apache.maven.plugin.PluginNotFoundException;
48 import org.apache.maven.plugin.descriptor.MojoDescriptor;
49 import org.apache.maven.plugin.descriptor.PluginDescriptor;
50 import org.apache.maven.plugin.lifecycle.Execution;
51 import org.apache.maven.plugin.lifecycle.Phase;
52 import org.apache.maven.plugin.version.PluginVersionNotFoundException;
53 import org.apache.maven.plugin.version.PluginVersionResolutionException;
54 import org.apache.maven.project.MavenProject;
55 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
56 import org.apache.maven.reporting.MavenReport;
57 import org.apache.maven.settings.Settings;
58 import org.codehaus.plexus.PlexusContainerException;
59 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
60 import org.codehaus.plexus.logging.AbstractLogEnabled;
61 import org.codehaus.plexus.util.StringUtils;
62 import org.codehaus.plexus.util.xml.Xpp3Dom;
63 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
64
65 import java.io.IOException;
66 import java.util.ArrayList;
67 import java.util.Collections;
68 import java.util.HashMap;
69 import java.util.Iterator;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.Stack;
73 import java.util.StringTokenizer;
74
75 /**
76 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
77 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
78 * @version $Id: DefaultLifecycleExecutor.java 642436 2008-03-28 23:39:20Z jdcasey $
79 * @todo because of aggregation, we ended up with cli-ish stuff in here (like line() and the project logging, without much of the event handling)
80 */
81 public class DefaultLifecycleExecutor
82 extends AbstractLogEnabled
83 implements LifecycleExecutor
84 {
85 // ----------------------------------------------------------------------
86 // Components
87 // ----------------------------------------------------------------------
88
89 private PluginManager pluginManager;
90
91 private ExtensionManager extensionManager;
92
93 private List lifecycles;
94
95 private ArtifactHandlerManager artifactHandlerManager;
96
97 private List defaultReports;
98
99 private Map phaseToLifecycleMap;
100
101 // ----------------------------------------------------------------------
102 //
103 // ----------------------------------------------------------------------
104
105 /**
106 * Execute a task. Each task may be a phase in the lifecycle or the
107 * execution of a mojo.
108 *
109 * @param session
110 * @param rm
111 * @param dispatcher
112 */
113 public void execute( MavenSession session, ReactorManager rm, EventDispatcher dispatcher )
114 throws BuildFailureException, LifecycleExecutionException
115 {
116 // TODO: This is dangerous, particularly when it's just a collection of loose-leaf projects being built
117 // within the same reactor (using an inclusion pattern to gather them up)...
118 MavenProject rootProject = rm.getTopLevelProject();
119
120 List goals = session.getGoals();
121
122 if ( goals.isEmpty() && rootProject != null )
123 {
124 String goal = rootProject.getDefaultGoal();
125
126 if ( goal != null )
127 {
128 goals = Collections.singletonList( goal );
129 }
130 }
131
132 if ( goals.isEmpty() )
133 {
134 throw new BuildFailureException( "\n\nYou must specify at least one goal. Try 'mvn install' to build or 'mvn -?' for options \nSee http://maven.apache.org for more information.\n\n" );
135 }
136
137 List taskSegments = segmentTaskListByAggregationNeeds( goals, session, rootProject );
138
139 // TODO: probably don't want to do all this up front
140 findExtensions( session );
141
142 executeTaskSegments( taskSegments, rm, session, rootProject, dispatcher );
143 }
144
145 private void findExtensions( MavenSession session )
146 throws LifecycleExecutionException
147 {
148 for ( Iterator i = session.getSortedProjects().iterator(); i.hasNext(); )
149 {
150 MavenProject project = (MavenProject) i.next();
151
152 for ( Iterator j = project.getBuildExtensions().iterator(); j.hasNext(); )
153 {
154 Extension extension = (Extension) j.next();
155 try
156 {
157 extensionManager.addExtension( extension, project, session.getLocalRepository() );
158 }
159 catch ( PlexusContainerException e )
160 {
161 throw new LifecycleExecutionException( "Unable to initialise extensions", e );
162 }
163 catch ( ArtifactResolutionException e )
164 {
165 throw new LifecycleExecutionException( e.getMessage(), e );
166 }
167 catch ( ArtifactNotFoundException e )
168 {
169 throw new LifecycleExecutionException( e.getMessage(), e );
170 }
171 }
172
173 extensionManager.registerWagons();
174
175 try
176 {
177 Map handlers = findArtifactTypeHandlers( project, session.getSettings(), session.getLocalRepository() );
178
179 artifactHandlerManager.addHandlers( handlers );
180 }
181 catch ( PluginNotFoundException e )
182 {
183 throw new LifecycleExecutionException( e.getMessage(), e );
184 }
185 }
186 }
187
188 private void executeTaskSegments( List taskSegments, ReactorManager rm, MavenSession session,
189 MavenProject rootProject, EventDispatcher dispatcher )
190 throws LifecycleExecutionException, BuildFailureException
191 {
192 for ( Iterator it = taskSegments.iterator(); it.hasNext(); )
193 {
194 TaskSegment segment = (TaskSegment) it.next();
195
196 if ( segment.aggregate() )
197 {
198 if ( !rm.isBlackListed( rootProject ) )
199 {
200 line();
201
202 getLogger().info( "Building " + rootProject.getName() );
203
204 getLogger().info( " " + segment );
205
206 line();
207
208 // !! This is ripe for refactoring to an aspect.
209 // Event monitoring.
210 String event = MavenEvents.PROJECT_EXECUTION;
211
212 long buildStartTime = System.currentTimeMillis();
213
214 String target = rootProject.getId() + " ( " + segment + " )";
215
216 dispatcher.dispatchStart( event, target );
217
218 try
219 {
220 session.setCurrentProject( rootProject );
221
222 // only call once, with the top-level project (assumed to be provided as a parameter)...
223 for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
224 {
225 String task = (String) goalIterator.next();
226
227 executeGoalAndHandleFailures( task, session, rootProject, dispatcher, event, rm, buildStartTime,
228 target );
229 }
230
231 rm.registerBuildSuccess( rootProject, System.currentTimeMillis() - buildStartTime );
232
233 }
234 finally
235 {
236 session.setCurrentProject( null );
237 }
238
239 dispatcher.dispatchEnd( event, target );
240 }
241 else
242 {
243 line();
244
245 getLogger().info( "SKIPPING " + rootProject.getName() );
246
247 getLogger().info( " " + segment );
248
249 getLogger().info(
250 "This project has been banned from further executions due to previous failures." );
251
252 line();
253 }
254 }
255 else
256 {
257 List sortedProjects = session.getSortedProjects();
258
259 // iterate over projects, and execute on each...
260 for ( Iterator projectIterator = sortedProjects.iterator(); projectIterator.hasNext(); )
261 {
262 MavenProject currentProject = (MavenProject) projectIterator.next();
263
264 if ( !rm.isBlackListed( currentProject ) )
265 {
266 line();
267
268 getLogger().info( "Building " + currentProject.getName() );
269
270 getLogger().info( " " + segment );
271
272 line();
273
274 // !! This is ripe for refactoring to an aspect.
275 // Event monitoring.
276 String event = MavenEvents.PROJECT_EXECUTION;
277
278 long buildStartTime = System.currentTimeMillis();
279
280 String target = currentProject.getId() + " ( " + segment + " )";
281 dispatcher.dispatchStart( event, target );
282
283 try
284 {
285 session.setCurrentProject( currentProject );
286
287 for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
288 {
289 String task = (String) goalIterator.next();
290
291 executeGoalAndHandleFailures( task, session, currentProject, dispatcher, event, rm,
292 buildStartTime, target );
293 }
294
295 }
296 finally
297 {
298 session.setCurrentProject( null );
299 }
300
301 rm.registerBuildSuccess( currentProject, System.currentTimeMillis() - buildStartTime );
302
303 dispatcher.dispatchEnd( event, target );
304 }
305 else
306 {
307 line();
308
309 getLogger().info( "SKIPPING " + currentProject.getName() );
310
311 getLogger().info( " " + segment );
312
313 getLogger().info(
314 "This project has been banned from further executions due to previous failures." );
315
316 line();
317 }
318 }
319 }
320 }
321 }
322
323 private void executeGoalAndHandleFailures( String task, MavenSession session, MavenProject project,
324 EventDispatcher dispatcher, String event, ReactorManager rm,
325 long buildStartTime, String target )
326 throws BuildFailureException, LifecycleExecutionException
327 {
328 try
329 {
330 executeGoal( task, session, project );
331 }
332 catch ( LifecycleExecutionException e )
333 {
334 dispatcher.dispatchError( event, target, e );
335
336 if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) )
337 {
338 throw e;
339 }
340 }
341 catch ( BuildFailureException e )
342 {
343 dispatcher.dispatchError( event, target, e );
344
345 if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) )
346 {
347 throw e;
348 }
349 }
350 }
351
352 private boolean handleExecutionFailure( ReactorManager rm, MavenProject project, Exception e, String task,
353 long buildStartTime )
354 {
355 rm.registerBuildFailure( project, e, task, System.currentTimeMillis() - buildStartTime );
356
357 if ( ReactorManager.FAIL_FAST.equals( rm.getFailureBehavior() ) )
358 {
359 return true;
360 }
361 else if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) )
362 {
363 rm.blackList( project );
364 }
365 // if NEVER, don't blacklist
366 return false;
367 }
368
369 private List segmentTaskListByAggregationNeeds( List tasks, MavenSession session, MavenProject project )
370 throws LifecycleExecutionException, BuildFailureException
371 {
372 List segments = new ArrayList();
373
374 if ( project != null )
375 {
376
377 TaskSegment currentSegment = null;
378 for ( Iterator it = tasks.iterator(); it.hasNext(); )
379 {
380 String task = (String) it.next();
381
382 // if it's a phase, then we don't need to check whether it's an aggregator.
383 // simply add it to the current task partition.
384 if ( getPhaseToLifecycleMap().containsKey( task ) )
385 {
386 if ( currentSegment != null && currentSegment.aggregate() )
387 {
388 segments.add( currentSegment );
389 currentSegment = null;
390 }
391
392 if ( currentSegment == null )
393 {
394 currentSegment = new TaskSegment();
395 }
396
397 currentSegment.add( task );
398 }
399 else
400 {
401 MojoDescriptor mojo = null;
402 try
403 {
404 // definitely a CLI goal, can use prefix
405 mojo = getMojoDescriptor( task, session, project, task, true, false );
406 }
407 catch ( PluginNotFoundException e )
408 {
409 // TODO: shouldn't hit this, investigate using the same resolution logic as otheres for plugins in the reactor
410 getLogger().info(
411 "Cannot find mojo descriptor for: \'" + task + "\' - Treating as non-aggregator." );
412 getLogger().debug( "", e );
413 }
414
415 // if the mojo descriptor was found, determine aggregator status according to:
416 // 1. whether the mojo declares itself an aggregator
417 // 2. whether the mojo DOES NOT require a project to function (implicitly avoid reactor)
418 if ( mojo != null && ( mojo.isAggregator() || !mojo.isProjectRequired() ) )
419 {
420 if ( currentSegment != null && !currentSegment.aggregate() )
421 {
422 segments.add( currentSegment );
423 currentSegment = null;
424 }
425
426 if ( currentSegment == null )
427 {
428 currentSegment = new TaskSegment( true );
429 }
430
431 currentSegment.add( task );
432 }
433 else
434 {
435 if ( currentSegment != null && currentSegment.aggregate() )
436 {
437 segments.add( currentSegment );
438 currentSegment = null;
439 }
440
441 if ( currentSegment == null )
442 {
443 currentSegment = new TaskSegment();
444 }
445
446 currentSegment.add( task );
447 }
448 }
449 }
450
451 segments.add( currentSegment );
452 }
453 else
454 {
455 TaskSegment segment = new TaskSegment( false );
456 for ( Iterator i = tasks.iterator(); i.hasNext(); )
457 {
458 segment.add( (String) i.next() );
459 }
460 segments.add( segment );
461 }
462
463 return segments;
464 }
465
466 private void executeGoal( String task, MavenSession session, MavenProject project )
467 throws LifecycleExecutionException, BuildFailureException
468 {
469 try
470 {
471 Stack forkEntryPoints = new Stack();
472 if ( getPhaseToLifecycleMap().containsKey( task ) )
473 {
474 Lifecycle lifecycle = getLifecycleForPhase( task );
475
476 // we have a lifecycle phase, so lets bind all the necessary goals
477 Map lifecycleMappings = constructLifecycleMappings( session, task, project, lifecycle );
478 executeGoalWithLifecycle( task, forkEntryPoints, session, lifecycleMappings, project, lifecycle );
479 }
480 else
481 {
482 executeStandaloneGoal( task, forkEntryPoints, session, project );
483 }
484 }
485 catch ( PluginNotFoundException e )
486 {
487 throw new BuildFailureException( "A required plugin was not found: " + e.getMessage(), e );
488 }
489 }
490
491 private void executeGoalWithLifecycle( String task, Stack forkEntryPoints, MavenSession session,
492 Map lifecycleMappings, MavenProject project, Lifecycle lifecycle )
493 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
494 {
495 List goals = processGoalChain( task, lifecycleMappings, lifecycle );
496
497 if ( !goals.isEmpty() )
498 {
499 executeGoals( goals, forkEntryPoints, session, project );
500 }
501 else
502 {
503 getLogger().info( "No goals needed for project - skipping" );
504 }
505 }
506
507 private void executeStandaloneGoal( String task, Stack forkEntryPoints, MavenSession session, MavenProject project )
508 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
509 {
510 // guaranteed to come from the CLI and not be part of a phase
511 MojoDescriptor mojoDescriptor = getMojoDescriptor( task, session, project, task, true, false );
512 executeGoals( Collections.singletonList( new MojoExecution( mojoDescriptor ) ), forkEntryPoints, session,
513 project );
514 }
515
516 private void executeGoals( List goals, Stack forkEntryPoints, MavenSession session, MavenProject project )
517 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
518 {
519 for ( Iterator i = goals.iterator(); i.hasNext(); )
520 {
521 MojoExecution mojoExecution = (MojoExecution) i.next();
522
523 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
524
525 if ( mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null )
526 {
527 forkEntryPoints.push( mojoDescriptor );
528
529 forkLifecycle( mojoDescriptor, forkEntryPoints, session, project );
530
531 forkEntryPoints.pop();
532 }
533
534 if ( mojoDescriptor.isRequiresReports() )
535 {
536 List reports = getReports( project, forkEntryPoints, mojoExecution, session );
537
538 mojoExecution.setReports( reports );
539
540 for ( Iterator j = mojoExecution.getForkedExecutions().iterator(); j.hasNext(); )
541 {
542 MojoExecution forkedExecution = (MojoExecution) j.next();
543 MojoDescriptor descriptor = forkedExecution.getMojoDescriptor();
544
545 if ( descriptor.getExecutePhase() != null )
546 {
547 forkEntryPoints.push( descriptor );
548
549 forkLifecycle( descriptor, forkEntryPoints, session, project );
550
551 forkEntryPoints.pop();
552 }
553 }
554 }
555
556 try
557 {
558 pluginManager.executeMojo( project, mojoExecution, session );
559 }
560 catch ( PluginManagerException e )
561 {
562 throw new LifecycleExecutionException( "Internal error in the plugin manager executing goal '" +
563 mojoDescriptor.getId() + "': " + e.getMessage(), e );
564 }
565 catch ( ArtifactNotFoundException e )
566 {
567 throw new LifecycleExecutionException( e.getMessage(), e );
568 }
569 catch ( InvalidDependencyVersionException e )
570 {
571 throw new LifecycleExecutionException( e.getMessage(), e );
572 }
573 catch ( ArtifactResolutionException e )
574 {
575 throw new LifecycleExecutionException( e.getMessage(), e );
576 }
577 catch ( MojoFailureException e )
578 {
579 throw new BuildFailureException( e.getMessage(), e );
580 }
581 catch ( MojoExecutionException e )
582 {
583 throw new LifecycleExecutionException( e.getMessage(), e );
584 }
585 catch ( PluginConfigurationException e )
586 {
587 throw new LifecycleExecutionException( e.getMessage(), e );
588 }
589 }
590 }
591
592 private List getReports( MavenProject project, Stack forkEntryPoints, MojoExecution mojoExecution, MavenSession session )
593 throws LifecycleExecutionException, PluginNotFoundException
594 {
595 List reportPlugins = project.getReportPlugins();
596
597 if ( project.getModel().getReports() != null )
598 {
599 getLogger().error(
600 "Plugin contains a <reports/> section: this is IGNORED - please use <reporting/> instead." );
601 }
602
603 if ( project.getReporting() == null || !project.getReporting().isExcludeDefaults() )
604 {
605 if ( reportPlugins == null )
606 {
607 reportPlugins = new ArrayList();
608 }
609 else
610 {
611 reportPlugins = new ArrayList( reportPlugins );
612 }
613
614 for ( Iterator i = defaultReports.iterator(); i.hasNext(); )
615 {
616 String report = (String) i.next();
617
618 StringTokenizer tok = new StringTokenizer( report, ":" );
619 if ( tok.countTokens() != 2 )
620 {
621 getLogger().warn( "Invalid default report ignored: '" + report + "' (must be groupId:artifactId)" );
622 }
623 else
624 {
625 String groupId = tok.nextToken();
626 String artifactId = tok.nextToken();
627
628 boolean found = false;
629 for ( Iterator j = reportPlugins.iterator(); j.hasNext() && !found; )
630 {
631 ReportPlugin reportPlugin = (ReportPlugin) j.next();
632 if ( reportPlugin.getGroupId().equals( groupId ) &&
633 reportPlugin.getArtifactId().equals( artifactId ) )
634 {
635 found = true;
636 }
637 }
638
639 if ( !found )
640 {
641 ReportPlugin reportPlugin = new ReportPlugin();
642 reportPlugin.setGroupId( groupId );
643 reportPlugin.setArtifactId( artifactId );
644 reportPlugins.add( reportPlugin );
645 }
646 }
647 }
648 }
649
650 List reports = new ArrayList();
651 if ( reportPlugins != null )
652 {
653 for ( Iterator it = reportPlugins.iterator(); it.hasNext(); )
654 {
655 ReportPlugin reportPlugin = (ReportPlugin) it.next();
656
657 List reportSets = reportPlugin.getReportSets();
658
659 if ( reportSets == null || reportSets.isEmpty() )
660 {
661 reports.addAll( getReports( reportPlugin, forkEntryPoints, null, project, session, mojoExecution ) );
662 }
663 else
664 {
665 for ( Iterator j = reportSets.iterator(); j.hasNext(); )
666 {
667 ReportSet reportSet = (ReportSet) j.next();
668
669 reports.addAll( getReports( reportPlugin, forkEntryPoints, reportSet, project, session, mojoExecution ) );
670 }
671 }
672 }
673 }
674 return reports;
675 }
676
677 private List getReports( ReportPlugin reportPlugin,
678 Stack forkEntryPoints,
679 ReportSet reportSet,
680 MavenProject project,
681 MavenSession session,
682 MojoExecution mojoExecution )
683 throws LifecycleExecutionException, PluginNotFoundException
684 {
685 PluginDescriptor pluginDescriptor = verifyReportPlugin( reportPlugin, project, session );
686
687 List reports = new ArrayList();
688 for ( Iterator i = pluginDescriptor.getMojos().iterator(); i.hasNext(); )
689 {
690 MojoDescriptor mojoDescriptor = (MojoDescriptor) i.next();
691 if ( forkEntryPoints.contains( mojoDescriptor ) )
692 {
693 getLogger().debug( "Omitting report: " + mojoDescriptor.getFullGoalName() + " from reports list. It initiated part of the fork currently executing." );
694 continue;
695 }
696
697 // TODO: check ID is correct for reports
698 // if the POM configured no reports, give all from plugin
699 if ( reportSet == null || reportSet.getReports().contains( mojoDescriptor.getGoal() ) )
700 {
701 String id = null;
702 if ( reportSet != null )
703 {
704 id = reportSet.getId();
705 }
706
707 MojoExecution reportExecution = new MojoExecution( mojoDescriptor, id );
708
709 try
710 {
711 MavenReport reportMojo = pluginManager.getReport( project, reportExecution, session );
712
713 // Comes back null if it was a plugin, not a report - these are mojos in the reporting plugins that are not reports
714 if ( reportMojo != null )
715 {
716 reports.add( reportMojo );
717 mojoExecution.addMojoExecution( reportExecution );
718 }
719 }
720 catch ( PluginManagerException e )
721 {
722 throw new LifecycleExecutionException(
723 "Error getting reports from the plugin '" + reportPlugin.getKey() + "': " + e.getMessage(), e );
724 }
725 catch ( PluginConfigurationException e )
726 {
727 throw new LifecycleExecutionException(
728 "Error getting reports from the plugin '" + reportPlugin.getKey() + "'", e );
729 }
730 catch ( ArtifactNotFoundException e )
731 {
732 throw new LifecycleExecutionException( e.getMessage(), e );
733 }
734 catch ( ArtifactResolutionException e )
735 {
736 throw new LifecycleExecutionException( e.getMessage(), e );
737 }
738 }
739 }
740 return reports;
741 }
742
743 private void forkLifecycle( MojoDescriptor mojoDescriptor, Stack ancestorLifecycleForkers, MavenSession session,
744 MavenProject project )
745 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
746 {
747 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
748 getLogger().info( "Preparing " + pluginDescriptor.getGoalPrefix() + ":" + mojoDescriptor.getGoal() );
749
750 if ( mojoDescriptor.isAggregator() )
751 {
752 for ( Iterator i = session.getSortedProjects().iterator(); i.hasNext(); )
753 {
754 MavenProject reactorProject = (MavenProject) i.next();
755
756 line();
757
758 getLogger().info( "Building " + reactorProject.getName() );
759
760 line();
761
762 forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, reactorProject );
763 }
764 }
765 else
766 {
767 forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, project );
768 }
769 }
770
771 private void forkProjectLifecycle( MojoDescriptor mojoDescriptor, Stack forkEntryPoints, MavenSession session,
772 MavenProject project )
773 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
774 {
775 forkEntryPoints.push( mojoDescriptor );
776
777 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
778
779 String targetPhase = mojoDescriptor.getExecutePhase();
780
781 Map lifecycleMappings = null;
782 if ( targetPhase != null )
783 {
784 Lifecycle lifecycle = getLifecycleForPhase( targetPhase );
785
786 // Create new lifecycle
787 lifecycleMappings = constructLifecycleMappings( session, targetPhase, project, lifecycle );
788
789 String executeLifecycle = mojoDescriptor.getExecuteLifecycle();
790 if ( executeLifecycle != null )
791 {
792 org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
793 try
794 {
795 lifecycleOverlay = pluginDescriptor.getLifecycleMapping( executeLifecycle );
796 }
797 catch ( IOException e )
798 {
799 throw new LifecycleExecutionException( "Unable to read lifecycle mapping file: " + e.getMessage(),
800 e );
801 }
802 catch ( XmlPullParserException e )
803 {
804 throw new LifecycleExecutionException( "Unable to parse lifecycle mapping file: " + e.getMessage(),
805 e );
806 }
807
808 if ( lifecycleOverlay == null )
809 {
810 throw new LifecycleExecutionException( "Lifecycle '" + executeLifecycle + "' not found in plugin" );
811 }
812
813 for ( Iterator i = lifecycleOverlay.getPhases().iterator(); i.hasNext(); )
814 {
815 Phase phase = (Phase) i.next();
816 for ( Iterator j = phase.getExecutions().iterator(); j.hasNext(); )
817 {
818 Execution exec = (Execution) j.next();
819
820 for ( Iterator k = exec.getGoals().iterator(); k.hasNext(); )
821 {
822 String goal = (String) k.next();
823
824 PluginDescriptor lifecyclePluginDescriptor;
825 String lifecycleGoal;
826
827 // Here we are looking to see if we have a mojo from an external plugin.
828 // If we do then we need to lookup the plugin descriptor for the externally
829 // referenced plugin so that we can overly the execution into the lifecycle.
830 // An example of this is the corbertura plugin that needs to call the surefire
831 // plugin in forking mode.
832 //
833 //<phase>
834 // <id>test</id>
835 // <executions>
836 // <execution>
837 // <goals>
838 // <goal>org.apache.maven.plugins:maven-surefire-plugin:test</goal>
839 // </goals>
840 // <configuration>
841 // <classesDirectory>${project.build.directory}/generated-classes/cobertura</classesDirectory>
842 // <ignoreFailures>true</ignoreFailures>
843 // <forkMode>once</forkMode>
844 // </configuration>
845 // </execution>
846 // </executions>
847 //</phase>
848
849 // ----------------------------------------------------------------------
850 //
851 // ----------------------------------------------------------------------
852
853 if ( goal.indexOf( ":" ) > 0 )
854 {
855 String[] s = StringUtils.split( goal, ":" );
856
857 String groupId = s[0];
858 String artifactId = s[1];
859 lifecycleGoal = s[2];
860
861 Plugin plugin = new Plugin();
862 plugin.setGroupId( groupId );
863 plugin.setArtifactId( artifactId );
864 lifecyclePluginDescriptor = verifyPlugin( plugin, project, session.getSettings(),
865 session.getLocalRepository() );
866 if ( lifecyclePluginDescriptor == null )
867 {
868 throw new LifecycleExecutionException(
869 "Unable to find plugin " + groupId + ":" + artifactId );
870 }
871 }
872 else
873 {
874 lifecyclePluginDescriptor = pluginDescriptor;
875 lifecycleGoal = goal;
876 }
877
878 Xpp3Dom configuration = (Xpp3Dom) exec.getConfiguration();
879 if ( phase.getConfiguration() != null )
880 {
881 configuration = Xpp3Dom.mergeXpp3Dom( new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ),
882 configuration );
883 }
884
885 MojoDescriptor desc = getMojoDescriptor( lifecyclePluginDescriptor, lifecycleGoal );
886 MojoExecution mojoExecution = new MojoExecution( desc, configuration );
887 addToLifecycleMappings( lifecycleMappings, phase.getId(), mojoExecution,
888 session.getSettings() );
889 }
890 }
891
892 if ( phase.getConfiguration() != null )
893 {
894 // Merge in general configuration for a phase.
895 // TODO: this is all kind of backwards from the POMM. Let's align it all under 2.1.
896 // We should create a new lifecycle executor for modelVersion >5.0.0
897 for ( Iterator j = lifecycleMappings.values().iterator(); j.hasNext(); )
898 {
899 List tasks = (List) j.next();
900
901 for ( Iterator k = tasks.iterator(); k.hasNext(); )
902 {
903 MojoExecution exec = (MojoExecution) k.next();
904
905 Xpp3Dom configuration = Xpp3Dom.mergeXpp3Dom(
906 new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ), exec.getConfiguration() );
907
908 exec.setConfiguration( configuration );
909 }
910 }
911 }
912
913 }
914 }
915
916 removeFromLifecycle( forkEntryPoints, lifecycleMappings );
917 }
918
919 MavenProject executionProject = new MavenProject( project );
920 if ( targetPhase != null )
921 {
922 Lifecycle lifecycle = getLifecycleForPhase( targetPhase );
923
924 executeGoalWithLifecycle( targetPhase, forkEntryPoints, session, lifecycleMappings, executionProject,
925 lifecycle );
926 }
927 else
928 {
929 String goal = mojoDescriptor.getExecuteGoal();
930 MojoDescriptor desc = getMojoDescriptor( pluginDescriptor, goal );
931 executeGoals( Collections.singletonList( new MojoExecution( desc ) ), forkEntryPoints, session,
932 executionProject );
933 }
934 project.setExecutionProject( executionProject );
935 }
936
937 private Lifecycle getLifecycleForPhase( String phase )
938 throws BuildFailureException, LifecycleExecutionException
939 {
940 Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap().get( phase );
941
942 if ( lifecycle == null )
943 {
944 throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" );
945 }
946 return lifecycle;
947 }
948
949 private MojoDescriptor getMojoDescriptor( PluginDescriptor pluginDescriptor, String goal )
950 throws LifecycleExecutionException
951 {
952 MojoDescriptor desc = pluginDescriptor.getMojo( goal );
953
954 if ( desc == null )
955 {
956 String message =
957 "Required goal '" + goal + "' not found in plugin '" + pluginDescriptor.getGoalPrefix() + "'";
958 int index = goal.indexOf( ':' );
959 if ( index >= 0 )
960 {
961 String prefix = goal.substring( index + 1 );
962 if ( prefix.equals( pluginDescriptor.getGoalPrefix() ) )
963 {
964 message = message + " (goals should not be prefixed - try '" + prefix + "')";
965 }
966 }
967 throw new LifecycleExecutionException( message );
968 }
969 return desc;
970 }
971
972 private void removeFromLifecycle( Stack lifecycleForkers, Map lifecycleMappings )
973 {
974 for ( Iterator lifecycleIterator = lifecycleMappings.values().iterator(); lifecycleIterator.hasNext(); )
975 {
976 List tasks = (List) lifecycleIterator.next();
977
978 for ( Iterator taskIterator = tasks.iterator(); taskIterator.hasNext(); )
979 {
980 MojoExecution execution = (MojoExecution) taskIterator.next();
981
982 if ( lifecycleForkers.contains( execution.getMojoDescriptor() ) )
983 {
984 taskIterator.remove();
985 getLogger().warn( "Removing: " + execution.getMojoDescriptor().getGoal()
986 + " from forked lifecycle, to prevent recursive invocation." );
987 }
988 }
989 }
990 }
991
992 private Map constructLifecycleMappings( MavenSession session, String selectedPhase, MavenProject project,
993 Lifecycle lifecycle )
994 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
995 {
996 // first, bind those associated with the packaging
997 Map lifecycleMappings = bindLifecycleForPackaging( session, selectedPhase, project, lifecycle );
998
999 // next, loop over plugins and for any that have a phase, bind it
1000 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1001 {
1002 Plugin plugin = (Plugin) i.next();
1003
1004 bindPluginToLifecycle( plugin, session, lifecycleMappings, project );
1005 }
1006
1007 return lifecycleMappings;
1008 }
1009
1010 private Map bindLifecycleForPackaging( MavenSession session, String selectedPhase, MavenProject project,
1011 Lifecycle lifecycle )
1012 throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
1013 {
1014 Map mappings = findMappingsForLifecycle( session, project, lifecycle );
1015
1016 List optionalMojos = findOptionalMojosForLifecycle( session, project, lifecycle );
1017
1018 Map lifecycleMappings = new HashMap();
1019
1020 for ( Iterator i = lifecycle.getPhases().iterator(); i.hasNext(); )
1021 {
1022 String phase = (String) i.next();
1023
1024 String phaseTasks = (String) mappings.get( phase );
1025
1026 if ( phaseTasks != null )
1027 {
1028 for ( StringTokenizer tok = new StringTokenizer( phaseTasks, "," ); tok.hasMoreTokens(); )
1029 {
1030 String goal = tok.nextToken().trim();
1031
1032 // Not from the CLI, don't use prefix
1033 MojoDescriptor mojoDescriptor = getMojoDescriptor( goal, session, project, selectedPhase, false,
1034 optionalMojos.contains( goal ) );
1035
1036 if ( mojoDescriptor == null )
1037 {
1038 continue;
1039 }
1040
1041 if ( mojoDescriptor.isDirectInvocationOnly() )
1042 {
1043 throw new LifecycleExecutionException( "Mojo: \'" + goal +
1044 "\' requires direct invocation. It cannot be used as part of lifecycle: \'" +
1045 project.getPackaging() + "\'." );
1046 }
1047
1048 addToLifecycleMappings( lifecycleMappings, phase, new MojoExecution( mojoDescriptor ),
1049 session.getSettings() );
1050 }
1051 }
1052
1053 if ( phase.equals( selectedPhase ) )
1054 {
1055 break;
1056 }
1057 }
1058
1059 return lifecycleMappings;
1060 }
1061
1062 private Map findMappingsForLifecycle( MavenSession session, MavenProject project, Lifecycle lifecycle )
1063 throws LifecycleExecutionException, PluginNotFoundException
1064 {
1065 String packaging = project.getPackaging();
1066 Map mappings = null;
1067
1068 LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging,
1069 session.getSettings(), session.getLocalRepository() );
1070 if ( m != null )
1071 {
1072 mappings = m.getPhases( lifecycle.getId() );
1073 }
1074
1075 Map defaultMappings = lifecycle.getDefaultPhases();
1076
1077 if ( mappings == null )
1078 {
1079 try
1080 {
1081 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
1082 mappings = m.getPhases( lifecycle.getId() );
1083 }
1084 catch ( ComponentLookupException e )
1085 {
1086 if ( defaultMappings == null )
1087 {
1088 throw new LifecycleExecutionException(
1089 "Cannot find lifecycle mapping for packaging: \'" + packaging + "\'.", e );
1090 }
1091 }
1092 }
1093
1094 if ( mappings == null )
1095 {
1096 if ( defaultMappings == null )
1097 {
1098 throw new LifecycleExecutionException(
1099 "Cannot find lifecycle mapping for packaging: \'" + packaging + "\', and there is no default" );
1100 }
1101 else
1102 {
1103 mappings = defaultMappings;
1104 }
1105 }
1106
1107 return mappings;
1108 }
1109
1110 private List findOptionalMojosForLifecycle( MavenSession session, MavenProject project, Lifecycle lifecycle )
1111 throws LifecycleExecutionException, PluginNotFoundException
1112 {
1113 String packaging = project.getPackaging();
1114 List optionalMojos = null;
1115
1116 LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session
1117 .getSettings(), session.getLocalRepository() );
1118
1119 if ( m != null )
1120 {
1121 optionalMojos = m.getOptionalMojos( lifecycle.getId() );
1122 }
1123
1124 if ( optionalMojos == null )
1125 {
1126 try
1127 {
1128 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
1129 optionalMojos = m.getOptionalMojos( lifecycle.getId() );
1130 }
1131 catch ( ComponentLookupException e )
1132 {
1133 getLogger().debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: " +
1134 lifecycle.getId() + ". Error: " + e.getMessage(), e );
1135 }
1136 }
1137
1138 if ( optionalMojos == null )
1139 {
1140 optionalMojos = Collections.EMPTY_LIST;
1141 }
1142
1143 return optionalMojos;
1144 }
1145
1146 private Object findExtension( MavenProject project, String role, String roleHint, Settings settings,
1147 ArtifactRepository localRepository )
1148 throws LifecycleExecutionException, PluginNotFoundException
1149 {
1150 Object pluginComponent = null;
1151
1152 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext() && pluginComponent == null; )
1153 {
1154 Plugin plugin = (Plugin) i.next();
1155
1156 if ( plugin.isExtensions() )
1157 {
1158 verifyPlugin( plugin, project, settings, localRepository );
1159
1160 // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly
1161 try
1162 {
1163 pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint );
1164 }
1165 catch ( ComponentLookupException e )
1166 {
1167 getLogger().debug( "Unable to find the lifecycle component in the extension", e );
1168 }
1169 catch ( PluginManagerException e )
1170 {
1171 throw new LifecycleExecutionException(
1172 "Error getting extensions from the plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
1173 }
1174 }
1175 }
1176 return pluginComponent;
1177 }
1178
1179 /**
1180 * @todo Not particularly happy about this. Would like WagonManager and ArtifactTypeHandlerManager to be able to
1181 * lookup directly, or have them passed in
1182 */
1183 private Map findArtifactTypeHandlers( MavenProject project, Settings settings, ArtifactRepository localRepository )
1184 throws LifecycleExecutionException, PluginNotFoundException
1185 {
1186 Map map = new HashMap();
1187 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1188 {
1189 Plugin plugin = (Plugin) i.next();
1190
1191 if ( plugin.isExtensions() )
1192 {
1193 verifyPlugin( plugin, project, settings, localRepository );
1194
1195 // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly
1196 try
1197 {
1198 Map components = pluginManager.getPluginComponents( plugin, ArtifactHandler.ROLE );
1199 map.putAll( components );
1200 }
1201 catch ( ComponentLookupException e )
1202 {
1203 getLogger().debug( "Unable to find the lifecycle component in the extension", e );
1204 }
1205 catch ( PluginManagerException e )
1206 {
1207 throw new LifecycleExecutionException( "Error looking up available components from plugin '" +
1208 plugin.getKey() + "': " + e.getMessage(), e );
1209 }
1210
1211 // shudder...
1212 for ( Iterator j = map.values().iterator(); j.hasNext(); )
1213 {
1214 ArtifactHandler handler = (ArtifactHandler) j.next();
1215 if ( project.getPackaging().equals( handler.getPackaging() ) )
1216 {
1217 project.getArtifact().setArtifactHandler( handler );
1218 }
1219 }
1220 }
1221 }
1222 return map;
1223 }
1224
1225 /**
1226 * Take each mojo contained with a plugin, look to see whether it contributes to a
1227 * phase in the lifecycle and if it does place it at the end of the list of goals
1228 * to execute for that given phase.
1229 *
1230 * @param project
1231 * @param session
1232 */
1233 private void bindPluginToLifecycle( Plugin plugin, MavenSession session, Map phaseMap, MavenProject project )
1234 throws LifecycleExecutionException, PluginNotFoundException
1235 {
1236 Settings settings = session.getSettings();
1237
1238 PluginDescriptor pluginDescriptor =
1239 verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
1240
1241 if ( pluginDescriptor.getMojos() != null && !pluginDescriptor.getMojos().isEmpty() )
1242 {
1243 // use the plugin if inherit was true in a base class, or it is in the current POM, otherwise use the default inheritence setting
1244 if ( plugin.isInheritanceApplied() || pluginDescriptor.isInheritedByDefault() )
1245 {
1246 if ( plugin.getGoals() != null )
1247 {
1248 getLogger().error(
1249 "Plugin contains a <goals/> section: this is IGNORED - please use <executions/> instead." );
1250 }
1251
1252 List executions = plugin.getExecutions();
1253
1254 if ( executions != null )
1255 {
1256 for ( Iterator it = executions.iterator(); it.hasNext(); )
1257 {
1258 PluginExecution execution = (PluginExecution) it.next();
1259
1260 bindExecutionToLifecycle( pluginDescriptor, phaseMap, execution, settings );
1261 }
1262 }
1263 }
1264 }
1265 }
1266
1267 private PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings,
1268 ArtifactRepository localRepository )
1269 throws LifecycleExecutionException, PluginNotFoundException
1270 {
1271 PluginDescriptor pluginDescriptor;
1272 try
1273 {
1274 pluginDescriptor = pluginManager.verifyPlugin( plugin, project, settings, localRepository );
1275 }
1276 catch ( PluginManagerException e )
1277 {
1278 throw new LifecycleExecutionException(
1279 "Internal error in the plugin manager getting plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
1280 }
1281 catch ( PluginVersionResolutionException e )
1282 {
1283 throw new LifecycleExecutionException( e.getMessage(), e );
1284 }
1285 catch ( InvalidVersionSpecificationException e )
1286 {
1287 throw new LifecycleExecutionException( e.getMessage(), e );
1288 }
1289 catch ( InvalidPluginException e )
1290 {
1291 throw new LifecycleExecutionException( e.getMessage(), e );
1292 }
1293 catch ( ArtifactNotFoundException e )
1294 {
1295 throw new LifecycleExecutionException( e.getMessage(), e );
1296 }
1297 catch ( ArtifactResolutionException e )
1298 {
1299 throw new LifecycleExecutionException( e.getMessage(), e );
1300 }
1301 catch ( PluginVersionNotFoundException e )
1302 {
1303 throw new LifecycleExecutionException( e.getMessage(), e );
1304 }
1305 return pluginDescriptor;
1306 }
1307
1308 private PluginDescriptor verifyReportPlugin( ReportPlugin plugin, MavenProject project, MavenSession session )
1309 throws LifecycleExecutionException, PluginNotFoundException
1310 {
1311 PluginDescriptor pluginDescriptor;
1312 try
1313 {
1314 pluginDescriptor = pluginManager.verifyReportPlugin( plugin, project, session );
1315 }
1316 catch ( PluginManagerException e )
1317 {
1318 throw new LifecycleExecutionException(
1319 "Internal error in the plugin manager getting report '" + plugin.getKey() + "': " + e.getMessage(), e );
1320 }
1321 catch ( PluginVersionResolutionException e )
1322 {
1323 throw new LifecycleExecutionException( e.getMessage(), e );
1324 }
1325 catch ( InvalidVersionSpecificationException e )
1326 {
1327 throw new LifecycleExecutionException( e.getMessage(), e );
1328 }
1329 catch ( InvalidPluginException e )
1330 {
1331 throw new LifecycleExecutionException( e.getMessage(), e );
1332 }
1333 catch ( ArtifactNotFoundException e )
1334 {
1335 throw new LifecycleExecutionException( e.getMessage(), e );
1336 }
1337 catch ( ArtifactResolutionException e )
1338 {
1339 throw new LifecycleExecutionException( e.getMessage(), e );
1340 }
1341 catch ( PluginVersionNotFoundException e )
1342 {
1343 throw new LifecycleExecutionException( e.getMessage(), e );
1344 }
1345 return pluginDescriptor;
1346 }
1347
1348 private void bindExecutionToLifecycle( PluginDescriptor pluginDescriptor, Map phaseMap, PluginExecution execution,
1349 Settings settings )
1350 throws LifecycleExecutionException
1351 {
1352 for ( Iterator i = execution.getGoals().iterator(); i.hasNext(); )
1353 {
1354 String goal = (String) i.next();
1355
1356 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
1357 if ( mojoDescriptor == null )
1358 {
1359 throw new LifecycleExecutionException(
1360 "'" + goal + "' was specified in an execution, but not found in the plugin" );
1361 }
1362
1363 // We have to check to see that the inheritance rules have been applied before binding this mojo.
1364 if ( execution.isInheritanceApplied() || mojoDescriptor.isInheritedByDefault() )
1365 {
1366 MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
1367
1368 String phase = execution.getPhase();
1369
1370 if ( phase == null )
1371 {
1372 // if the phase was not in the configuration, use the phase in the descriptor
1373 phase = mojoDescriptor.getPhase();
1374 }
1375
1376 if ( phase != null )
1377 {
1378 if ( mojoDescriptor.isDirectInvocationOnly() )
1379 {
1380 throw new LifecycleExecutionException( "Mojo: \'" + goal +
1381 "\' requires direct invocation. It cannot be used as part of the lifecycle (it was included via the POM)." );
1382 }
1383
1384 addToLifecycleMappings( phaseMap, phase, mojoExecution, settings );
1385 }
1386 }
1387 }
1388 }
1389
1390 private void addToLifecycleMappings( Map lifecycleMappings, String phase, MojoExecution mojoExecution,
1391 Settings settings )
1392 {
1393 List goals = (List) lifecycleMappings.get( phase );
1394
1395 if ( goals == null )
1396 {
1397 goals = new ArrayList();
1398 lifecycleMappings.put( phase, goals );
1399 }
1400
1401 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
1402 if ( settings.isOffline() && mojoDescriptor.isOnlineRequired() )
1403 {
1404 String goal = mojoDescriptor.getGoal();
1405 getLogger().warn( goal + " requires online mode, but maven is currently offline. Disabling " + goal + "." );
1406 }
1407 else
1408 {
1409 goals.add( mojoExecution );
1410 }
1411 }
1412
1413 private List processGoalChain( String task, Map phaseMap, Lifecycle lifecycle )
1414 {
1415 List goals = new ArrayList();
1416
1417 // only execute up to the given phase
1418 int index = lifecycle.getPhases().indexOf( task );
1419
1420 for ( int i = 0; i <= index; i++ )
1421 {
1422 String p = (String) lifecycle.getPhases().get( i );
1423
1424 List phaseGoals = (List) phaseMap.get( p );
1425
1426 if ( phaseGoals != null )
1427 {
1428 goals.addAll( phaseGoals );
1429 }
1430 }
1431 return goals;
1432 }
1433
1434 private MojoDescriptor getMojoDescriptor( String task, MavenSession session, MavenProject project,
1435 String invokedVia, boolean canUsePrefix, boolean isOptionalMojo )
1436 throws BuildFailureException, LifecycleExecutionException, PluginNotFoundException
1437 {
1438 String goal;
1439 Plugin plugin;
1440
1441 PluginDescriptor pluginDescriptor = null;
1442
1443 try
1444 {
1445 StringTokenizer tok = new StringTokenizer( task, ":" );
1446 int numTokens = tok.countTokens();
1447
1448 if ( numTokens == 2 )
1449 {
1450 if ( !canUsePrefix )
1451 {
1452 String msg = "Mapped-prefix lookup of mojos are only supported from direct invocation. " +
1453 "Please use specification of the form groupId:artifactId[:version]:goal instead. " +
1454 "(Offending mojo: \'" + task + "\', invoked via: \'" + invokedVia + "\')";
1455 throw new LifecycleExecutionException( msg );
1456 }
1457
1458 String prefix = tok.nextToken();
1459 goal = tok.nextToken();
1460
1461 // Steps for retrieving the plugin model instance:
1462 // 1. request directly from the plugin collector by prefix
1463 pluginDescriptor = pluginManager.getPluginDescriptorForPrefix( prefix );
1464
1465 // 2. look in the repository via search groups
1466 if ( pluginDescriptor == null )
1467 {
1468 plugin = pluginManager.getPluginDefinitionForPrefix( prefix, session, project );
1469 }
1470 else
1471 {
1472 plugin = new Plugin();
1473
1474 plugin.setGroupId( pluginDescriptor.getGroupId() );
1475 plugin.setArtifactId( pluginDescriptor.getArtifactId() );
1476 plugin.setVersion( pluginDescriptor.getVersion() );
1477 }
1478
1479 // 3. search plugins in the current POM
1480 if ( plugin == null )
1481 {
1482 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1483 {
1484 Plugin buildPlugin = (Plugin) i.next();
1485
1486 PluginDescriptor desc = verifyPlugin( buildPlugin, project, session.getSettings(), session
1487 .getLocalRepository() );
1488 if ( prefix.equals( desc.getGoalPrefix() ) )
1489 {
1490 plugin = buildPlugin;
1491 }
1492 }
1493 }
1494
1495 // 4. default to o.a.m.plugins and maven-<prefix>-plugin
1496 if ( plugin == null )
1497 {
1498 plugin = new Plugin();
1499 plugin.setGroupId( PluginDescriptor.getDefaultPluginGroupId() );
1500 plugin.setArtifactId( PluginDescriptor.getDefaultPluginArtifactId( prefix ) );
1501 }
1502 }
1503 else if ( numTokens == 3 || numTokens == 4 )
1504 {
1505 plugin = new Plugin();
1506
1507 plugin.setGroupId( tok.nextToken() );
1508 plugin.setArtifactId( tok.nextToken() );
1509
1510 if ( numTokens == 4 )
1511 {
1512 plugin.setVersion( tok.nextToken() );
1513 }
1514
1515 goal = tok.nextToken();
1516 }
1517 else
1518 {
1519 String message = "Invalid task '" + task + "': you must specify a valid lifecycle phase, or" +
1520 " a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal";
1521 throw new BuildFailureException( message );
1522 }
1523
1524 if ( plugin.getVersion() == null )
1525 {
1526 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1527 {
1528 Plugin buildPlugin = (Plugin) i.next();
1529
1530 if ( buildPlugin.getKey().equals( plugin.getKey() ) )
1531 {
1532 plugin = buildPlugin;
1533 break;
1534 }
1535 }
1536
1537 project.injectPluginManagementInfo( plugin );
1538 }
1539
1540 if ( pluginDescriptor == null )
1541 {
1542 pluginDescriptor = verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
1543 }
1544
1545 // this has been simplified from the old code that injected the plugin management stuff, since
1546 // pluginManagement injection is now handled by the project method.
1547 project.addPlugin( plugin );
1548
1549 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
1550 if ( mojoDescriptor == null )
1551 {
1552 if ( isOptionalMojo )
1553 {
1554 getLogger().info( "Skipping missing optional mojo: " + task );
1555 }
1556 else
1557 {
1558 throw new BuildFailureException( "Required goal not found: " + task + " in "
1559 + pluginDescriptor.getId() );
1560 }
1561 }
1562
1563 return mojoDescriptor;
1564 }
1565 catch ( PluginNotFoundException e )
1566 {
1567 if ( isOptionalMojo )
1568 {
1569 getLogger().info( "Skipping missing optional mojo: " + task );
1570 getLogger().debug( "Mojo: " + task + " could not be found. Reason: " + e.getMessage(), e );
1571 }
1572 else
1573 {
1574 throw e;
1575 }
1576 }
1577
1578 return null;
1579 }
1580
1581 protected void line()
1582 {
1583 getLogger().info( "------------------------------------------------------------------------" );
1584 }
1585
1586 public Map getPhaseToLifecycleMap()
1587 throws LifecycleExecutionException
1588 {
1589 if ( phaseToLifecycleMap == null )
1590 {
1591 phaseToLifecycleMap = new HashMap();
1592
1593 for ( Iterator i = lifecycles.iterator(); i.hasNext(); )
1594 {
1595 Lifecycle lifecycle = (Lifecycle) i.next();
1596
1597 for ( Iterator p = lifecycle.getPhases().iterator(); p.hasNext(); )
1598 {
1599 String phase = (String) p.next();
1600
1601 if ( phaseToLifecycleMap.containsKey( phase ) )
1602 {
1603 Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase );
1604 throw new LifecycleExecutionException( "Phase '" + phase +
1605 "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '" +
1606 prevLifecycle.getId() + "'" );
1607 }
1608 else
1609 {
1610 phaseToLifecycleMap.put( phase, lifecycle );
1611 }
1612 }
1613 }
1614 }
1615 return phaseToLifecycleMap;
1616 }
1617
1618 private static class TaskSegment
1619 {
1620 private boolean aggregate;
1621
1622 private List tasks = new ArrayList();
1623
1624 TaskSegment()
1625 {
1626
1627 }
1628
1629 TaskSegment( boolean aggregate )
1630 {
1631 this.aggregate = aggregate;
1632 }
1633
1634 public String toString()
1635 {
1636 StringBuffer message = new StringBuffer();
1637
1638 message.append( " task-segment: [" );
1639
1640 for ( Iterator it = tasks.iterator(); it.hasNext(); )
1641 {
1642 String task = (String) it.next();
1643
1644 message.append( task );
1645
1646 if ( it.hasNext() )
1647 {
1648 message.append( ", " );
1649 }
1650 }
1651
1652 message.append( "]" );
1653
1654 if ( aggregate )
1655 {
1656 message.append( " (aggregator-style)" );
1657 }
1658
1659 return message.toString();
1660 }
1661
1662 boolean aggregate()
1663 {
1664 return aggregate;
1665 }
1666
1667 void add( String task )
1668 {
1669 tasks.add( task );
1670 }
1671
1672 List getTasks()
1673 {
1674 return tasks;
1675 }
1676 }
1677 }