1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Provider;
24 import javax.inject.Singleton;
25
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedHashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Objects;
35 import java.util.Optional;
36 import java.util.Set;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39
40 import org.apache.maven.api.DependencyScope;
41 import org.apache.maven.api.Lifecycle;
42 import org.apache.maven.api.model.InputLocation;
43 import org.apache.maven.api.model.InputSource;
44 import org.apache.maven.api.model.Plugin;
45 import org.apache.maven.api.services.LifecycleRegistry;
46 import org.apache.maven.api.services.LookupException;
47 import org.apache.maven.api.spi.ExtensibleEnumProvider;
48 import org.apache.maven.api.spi.LifecycleProvider;
49 import org.apache.maven.lifecycle.mapping.LifecyclePhase;
50 import org.codehaus.plexus.PlexusContainer;
51 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
52
53 import static org.apache.maven.api.Lifecycle.AFTER;
54 import static org.apache.maven.api.Lifecycle.BEFORE;
55 import static org.apache.maven.api.Lifecycle.Phase.ALL;
56 import static org.apache.maven.api.Lifecycle.Phase.BUILD;
57 import static org.apache.maven.api.Lifecycle.Phase.COMPILE;
58 import static org.apache.maven.api.Lifecycle.Phase.DEPLOY;
59 import static org.apache.maven.api.Lifecycle.Phase.EACH;
60 import static org.apache.maven.api.Lifecycle.Phase.INITIALIZE;
61 import static org.apache.maven.api.Lifecycle.Phase.INSTALL;
62 import static org.apache.maven.api.Lifecycle.Phase.INTEGRATION_TEST;
63 import static org.apache.maven.api.Lifecycle.Phase.PACKAGE;
64 import static org.apache.maven.api.Lifecycle.Phase.READY;
65 import static org.apache.maven.api.Lifecycle.Phase.RESOURCES;
66 import static org.apache.maven.api.Lifecycle.Phase.SOURCES;
67 import static org.apache.maven.api.Lifecycle.Phase.TEST;
68 import static org.apache.maven.api.Lifecycle.Phase.TEST_COMPILE;
69 import static org.apache.maven.api.Lifecycle.Phase.TEST_RESOURCES;
70 import static org.apache.maven.api.Lifecycle.Phase.TEST_SOURCES;
71 import static org.apache.maven.api.Lifecycle.Phase.UNIT_TEST;
72 import static org.apache.maven.api.Lifecycle.Phase.VALIDATE;
73 import static org.apache.maven.api.Lifecycle.Phase.VERIFY;
74 import static org.apache.maven.internal.impl.Lifecycles.after;
75 import static org.apache.maven.internal.impl.Lifecycles.alias;
76 import static org.apache.maven.internal.impl.Lifecycles.children;
77 import static org.apache.maven.internal.impl.Lifecycles.dependencies;
78 import static org.apache.maven.internal.impl.Lifecycles.phase;
79 import static org.apache.maven.internal.impl.Lifecycles.plugin;
80
81
82
83
84 @Named
85 @Singleton
86 public class DefaultLifecycleRegistry implements LifecycleRegistry {
87
88 private static final String MAVEN_PLUGINS = "org.apache.maven.plugins:";
89
90 public static final String DEFAULT_LIFECYCLE_MODELID = "org.apache.maven:maven-core:"
91 + DefaultLifecycleRegistry.class.getPackage().getImplementationVersion()
92 + ":default-lifecycle-bindings";
93
94 public static final InputLocation DEFAULT_LIFECYCLE_INPUT_LOCATION =
95 new InputLocation(new InputSource(DEFAULT_LIFECYCLE_MODELID, null));
96
97 public static final String SCOPE_COMPILE = DependencyScope.COMPILE.id();
98 public static final String SCOPE_RUNTIME = DependencyScope.RUNTIME.id();
99 public static final String SCOPE_TEST_ONLY = DependencyScope.TEST_ONLY.id();
100 public static final String SCOPE_TEST = DependencyScope.TEST.id();
101
102 private final List<LifecycleProvider> providers;
103
104 public DefaultLifecycleRegistry() {
105 this(Collections.emptyList());
106 }
107
108 @Inject
109 public DefaultLifecycleRegistry(List<LifecycleProvider> providers) {
110 List<LifecycleProvider> p = new ArrayList<>(providers);
111 p.add(() -> List.of(new CleanLifecycle(), new DefaultLifecycle(), new SiteLifecycle()));
112 this.providers = p;
113
114 for (Lifecycle lifecycle : this) {
115 Set<String> set = new HashSet<>();
116 lifecycle.allPhases().forEach(phase -> {
117 if (!set.add(phase.name())) {
118 throw new IllegalArgumentException(
119 "Found duplicated phase '" + phase.name() + "' in '" + lifecycle.id() + "' lifecycle");
120 }
121 });
122 }
123 }
124
125 @Override
126 public Iterator<Lifecycle> iterator() {
127 return stream().toList().iterator();
128 }
129
130 @Override
131 public Stream<Lifecycle> stream() {
132 return providers.stream().map(ExtensibleEnumProvider::provides).flatMap(Collection::stream);
133 }
134
135 @Override
136 public Optional<Lifecycle> lookup(String id) {
137 return stream().filter(lf -> Objects.equals(id, lf.id())).findAny();
138 }
139
140 @Override
141 public List<String> computePhases(Lifecycle lifecycle) {
142 Graph graph = new Graph();
143 addPhases(graph, null, null, lifecycle.v3phases());
144 List<String> allPhases = graph.visitAll();
145 Collections.reverse(allPhases);
146 List<String> computed =
147 allPhases.stream().filter(s -> !s.startsWith("$")).collect(Collectors.toList());
148 return computed;
149 }
150
151 private static void addPhase(
152 Graph graph, Graph.Vertex before, Graph.Vertex after, org.apache.maven.api.Lifecycle.Phase phase) {
153 Graph.Vertex ep0 = graph.addVertex(BEFORE + phase.name());
154 Graph.Vertex ep1 = graph.addVertex("$$" + phase.name());
155 Graph.Vertex ep2 = graph.addVertex(phase.name());
156 Graph.Vertex ep3 = graph.addVertex(AFTER + phase.name());
157 graph.addEdge(ep0, ep1);
158 graph.addEdge(ep1, ep2);
159 graph.addEdge(ep2, ep3);
160 if (before != null) {
161 graph.addEdge(before, ep0);
162 }
163 if (after != null) {
164 graph.addEdge(ep3, after);
165 }
166 phase.links().forEach(link -> {
167 if (link.pointer().type() == Lifecycle.Pointer.Type.PROJECT) {
168 if (link.kind() == Lifecycle.Link.Kind.AFTER) {
169 graph.addEdge(graph.addVertex(link.pointer().phase()), ep0);
170 } else {
171 graph.addEdge(ep3, graph.addVertex(BEFORE + link.pointer().phase()));
172 }
173 }
174 });
175 addPhases(graph, ep1, ep2, phase.phases());
176 }
177
178 private static void addPhases(
179 Graph graph, Graph.Vertex before, Graph.Vertex after, Collection<Lifecycle.Phase> phases) {
180
181
182
183 Lifecycle.Phase prev = null;
184 for (Lifecycle.Phase child : phases) {
185
186 addPhase(graph, before, after, child);
187 if (prev != null) {
188
189 graph.addEdge(graph.addVertex(AFTER + prev.name()), graph.addVertex(BEFORE + child.name()));
190 }
191 prev = child;
192 }
193 }
194
195 @Named
196 @Singleton
197 public static class LifecycleWrapperProvider implements LifecycleProvider {
198 private final PlexusContainer container;
199
200 @Inject
201 public LifecycleWrapperProvider(PlexusContainer container) {
202 this.container = container;
203 }
204
205 @Override
206 public Collection<Lifecycle> provides() {
207 try {
208 Map<String, org.apache.maven.lifecycle.Lifecycle> all =
209 container.lookupMap(org.apache.maven.lifecycle.Lifecycle.class);
210 return all.keySet().stream()
211 .filter(id -> !Lifecycle.CLEAN.equals(id)
212 && !Lifecycle.DEFAULT.equals(id)
213 && !Lifecycle.SITE.equals(id))
214 .map(id -> wrap(all.get(id)))
215 .collect(Collectors.toList());
216 } catch (ComponentLookupException e) {
217 throw new LookupException(e);
218 }
219 }
220
221 private Lifecycle wrap(org.apache.maven.lifecycle.Lifecycle lifecycle) {
222 return new Lifecycle() {
223 @Override
224 public String id() {
225 return lifecycle.getId();
226 }
227
228 @Override
229 public Collection<Phase> phases() {
230 List<String> names = lifecycle.getPhases();
231 List<Phase> phases = new ArrayList<>();
232 for (int i = 0; i < names.size(); i++) {
233 String name = names.get(i);
234 String prev = i > 0 ? names.get(i - 1) : null;
235 phases.add(new Phase() {
236 @Override
237 public String name() {
238 return name;
239 }
240
241 @Override
242 public List<Phase> phases() {
243 return List.of();
244 }
245
246 @Override
247 public Stream<Phase> allPhases() {
248 return Stream.concat(
249 Stream.of(this), phases().stream().flatMap(Lifecycle.Phase::allPhases));
250 }
251
252 @Override
253 public List<Plugin> plugins() {
254 Map<String, LifecyclePhase> lfPhases = lifecycle.getDefaultLifecyclePhases();
255 LifecyclePhase phase = lfPhases != null ? lfPhases.get(name) : null;
256 if (phase != null) {
257 Map<String, Plugin> plugins = new LinkedHashMap<>();
258 DefaultPackagingRegistry.parseLifecyclePhaseDefinitions(plugins, name, phase);
259 return plugins.values().stream().toList();
260 }
261 return List.of();
262 }
263
264 @Override
265 public Collection<Link> links() {
266 if (prev == null) {
267 return List.of();
268 } else {
269 return List.of(new Link() {
270 @Override
271 public Kind kind() {
272 return Kind.AFTER;
273 }
274
275 @Override
276 public Pointer pointer() {
277 return new Pointer() {
278 @Override
279 public String phase() {
280 return prev;
281 }
282
283 @Override
284 public Type type() {
285 return Type.PROJECT;
286 }
287 };
288 }
289 });
290 }
291 }
292 });
293 }
294 return phases;
295 }
296
297 @Override
298 public Collection<Alias> aliases() {
299 return Collections.emptyList();
300 }
301 };
302 }
303 }
304
305 static class WrappedLifecycle extends org.apache.maven.lifecycle.Lifecycle {
306 WrappedLifecycle(LifecycleRegistry registry, Lifecycle lifecycle) {
307 super(registry, lifecycle);
308 }
309 }
310
311 abstract static class BaseLifecycleProvider implements Provider<org.apache.maven.lifecycle.Lifecycle> {
312 @Inject
313 private PlexusContainer lookup;
314
315 private final String name;
316
317 BaseLifecycleProvider(String name) {
318 this.name = name;
319 }
320
321 @Override
322 public org.apache.maven.lifecycle.Lifecycle get() {
323 try {
324 LifecycleRegistry registry = lookup.lookup(LifecycleRegistry.class);
325 return new WrappedLifecycle(registry, registry.require(name));
326 } catch (ComponentLookupException e) {
327 throw new LookupException(e);
328 }
329 }
330 }
331
332 @Singleton
333 @Named(Lifecycle.CLEAN)
334 @SuppressWarnings("unused")
335 static class CleanLifecycleProvider extends BaseLifecycleProvider {
336 CleanLifecycleProvider() {
337 super(Lifecycle.CLEAN);
338 }
339 }
340
341 @Singleton
342 @Named(Lifecycle.DEFAULT)
343 @SuppressWarnings("unused")
344 static class DefaultLifecycleProvider extends BaseLifecycleProvider {
345 DefaultLifecycleProvider() {
346 super(Lifecycle.DEFAULT);
347 }
348 }
349
350 @Singleton
351 @Named(Lifecycle.SITE)
352 @SuppressWarnings("unused")
353 static class SiteLifecycleProvider extends BaseLifecycleProvider {
354 SiteLifecycleProvider() {
355 super(Lifecycle.SITE);
356 }
357 }
358
359 static class CleanLifecycle implements Lifecycle {
360
361 private static final String MAVEN_CLEAN_PLUGIN_VERSION = "3.4.0";
362
363 @Override
364 public String id() {
365 return Lifecycle.CLEAN;
366 }
367
368 @Override
369 public Collection<Phase> phases() {
370
371 return List.of(phase(
372 Phase.CLEAN,
373 plugin(
374 MAVEN_PLUGINS + "maven-clean-plugin:" + MAVEN_CLEAN_PLUGIN_VERSION + ":clean",
375 Phase.CLEAN)));
376
377 }
378
379 @Override
380 public Collection<Alias> aliases() {
381 return List.of(alias("pre-clean", BEFORE + Phase.CLEAN), alias("post-clean", AFTER + Phase.CLEAN));
382 }
383 }
384
385 static class DefaultLifecycle implements Lifecycle {
386 @Override
387 public String id() {
388 return Lifecycle.DEFAULT;
389 }
390
391 @Override
392 public Collection<Phase> phases() {
393
394 return List.of(phase(
395 ALL,
396 children(ALL),
397 phase(
398 EACH,
399 phase(VALIDATE, phase(INITIALIZE)),
400 phase(
401 BUILD,
402 after(VALIDATE),
403 phase(SOURCES),
404 phase(RESOURCES),
405 phase(COMPILE, after(SOURCES), dependencies(SCOPE_COMPILE, READY)),
406 phase(READY, after(COMPILE), after(RESOURCES)),
407 phase(PACKAGE, after(READY), dependencies(SCOPE_RUNTIME, PACKAGE))),
408 phase(
409 VERIFY,
410 after(VALIDATE),
411 phase(
412 UNIT_TEST,
413 phase(TEST_SOURCES),
414 phase(TEST_RESOURCES),
415 phase(
416 TEST_COMPILE,
417 after(TEST_SOURCES),
418 after(READY),
419 dependencies(SCOPE_TEST_ONLY, READY)),
420 phase(
421 TEST,
422 after(TEST_COMPILE),
423 after(TEST_RESOURCES),
424 dependencies(SCOPE_TEST, READY))),
425 phase(INTEGRATION_TEST)),
426 phase(INSTALL, after(PACKAGE)),
427 phase(DEPLOY, after(PACKAGE)))));
428
429 }
430
431 @Override
432 public Collection<Phase> v3phases() {
433 return List.of(phase(
434 ALL,
435 phase(INITIALIZE, phase(VALIDATE)),
436 phase(
437 BUILD,
438 phase(SOURCES),
439 phase(RESOURCES),
440 phase(COMPILE),
441 phase(READY),
442 phase(TEST_SOURCES),
443 phase(TEST_RESOURCES),
444 phase(TEST_COMPILE),
445 phase(TEST),
446 phase(UNIT_TEST),
447 phase(PACKAGE)),
448 phase(VERIFY, phase(INTEGRATION_TEST)),
449 phase(INSTALL),
450 phase(DEPLOY)));
451 }
452
453 @Override
454 public Collection<Alias> aliases() {
455 return List.of(
456 alias("generate-sources", SOURCES),
457 alias("process-sources", AFTER + SOURCES),
458 alias("generate-resources", RESOURCES),
459 alias("process-resources", AFTER + RESOURCES),
460 alias("process-classes", AFTER + COMPILE),
461 alias("generate-test-sources", TEST_SOURCES),
462 alias("process-test-sources", AFTER + TEST_SOURCES),
463 alias("generate-test-resources", TEST_RESOURCES),
464 alias("process-test-resources", AFTER + TEST_RESOURCES),
465 alias("process-test-classes", AFTER + TEST_COMPILE),
466 alias("prepare-package", BEFORE + PACKAGE),
467 alias("pre-integration-test", BEFORE + INTEGRATION_TEST),
468 alias("post-integration-test", AFTER + INTEGRATION_TEST));
469 }
470 }
471
472 static class SiteLifecycle implements Lifecycle {
473
474 private static final String MAVEN_SITE_PLUGIN_VERSION = "3.21.0";
475 private static final String MAVEN_SITE_PLUGIN =
476 MAVEN_PLUGINS + "maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":";
477 private static final String PHASE_SITE = "site";
478 private static final String PHASE_SITE_DEPLOY = "site-deploy";
479
480 @Override
481 public String id() {
482 return Lifecycle.SITE;
483 }
484
485 @Override
486 public Collection<Phase> phases() {
487
488 return List.of(
489 phase(PHASE_SITE, plugin(MAVEN_SITE_PLUGIN + "site", PHASE_SITE)),
490 phase(
491 PHASE_SITE_DEPLOY,
492 after(PHASE_SITE),
493 plugin(MAVEN_SITE_PLUGIN + "deploy", PHASE_SITE_DEPLOY)));
494
495 }
496
497 @Override
498 public Collection<Alias> aliases() {
499 return List.of(alias("pre-site", BEFORE + PHASE_SITE), alias("post-site", AFTER + PHASE_SITE));
500 }
501 }
502 }