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