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