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