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