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