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