[MNG-8084] Include lifecycle in the API

This commit is contained in:
Guillaume Nodet 2024-04-11 08:17:32 +02:00
parent 84e2d8ad3f
commit 9be08ccef8
18 changed files with 587 additions and 299 deletions

View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api;
import java.util.*;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Immutable;
import org.apache.maven.api.model.Plugin;
/**
* Lifecycle definition
*
* @since 4.0.0
*/
@Experimental
@Immutable
public interface Lifecycle extends ExtensibleEnum {
String CLEAN = "clean";
String DEFAULT = "default";
String SITE = "site";
String WRAPPER = "wrapper";
/**
* Name or identifier of this lifecycle.
*
* @return the unique identifier for this lifecycle
*/
@Override
String id();
/**
* Collection of phases for this lifecycle
*/
Collection<Phase> phases();
/**
* Pre-ordered list of phases.
* If not provided, a default order will be computed.
*/
default Optional<List<String>> orderedPhases() {
return Optional.empty();
}
/**
* A phase in the lifecycle.
*/
interface Phase {
String name();
List<Plugin> plugins();
}
}

View File

@ -46,6 +46,7 @@ import static org.apache.maven.api.ExtensibleEnums.pathScope;
@Immutable @Immutable
public interface PathScope extends ExtensibleEnum { public interface PathScope extends ExtensibleEnum {
// TODO: what if I simply want all dependencies ?
@Nonnull @Nonnull
ProjectScope projectScope(); ProjectScope projectScope();

View File

@ -41,21 +41,10 @@ import org.apache.maven.api.annotations.Nonnull;
public @interface Execute { public @interface Execute {
/** /**
* Lifecycle phase to fork. Note that specifying a phase overrides specifying a goal. * Lifecycle phase to fork. Note that specifying a phase overrides specifying a goal.
* For custom lifecycle phase ids use {@link #customPhase()} instead.
* Only one of {@link #customPhase()} and {@link #phase()} must be set.
* @return the phase * @return the phase
*/ */
@Nonnull @Nonnull
LifecyclePhase phase() default LifecyclePhase.NONE; String phase() default "";
/**
* Custom lifecycle phase to fork. Note that specifying a phase overrides specifying a goal.
* This element should only be used for non-standard phases. For standard phases rather use {@link #phase()}.
* Only one of {@link #customPhase()} and {@link #phase()} must be set.
* @return the custom phase id
*/
@Nonnull
String customPhase() default "";
/** /**
* Goal to fork. Note that specifying a phase overrides specifying a goal. The specified <code>goal</code> must be * Goal to fork. Note that specifying a phase overrides specifying a goal. The specified <code>goal</code> must be

View File

@ -1,74 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.plugin.annotations;
import org.apache.maven.api.annotations.Experimental;
/**
* <a href="/ref/3.0.4/maven-core/lifecycles.html">Lifecycle phases</a>.
*
* @since 4.0.0
*/
@Experimental
public enum LifecyclePhase {
VALIDATE("validate"),
INITIALIZE("initialize"),
GENERATE_SOURCES("generate-sources"),
PROCESS_SOURCES("process-sources"),
GENERATE_RESOURCES("generate-resources"),
PROCESS_RESOURCES("process-resources"),
COMPILE("compile"),
PROCESS_CLASSES("process-classes"),
GENERATE_TEST_SOURCES("generate-test-sources"),
PROCESS_TEST_SOURCES("process-test-sources"),
GENERATE_TEST_RESOURCES("generate-test-resources"),
PROCESS_TEST_RESOURCES("process-test-resources"),
TEST_COMPILE("test-compile"),
PROCESS_TEST_CLASSES("process-test-classes"),
TEST("test"),
PREPARE_PACKAGE("prepare-package"),
PACKAGE("package"),
PRE_INTEGRATION_TEST("pre-integration-test"),
INTEGRATION_TEST("integration-test"),
POST_INTEGRATION_TEST("post-integration-test"),
VERIFY("verify"),
INSTALL("install"),
DEPLOY("deploy"),
PRE_CLEAN("pre-clean"),
CLEAN("clean"),
POST_CLEAN("post-clean"),
PRE_SITE("pre-site"),
SITE("site"),
POST_SITE("post-site"),
SITE_DEPLOY("site-deploy"),
NONE("");
private final String id;
LifecyclePhase(String id) {
this.id = id;
}
public String id() {
return this.id;
}
}

View File

@ -54,7 +54,7 @@ public @interface Mojo {
* @return the default phase * @return the default phase
*/ */
@Nonnull @Nonnull
LifecyclePhase defaultPhase() default LifecyclePhase.NONE; String defaultPhase() default "";
/** /**
* does your mojo requires a project to be executed? * does your mojo requires a project to be executed?

View File

@ -16,32 +16,18 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.maven.lifecycle.providers; package org.apache.maven.api.services;
import javax.inject.Inject; import java.util.List;
import javax.inject.Named; import java.util.stream.Stream;
import javax.inject.Singleton; import java.util.stream.StreamSupport;
/** import org.apache.maven.api.Lifecycle;
* {@code wrapper} lifecycle provider.
*/
@Named(WrapperLifecycleProvider.LIFECYCLE_ID)
@Singleton
public final class WrapperLifecycleProvider extends AbstractLifecycleProvider {
static final String LIFECYCLE_ID = "wrapper";
// START SNIPPET: wrapper public interface LifecycleRegistry extends ExtensibleEnumRegistry<Lifecycle>, Iterable<Lifecycle> {
private static final String[] PHASES = {"wrapper"}; default Stream<Lifecycle> stream() {
return StreamSupport.stream(spliterator(), false);
private static final String MAVEN_WRAPPER_PLUGIN_VERSION = "3.2.0";
private static final String[] BINDINGS = {
"wrapper", "org.apache.maven.plugins:maven-wrapper-plugin:" + MAVEN_WRAPPER_PLUGIN_VERSION + ":wrapper"
};
// END SNIPPET: wrapper
@Inject
public WrapperLifecycleProvider() {
super(LIFECYCLE_ID, PHASES, BINDINGS);
} }
List<String> computePhases(Lifecycle lifecycle);
} }

View File

@ -16,18 +16,12 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.maven.api; package org.apache.maven.api.spi;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Experimental;
/**
* Storage location for metadata
*
* @since 4.0.0
*/
@Experimental @Experimental
public enum MetadataStorage { @Consumer
GROUP, public interface LifecycleProvider extends ExtensibleEnumProvider<Lifecycle> {}
ARTIFACT,
VERSION
}

View File

@ -0,0 +1,227 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.services.LifecycleRegistry;
import org.apache.maven.api.spi.LifecycleProvider;
import static java.util.Arrays.asList;
import static java.util.Collections.*;
import static org.apache.maven.internal.impl.Lifecycles.*;
/**
* TODO: this is session scoped as SPI can contribute.
*/
@Named
@Singleton
public class DefaultLifecycleRegistry
extends ExtensibleEnumRegistries.DefaultExtensibleEnumRegistry<Lifecycle, LifecycleProvider>
implements LifecycleRegistry {
public DefaultLifecycleRegistry() {
super(Collections.emptyList());
}
@Inject
public DefaultLifecycleRegistry(
List<LifecycleProvider> providers, Map<String, org.apache.maven.lifecycle.Lifecycle> lifecycles) {
super(
concat(providers, new LifecycleWrapperProvider(lifecycles)),
new CleanLifecycle(),
new DefaultLifecycle(),
new SiteLifecycle(),
new WrapperLifecycle());
// validate lifecycle
for (Lifecycle lifecycle : this) {
Set<String> set = new HashSet<>();
lifecycle.phases().forEach(phase -> {
if (!set.add(phase.name())) {
throw new IllegalArgumentException(
"Found duplicated phase '" + phase.name() + "' in '" + lifecycle.id() + "' lifecycle");
}
});
}
}
@Override
public Iterator<Lifecycle> iterator() {
return values.values().iterator();
}
@Override
public Stream<Lifecycle> stream() {
return values.values().stream();
}
static <T> List<T> concat(List<T> l, T t) {
List<T> nl = new ArrayList<>(l.size() + 1);
nl.addAll(l);
nl.add(t);
return nl;
}
@Override
public List<String> computePhases(Lifecycle lifecycle) {
return lifecycle.phases().stream().map(Lifecycle.Phase::name).toList();
}
static class LifecycleWrapperProvider implements LifecycleProvider {
private final Map<String, org.apache.maven.lifecycle.Lifecycle> lifecycles;
@Inject
LifecycleWrapperProvider(Map<String, org.apache.maven.lifecycle.Lifecycle> lifecycles) {
this.lifecycles = lifecycles;
}
@Override
public Collection<Lifecycle> provides() {
return lifecycles.values().stream().map(this::wrap).collect(Collectors.toList());
}
private Lifecycle wrap(org.apache.maven.lifecycle.Lifecycle lifecycle) {
return new Lifecycle() {
@Override
public String id() {
return lifecycle.getId();
}
@Override
public Collection<Phase> phases() {
// TODO: implement
throw new UnsupportedOperationException();
}
};
}
}
static class CleanLifecycle implements Lifecycle {
private static final String MAVEN_CLEAN_PLUGIN_VERSION = "3.2.0";
@Override
public String id() {
return Lifecycle.CLEAN;
}
@Override
public Collection<Phase> phases() {
return asList(
phase("pre-clean"),
phase(
"clean",
plugin(
"org.apache.maven.plugins:maven-clean-plugin:" + MAVEN_CLEAN_PLUGIN_VERSION
+ ":clean",
"clean")),
phase("post-clean"));
}
}
static class DefaultLifecycle implements Lifecycle {
@Override
public String id() {
return Lifecycle.DEFAULT;
}
@Override
public Collection<Phase> phases() {
return asList(
phase("validate"),
phase("initialize"),
phase("generate-sources"),
phase("process-sources"),
phase("generate-resources"),
phase("process-resources"),
phase("compile"),
phase("process-classes"),
phase("generate-test-sources"),
phase("process-test-sources"),
phase("generate-test-resources"),
phase("process-test-resources"),
phase("test-compile"),
phase("process-test-classes"),
phase("test"),
phase("prepare-package"),
phase("package"),
phase("pre-integration-test"),
phase("integration-test"),
phase("post-integration-test"),
phase("verify"),
phase("install"),
phase("deploy"));
}
}
static class SiteLifecycle implements Lifecycle {
private static final String MAVEN_SITE_PLUGIN_VERSION = "3.12.1";
@Override
public String id() {
return Lifecycle.SITE;
}
@Override
public Collection<Phase> phases() {
return asList(
phase("pre-site"),
phase(
"site",
plugin(
"org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":site",
"site")),
phase("post-site"),
phase(
"site-deploy",
plugin(
"org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION
+ ":deploy",
"site-deploy")));
}
}
static class WrapperLifecycle implements Lifecycle {
private static final String MAVEN_WRAPPER_PLUGIN_VERSION = "3.2.0";
@Override
public String id() {
return WRAPPER;
}
@Override
public Collection<Phase> phases() {
return singleton(phase(
"wrapper",
plugin(
"org.apache.maven.plugins:maven-wrapper-plugin:" + MAVEN_WRAPPER_PLUGIN_VERSION
+ ":wrapper",
"wrapper")));
}
}
}

View File

@ -25,6 +25,7 @@ import javax.inject.Singleton;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -33,6 +34,8 @@ import org.apache.maven.api.*;
import org.apache.maven.api.services.*; import org.apache.maven.api.services.*;
import org.apache.maven.api.spi.*; import org.apache.maven.api.spi.*;
import static org.apache.maven.internal.impl.Utils.nonNull;
public class ExtensibleEnumRegistries { public class ExtensibleEnumRegistries {
@Named @Named
@ -76,17 +79,17 @@ public class ExtensibleEnumRegistries {
static class DefaultExtensibleEnumRegistry<T extends ExtensibleEnum, P extends ExtensibleEnumProvider<T>> static class DefaultExtensibleEnumRegistry<T extends ExtensibleEnum, P extends ExtensibleEnumProvider<T>>
implements ExtensibleEnumRegistry<T> { implements ExtensibleEnumRegistry<T> {
private final Map<String, T> values; protected final Map<String, T> values;
DefaultExtensibleEnumRegistry(List<P> providers, T... builtinValues) { DefaultExtensibleEnumRegistry(List<P> providers, T... builtinValues) {
values = Stream.<T>concat( values = Stream.<T>concat(
Stream.of(builtinValues), providers.stream().flatMap(p -> p.provides().stream())) Stream.of(builtinValues), providers.stream().flatMap(p -> p.provides().stream()))
.collect(Collectors.toMap(t -> t.id(), t -> t)); .collect(Collectors.toUnmodifiableMap(ExtensibleEnum::id, Function.identity()));
} }
@Override @Override
public Optional<T> lookup(String id) { public Optional<T> lookup(String id) {
return Optional.ofNullable(values.get(id)); return Optional.ofNullable(values.get(nonNull(id, "id")));
} }
} }
} }

View File

@ -0,0 +1,145 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.internal.impl;
import java.util.*;
import org.apache.maven.project.CycleDetectedException;
class Graph {
private enum DfsState {
VISITING,
VISITED
}
final Map<String, Vertex> vertices = new LinkedHashMap<>();
public Vertex getVertex(String id) {
return vertices.get(id);
}
public Collection<Vertex> getVertices() {
return vertices.values();
}
Vertex addVertex(String label) {
return vertices.computeIfAbsent(label, Vertex::new);
}
void addEdge(Vertex from, Vertex to) throws CycleDetectedException {
from.children.add(to);
to.parents.add(from);
List<String> cycle = findCycle(to);
if (cycle != null) {
// remove edge which introduced cycle
removeEdge(from, to);
throw new CycleDetectedException(
"Edge between '" + from.label + "' and '" + to.label + "' introduces to cycle in the graph", cycle);
}
}
void removeEdge(Vertex from, Vertex to) {
from.children.remove(to);
to.parents.remove(from);
}
List<String> visitAll() {
return visitAll(vertices.values(), new HashMap<>(), new ArrayList<>());
}
List<String> findCycle(Vertex vertex) {
return visitCycle(Collections.singleton(vertex), new HashMap<>(), new LinkedList<>());
}
private static List<String> visitAll(
Collection<Vertex> children, Map<Vertex, DfsState> stateMap, List<String> list) {
for (Vertex v : children) {
DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
if (state == null) {
visitAll(v.children, stateMap, list);
stateMap.put(v, DfsState.VISITED);
list.add(v.label);
}
}
return list;
}
private static List<String> visitCycle(
Collection<Vertex> children, Map<Vertex, DfsState> stateMap, LinkedList<String> cycle) {
for (Vertex v : children) {
DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
if (state == null) {
cycle.addLast(v.label);
List<String> ret = visitCycle(v.children, stateMap, cycle);
if (ret != null) {
return ret;
}
cycle.removeLast();
stateMap.put(v, DfsState.VISITED);
} else if (state == DfsState.VISITING) {
// we are already visiting this vertex, this mean we have a cycle
int pos = cycle.lastIndexOf(v.label);
List<String> ret = cycle.subList(pos, cycle.size());
ret.add(v.label);
return ret;
}
}
return null;
}
static class Vertex {
final String label;
final List<Vertex> children = new ArrayList<>();
final List<Vertex> parents = new ArrayList<>();
Vertex(String label) {
this.label = label;
}
String getLabel() {
return label;
}
List<Vertex> getChildren() {
return children;
}
List<Vertex> getParents() {
return parents;
}
}
static class CycleDetectedException extends RuntimeException {
private final List<String> cycle;
CycleDetectedException(String message, List<String> cycle) {
super(message);
this.cycle = cycle;
}
public List<String> getCycle() {
return cycle;
}
@Override
public String getMessage() {
return super.getMessage() + " " + String.join(" --> ", cycle);
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.internal.impl;
import java.util.Collections;
import java.util.List;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.model.Plugin;
import org.apache.maven.api.model.PluginExecution;
public class Lifecycles {
static Lifecycle.Phase phase(String name) {
return new DefaultPhase(name, Collections.emptyList(), Collections.emptyList());
}
static Lifecycle.Phase phase(String name, Plugin plugin) {
return new DefaultPhase(name, Collections.singletonList(plugin), Collections.emptyList());
}
static Plugin plugin(String coord, String phase) {
String[] c = coord.split(":");
return Plugin.newBuilder()
.groupId(c[0])
.artifactId(c[1])
.version(c[2])
.executions(Collections.singletonList(PluginExecution.newBuilder()
.id("default-" + c[3])
.phase(phase)
.goals(Collections.singletonList(c[3]))
.build()))
.build();
}
static class DefaultPhase implements Lifecycle.Phase {
private final String name;
private final List<Plugin> plugins;
private final List<Lifecycle.Phase> phases;
DefaultPhase(String name, List<Plugin> plugins, List<Lifecycle.Phase> phases) {
this.name = name;
this.plugins = plugins;
this.phases = phases;
}
@Override
public String name() {
return name;
}
@Override
public List<Plugin> plugins() {
return plugins;
}
}
}

View File

@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.maven.api.services.LifecycleRegistry;
import org.apache.maven.api.services.Lookup; import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.LookupException; import org.apache.maven.api.services.LookupException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -51,24 +52,29 @@ public class DefaultLifecycles {
private final Lookup lookup; private final Lookup lookup;
private final LifecycleRegistry registry;
private Map<String, Lifecycle> customLifecycles; private Map<String, Lifecycle> customLifecycles;
public DefaultLifecycles() { public DefaultLifecycles() {
this.lookup = null; this.lookup = null;
this.registry = null;
} }
/** /**
* @deprecated Rely on {@link #DefaultLifecycles(Lookup)} instead * @deprecated Use {@link #DefaultLifecycles(LifecycleRegistry,Lookup)} instead
*/ */
@Deprecated @Deprecated
public DefaultLifecycles(Map<String, Lifecycle> lifecycles, org.codehaus.plexus.logging.Logger logger) { public DefaultLifecycles(Map<String, Lifecycle> lifecycles, org.codehaus.plexus.logging.Logger logger) {
this.customLifecycles = lifecycles; this.customLifecycles = lifecycles;
this.lookup = null; this.lookup = null;
this.registry = null;
} }
@Inject @Inject
public DefaultLifecycles(Lookup lookup) { public DefaultLifecycles(LifecycleRegistry registry, Lookup lookup) {
this.lookup = lookup; this.lookup = lookup;
this.registry = registry;
} }
/** /**
@ -149,7 +155,11 @@ public class DefaultLifecycles {
// Lifecycles cannot be cached as extensions might add custom lifecycles later in the execution. // Lifecycles cannot be cached as extensions might add custom lifecycles later in the execution.
try { try {
return lookup.lookupMap(Lifecycle.class); Map<String, Lifecycle> lifecycles = new HashMap<>(lookup.lookupMap(Lifecycle.class));
for (org.apache.maven.api.Lifecycle lf : registry) {
lifecycles.put(lf.id(), new Lifecycle(registry, lf));
}
return lifecycles;
} catch (LookupException e) { } catch (LookupException e) {
throw new IllegalStateException("Unable to lookup lifecycles from the plexus container", e); throw new IllegalStateException("Unable to lookup lifecycles from the plexus container", e);
} }

View File

@ -18,8 +18,8 @@
*/ */
package org.apache.maven.lifecycle; package org.apache.maven.lifecycle;
import java.util.List; import java.util.*;
import java.util.Map; import java.util.stream.Collectors;
import org.apache.maven.lifecycle.mapping.LifecyclePhase; import org.apache.maven.lifecycle.mapping.LifecyclePhase;
@ -35,6 +35,14 @@ public class Lifecycle {
this.defaultPhases = defaultPhases; this.defaultPhases = defaultPhases;
} }
public Lifecycle(
org.apache.maven.api.services.LifecycleRegistry registry, org.apache.maven.api.Lifecycle lifecycle) {
this.lifecycle = lifecycle;
this.id = lifecycle.id();
this.phases = registry.computePhases(lifecycle);
this.defaultPhases = getDefaultPhases(lifecycle);
}
// <lifecycle> // <lifecycle>
// <id>clean</id> // <id>clean</id>
// <phases> // <phases>
@ -53,12 +61,25 @@ public class Lifecycle {
private Map<String, LifecyclePhase> defaultPhases; private Map<String, LifecyclePhase> defaultPhases;
private org.apache.maven.api.Lifecycle lifecycle;
public String getId() { public String getId() {
return this.id; return id;
} }
public List<String> getPhases() { public List<String> getPhases() {
return this.phases; return phases;
}
static Map<String, LifecyclePhase> getDefaultPhases(org.apache.maven.api.Lifecycle lifecycle) {
Map<String, List<String>> goals = new HashMap<>();
lifecycle.phases().forEach(phase -> phase.plugins()
.forEach(plugin -> plugin.getExecutions().forEach(exec -> exec.getGoals()
.forEach(goal -> goals.computeIfAbsent(phase.name(), n -> new ArrayList<>())
.add(plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + plugin.getVersion()
+ ":" + goal)))));
return goals.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> new LifecyclePhase(String.join(",", e.getValue()))));
} }
public Map<String, LifecyclePhase> getDefaultLifecyclePhases() { public Map<String, LifecyclePhase> getDefaultLifecyclePhases() {

View File

@ -1,47 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.lifecycle.providers;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
/**
* {@code clean} lifecycle provider.
*/
@Named(CleanLifecycleProvider.LIFECYCLE_ID)
@Singleton
public final class CleanLifecycleProvider extends AbstractLifecycleProvider {
static final String LIFECYCLE_ID = "clean";
// START SNIPPET: clean
private static final String[] PHASES = {"pre-clean", "clean", "post-clean"};
private static final String MAVEN_CLEAN_PLUGIN_VERSION = "3.2.0";
private static final String[] BINDINGS = {
"clean", "org.apache.maven.plugins:maven-clean-plugin:" + MAVEN_CLEAN_PLUGIN_VERSION + ":clean"
};
// END SNIPPET: clean
@Inject
public CleanLifecycleProvider() {
super(LIFECYCLE_ID, PHASES, BINDINGS);
}
}

View File

@ -1,70 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.lifecycle.providers;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
/**
* {@code default} lifecycle provider.
*/
@Named(DefaultLifecycleProvider.LIFECYCLE_ID)
@Singleton
public final class DefaultLifecycleProvider extends AbstractLifecycleProvider {
static final String LIFECYCLE_ID = "default";
// START SNIPPET: default
private static final String[] PHASES = {
"validate",
"initialize",
"generate-sources",
"process-sources",
"generate-resources",
"process-resources",
"compile",
"process-classes",
"generate-test-sources",
"process-test-sources",
"generate-test-resources",
"process-test-resources",
"test-compile",
"process-test-classes",
"test",
"prepare-package",
"package",
"pre-integration-test",
"integration-test",
"post-integration-test",
"verify",
"install",
"deploy"
};
// END SNIPPET: default
@Inject
public DefaultLifecycleProvider() {
super(
LIFECYCLE_ID,
PHASES,
null // no global plugin bindings for default lifecycle: they are defined per-packaging in separate
// providers
);
}
}

View File

@ -1,48 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.lifecycle.providers;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
/**
* {@code site} lifecycle provider.
*/
@Named(SiteLifecycleProvider.LIFECYCLE_ID)
@Singleton
public final class SiteLifecycleProvider extends AbstractLifecycleProvider {
static final String LIFECYCLE_ID = "site";
// START SNIPPET: site
private static final String[] PHASES = {"pre-site", "site", "post-site", "site-deploy"};
private static final String MAVEN_SITE_PLUGIN_VERSION = "3.12.1";
private static final String[] BINDINGS = {
"site", "org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":site",
"site-deploy", "org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":deploy"
};
// END SNIPPET: site
@Inject
public SiteLifecycleProvider() {
super(LIFECYCLE_ID, PHASES, BINDINGS);
}
}

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.maven.internal.impl.DefaultLifecycleRegistry;
import org.apache.maven.internal.impl.DefaultLookup; import org.apache.maven.internal.impl.DefaultLookup;
import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
@ -94,7 +95,9 @@ class DefaultLifecyclesTest {
PlexusContainer mockedPlexusContainer = mock(PlexusContainer.class); PlexusContainer mockedPlexusContainer = mock(PlexusContainer.class);
when(mockedPlexusContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles); when(mockedPlexusContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles);
DefaultLifecycles dl = new DefaultLifecycles(new DefaultLookup(mockedPlexusContainer)); DefaultLifecycles dl = new DefaultLifecycles(
new DefaultLifecycleRegistry(Collections.emptyList(), Collections.emptyMap()),
new DefaultLookup(mockedPlexusContainer));
assertThat(dl.getLifeCycles().get(0).getId(), is("clean")); assertThat(dl.getLifeCycles().get(0).getId(), is("clean"));
assertThat(dl.getLifeCycles().get(1).getId(), is("default")); assertThat(dl.getLifeCycles().get(1).getId(), is("default"));

View File

@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.maven.internal.impl.DefaultLifecycleRegistry;
import org.apache.maven.internal.impl.DefaultLookup; import org.apache.maven.internal.impl.DefaultLookup;
import org.apache.maven.lifecycle.DefaultLifecycles; import org.apache.maven.lifecycle.DefaultLifecycles;
import org.apache.maven.lifecycle.Lifecycle; import org.apache.maven.lifecycle.Lifecycle;
@ -71,6 +72,7 @@ public class DefaultLifecyclesStub {
PlexusContainer mockedContainer = mock(PlexusContainer.class); PlexusContainer mockedContainer = mock(PlexusContainer.class);
when(mockedContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles); when(mockedContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles);
return new DefaultLifecycles(new DefaultLookup(mockedContainer)); DefaultLifecycleRegistry reg = new DefaultLifecycleRegistry();
return new DefaultLifecycles(reg, new DefaultLookup(mockedContainer));
} }
} }