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