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