1 package org.apache.maven.lifecycle.internal;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.lifecycle.DefaultLifecycles;
33 import org.apache.maven.lifecycle.Lifecycle;
34 import org.apache.maven.lifecycle.LifecycleMappingDelegate;
35 import org.apache.maven.lifecycle.LifecycleNotFoundException;
36 import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
37 import org.apache.maven.lifecycle.MavenExecutionPlan;
38 import org.apache.maven.lifecycle.MojoExecutionConfigurator;
39 import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
40 import org.apache.maven.plugin.BuildPluginManager;
41 import org.apache.maven.plugin.InvalidPluginDescriptorException;
42 import org.apache.maven.plugin.MojoExecution;
43 import org.apache.maven.plugin.MojoNotFoundException;
44 import org.apache.maven.plugin.PluginDescriptorParsingException;
45 import org.apache.maven.plugin.PluginNotFoundException;
46 import org.apache.maven.plugin.PluginResolutionException;
47 import org.apache.maven.plugin.descriptor.MojoDescriptor;
48 import org.apache.maven.plugin.descriptor.Parameter;
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.prefix.NoPluginFoundForPrefixException;
53 import org.apache.maven.plugin.version.PluginVersionResolutionException;
54 import org.apache.maven.plugin.version.PluginVersionResolver;
55 import org.apache.maven.project.MavenProject;
56 import org.codehaus.plexus.component.annotations.Component;
57 import org.codehaus.plexus.component.annotations.Requirement;
58 import org.codehaus.plexus.util.StringUtils;
59 import org.codehaus.plexus.util.xml.Xpp3Dom;
60 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
61
62 import com.google.common.collect.ImmutableMap;
63
64
65
66
67
68
69
70
71 @Component( role = LifecycleExecutionPlanCalculator.class )
72 public class DefaultLifecycleExecutionPlanCalculator
73 implements LifecycleExecutionPlanCalculator
74 {
75 @Requirement
76 private PluginVersionResolver pluginVersionResolver;
77
78 @Requirement
79 private BuildPluginManager pluginManager;
80
81 @Requirement
82 private DefaultLifecycles defaultLifeCycles;
83
84 @Requirement
85 private MojoDescriptorCreator mojoDescriptorCreator;
86
87 @Requirement
88 private LifecyclePluginResolver lifecyclePluginResolver;
89
90 @Requirement( hint = DefaultLifecycleMappingDelegate.HINT )
91 private LifecycleMappingDelegate standardDelegate;
92
93 @Requirement
94 private Map<String, LifecycleMappingDelegate> delegates;
95
96 @Requirement
97 private Map<String, MojoExecutionConfigurator> mojoExecutionConfigurators;
98
99 @SuppressWarnings( { "UnusedDeclaration" } )
100 public DefaultLifecycleExecutionPlanCalculator()
101 {
102 }
103
104
105 public DefaultLifecycleExecutionPlanCalculator( BuildPluginManager pluginManager,
106 DefaultLifecycles defaultLifeCycles,
107 MojoDescriptorCreator mojoDescriptorCreator,
108 LifecyclePluginResolver lifecyclePluginResolver )
109 {
110 this.pluginManager = pluginManager;
111 this.defaultLifeCycles = defaultLifeCycles;
112 this.mojoDescriptorCreator = mojoDescriptorCreator;
113 this.lifecyclePluginResolver = lifecyclePluginResolver;
114 this.mojoExecutionConfigurators =
115 ImmutableMap.of( "default", (MojoExecutionConfigurator) new DefaultMojoExecutionConfigurator() );
116 }
117
118 @Override
119 public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks,
120 boolean setup )
121 throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
122 PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
123 NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
124 {
125 lifecyclePluginResolver.resolveMissingPluginVersions( project, session );
126
127 final List<MojoExecution> executions = calculateMojoExecutions( session, project, tasks );
128
129 if ( setup )
130 {
131 setupMojoExecutions( session, project, executions );
132 }
133
134 final List<ExecutionPlanItem> planItem = ExecutionPlanItem.createExecutionPlanItems( project, executions );
135
136 return new MavenExecutionPlan( planItem, defaultLifeCycles );
137 }
138
139 @Override
140 public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
141 throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
142 PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
143 NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
144 {
145 return calculateExecutionPlan( session, project, tasks, true );
146 }
147
148 private void setupMojoExecutions( MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions )
149 throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
150 MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
151 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
152 {
153 for ( MojoExecution mojoExecution : mojoExecutions )
154 {
155 setupMojoExecution( session, project, mojoExecution );
156 }
157 }
158
159 @Override
160 public void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution )
161 throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
162 MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
163 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
164 {
165 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
166
167 if ( mojoDescriptor == null )
168 {
169 mojoDescriptor =
170 pluginManager.getMojoDescriptor( mojoExecution.getPlugin(), mojoExecution.getGoal(),
171 project.getRemotePluginRepositories(),
172 session.getRepositorySession() );
173
174 mojoExecution.setMojoDescriptor( mojoDescriptor );
175 }
176
177 mojoExecutionConfigurator( mojoExecution ).configure( project,
178 mojoExecution,
179 MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) );
180
181 finalizeMojoConfiguration( mojoExecution );
182
183 calculateForkedExecutions( mojoExecution, session, project, new HashSet<MojoDescriptor>() );
184 }
185
186 public List<MojoExecution> calculateMojoExecutions( MavenSession session, MavenProject project, List<Object> tasks )
187 throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
188 MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
189 PluginVersionResolutionException, LifecyclePhaseNotFoundException
190 {
191 final List<MojoExecution> mojoExecutions = new ArrayList<>();
192
193 for ( Object task : tasks )
194 {
195 if ( task instanceof GoalTask )
196 {
197 String pluginGoal = ( (GoalTask) task ).pluginGoal;
198
199 String executionId = "default-cli";
200 int executionIdx = pluginGoal.indexOf( '@' );
201 if ( executionIdx > 0 )
202 {
203 executionId = pluginGoal.substring( executionIdx + 1 );
204 }
205
206 MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( pluginGoal, session, project );
207
208 MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, executionId,
209 MojoExecution.Source.CLI );
210
211 mojoExecutions.add( mojoExecution );
212 }
213 else if ( task instanceof LifecycleTask )
214 {
215 String lifecyclePhase = ( (LifecycleTask) task ).getLifecyclePhase();
216
217 Map<String, List<MojoExecution>> phaseToMojoMapping =
218 calculateLifecycleMappings( session, project, lifecyclePhase );
219
220 for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
221 {
222 mojoExecutions.addAll( mojoExecutionsFromLifecycle );
223 }
224 }
225 else
226 {
227 throw new IllegalStateException( "unexpected task " + task );
228 }
229 }
230 return mojoExecutions;
231 }
232
233 private Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
234 String lifecyclePhase )
235 throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
236 PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException
237 {
238
239
240
241
242 Lifecycle lifecycle = defaultLifeCycles.get( lifecyclePhase );
243
244 if ( lifecycle == null )
245 {
246 throw new LifecyclePhaseNotFoundException( "Unknown lifecycle phase \"" + lifecyclePhase
247 + "\". You must specify a valid lifecycle phase" + " or a goal in the format <plugin-prefix>:<goal> or"
248 + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
249 + defaultLifeCycles.getLifecyclePhaseList() + ".", lifecyclePhase );
250 }
251
252 LifecycleMappingDelegate delegate;
253 if ( Arrays.binarySearch( DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId() ) >= 0 )
254 {
255 delegate = standardDelegate;
256 }
257 else
258 {
259 delegate = delegates.get( lifecycle.getId() );
260 if ( delegate == null )
261 {
262 delegate = standardDelegate;
263 }
264 }
265
266 return delegate.calculateLifecycleMappings( session, project, lifecycle, lifecyclePhase );
267 }
268
269
270
271
272
273
274
275
276 private void finalizeMojoConfiguration( MojoExecution mojoExecution )
277 {
278 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
279
280 Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
281 if ( executionConfiguration == null )
282 {
283 executionConfiguration = new Xpp3Dom( "configuration" );
284 }
285
286 Xpp3Dom defaultConfiguration = getMojoConfiguration( mojoDescriptor );
287
288 Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
289
290 if ( mojoDescriptor.getParameters() != null )
291 {
292 for ( Parameter parameter : mojoDescriptor.getParameters() )
293 {
294 Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
295
296 if ( parameterConfiguration == null )
297 {
298 parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
299 }
300
301 Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
302
303 parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults,
304 Boolean.TRUE );
305
306 if ( parameterConfiguration != null )
307 {
308 parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
309
310 if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
311 && StringUtils.isNotEmpty( parameter.getImplementation() ) )
312 {
313 parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
314 }
315
316 finalConfiguration.addChild( parameterConfiguration );
317 }
318 }
319 }
320
321 mojoExecution.setConfiguration( finalConfiguration );
322 }
323
324 private Xpp3Dom getMojoConfiguration( MojoDescriptor mojoDescriptor )
325 {
326 return MojoDescriptorCreator.convert( mojoDescriptor );
327 }
328
329 @Override
330 public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
331 throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
332 PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
333 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
334 {
335 calculateForkedExecutions( mojoExecution, session, session.getCurrentProject(), new HashSet<MojoDescriptor>() );
336 }
337
338 private void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session, MavenProject project,
339 Collection<MojoDescriptor> alreadyForkedExecutions )
340 throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
341 PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
342 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
343 {
344 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
345
346 if ( !mojoDescriptor.isForking() )
347 {
348 return;
349 }
350
351 if ( !alreadyForkedExecutions.add( mojoDescriptor ) )
352 {
353 return;
354 }
355
356 List<MavenProject> forkedProjects =
357 LifecycleDependencyResolver.getProjects( project, session, mojoDescriptor.isAggregator() );
358
359 for ( MavenProject forkedProject : forkedProjects )
360 {
361 if ( forkedProject != project )
362 {
363 lifecyclePluginResolver.resolveMissingPluginVersions( forkedProject, session );
364 }
365
366 List<MojoExecution> forkedExecutions;
367
368 if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) )
369 {
370 forkedExecutions =
371 calculateForkedLifecycle( mojoExecution, session, forkedProject, alreadyForkedExecutions );
372 }
373 else
374 {
375 forkedExecutions = calculateForkedGoal( mojoExecution, session, forkedProject,
376 alreadyForkedExecutions );
377 }
378
379 mojoExecution.setForkedExecutions( BuilderCommon.getKey( forkedProject ), forkedExecutions );
380 }
381
382 alreadyForkedExecutions.remove( mojoDescriptor );
383 }
384
385 private List<MojoExecution> calculateForkedLifecycle( MojoExecution mojoExecution, MavenSession session,
386 MavenProject project,
387 Collection<MojoDescriptor> alreadyForkedExecutions )
388 throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
389 PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
390 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
391 {
392 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
393
394 String forkedPhase = mojoDescriptor.getExecutePhase();
395
396 Map<String, List<MojoExecution>> lifecycleMappings = calculateLifecycleMappings( session, project,
397 forkedPhase );
398
399 for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
400 {
401 for ( MojoExecution forkedExecution : forkedExecutions )
402 {
403 if ( forkedExecution.getMojoDescriptor() == null )
404 {
405 MojoDescriptor forkedMojoDescriptor =
406 pluginManager.getMojoDescriptor( forkedExecution.getPlugin(), forkedExecution.getGoal(),
407 project.getRemotePluginRepositories(),
408 session.getRepositorySession() );
409
410 forkedExecution.setMojoDescriptor( forkedMojoDescriptor );
411 }
412
413 mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, false );
414 }
415 }
416
417 injectLifecycleOverlay( lifecycleMappings, mojoExecution, session, project );
418
419 List<MojoExecution> mojoExecutions = new ArrayList<>();
420
421 for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
422 {
423 for ( MojoExecution forkedExecution : forkedExecutions )
424 {
425 if ( !alreadyForkedExecutions.contains( forkedExecution.getMojoDescriptor() ) )
426 {
427 finalizeMojoConfiguration( forkedExecution );
428
429 calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
430
431 mojoExecutions.add( forkedExecution );
432 }
433 }
434 }
435
436 return mojoExecutions;
437 }
438
439 private void injectLifecycleOverlay( Map<String, List<MojoExecution>> lifecycleMappings,
440 MojoExecution mojoExecution, MavenSession session, MavenProject project )
441 throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
442 PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
443 InvalidPluginDescriptorException, PluginVersionResolutionException
444 {
445 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
446
447 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
448
449 String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
450
451 if ( StringUtils.isEmpty( forkedLifecycle ) )
452 {
453 return;
454 }
455
456 org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
457
458 try
459 {
460 lifecycleOverlay = pluginDescriptor.getLifecycleMapping( forkedLifecycle );
461 }
462 catch ( IOException | XmlPullParserException e )
463 {
464 throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
465 }
466
467 if ( lifecycleOverlay == null )
468 {
469 throw new LifecycleNotFoundException( forkedLifecycle );
470 }
471
472 for ( Phase phase : lifecycleOverlay.getPhases() )
473 {
474 List<MojoExecution> forkedExecutions = lifecycleMappings.get( phase.getId() );
475
476 if ( forkedExecutions != null )
477 {
478 for ( Execution execution : phase.getExecutions() )
479 {
480 for ( String goal : execution.getGoals() )
481 {
482 MojoDescriptor forkedMojoDescriptor;
483
484 if ( goal.indexOf( ':' ) < 0 )
485 {
486 forkedMojoDescriptor = pluginDescriptor.getMojo( goal );
487 if ( forkedMojoDescriptor == null )
488 {
489 throw new MojoNotFoundException( goal, pluginDescriptor );
490 }
491 }
492 else
493 {
494 forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( goal, session, project );
495 }
496
497 MojoExecution forkedExecution =
498 new MojoExecution( forkedMojoDescriptor, mojoExecution.getExecutionId() );
499
500 Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
501
502 forkedExecution.setConfiguration( forkedConfiguration );
503
504 mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, true );
505
506 forkedExecutions.add( forkedExecution );
507 }
508 }
509
510 Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
511
512 if ( phaseConfiguration != null )
513 {
514 for ( MojoExecution forkedExecution : forkedExecutions )
515 {
516 Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
517
518 forkedConfiguration = Xpp3Dom.mergeXpp3Dom( phaseConfiguration, forkedConfiguration );
519
520 forkedExecution.setConfiguration( forkedConfiguration );
521 }
522 }
523 }
524 }
525 }
526
527
528
529
530
531
532 private List<MojoExecution> calculateForkedGoal( MojoExecution mojoExecution, MavenSession session,
533 MavenProject project,
534 Collection<MojoDescriptor> alreadyForkedExecutions )
535 throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
536 PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
537 LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
538 {
539 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
540
541 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
542
543 String forkedGoal = mojoDescriptor.getExecuteGoal();
544
545 MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo( forkedGoal );
546 if ( forkedMojoDescriptor == null )
547 {
548 throw new MojoNotFoundException( forkedGoal, pluginDescriptor );
549 }
550
551 if ( alreadyForkedExecutions.contains( forkedMojoDescriptor ) )
552 {
553 return Collections.emptyList();
554 }
555
556 MojoExecution forkedExecution = new MojoExecution( forkedMojoDescriptor, forkedGoal );
557
558 mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, true );
559
560 finalizeMojoConfiguration( forkedExecution );
561
562 calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
563
564 return Collections.singletonList( forkedExecution );
565 }
566
567 private MojoExecutionConfigurator mojoExecutionConfigurator( MojoExecution mojoExecution )
568 {
569 String configuratorId = mojoExecution.getMojoDescriptor().getComponentConfigurator();
570 if ( configuratorId == null )
571 {
572 configuratorId = "default";
573 }
574
575 MojoExecutionConfigurator mojoExecutionConfigurator = mojoExecutionConfigurators.get( configuratorId );
576
577 if ( mojoExecutionConfigurator == null )
578 {
579
580
581
582
583 mojoExecutionConfigurator = mojoExecutionConfigurators.get( "default" );
584 }
585 return mojoExecutionConfigurator;
586 }
587 }