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