Skip to content

Commit 52d453c

Browse files
authored
Complete Packaging in v4 api (#1451)
1 parent 6e50886 commit 52d453c

File tree

3 files changed

+168
-13
lines changed

3 files changed

+168
-13
lines changed

Diff for: api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.maven.api.annotations.Experimental;
2222
import org.apache.maven.api.annotations.Immutable;
2323
import org.apache.maven.api.annotations.Nonnull;
24+
import org.apache.maven.api.model.PluginContainer;
2425

2526
/**
2627
* Interface representing a Maven project packaging.
@@ -44,12 +45,19 @@ public interface Packaging extends ExtensibleEnum {
4445
*/
4546
@Nonnull
4647
default Language language() {
47-
return getType().getLanguage();
48+
return type().getLanguage();
4849
}
4950

5051
/**
5152
* The type of main artifact produced by this packaging.
5253
*/
5354
@Nonnull
54-
Type getType();
55+
Type type();
56+
57+
/**
58+
* Returns the binding to use specifically for this packaging.
59+
* This will be merged to the default packaging definition.
60+
*/
61+
@Nonnull
62+
PluginContainer plugins();
5563
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.api.spi;
20+
21+
import org.apache.maven.api.Packaging;
22+
import org.apache.maven.api.annotations.Consumer;
23+
import org.apache.maven.api.annotations.Experimental;
24+
25+
@Experimental
26+
@Consumer
27+
public interface PackagingProvider extends ExtensibleEnumProvider<Packaging> {}

Diff for: maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java

+131-11
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,53 @@
2222
import javax.inject.Named;
2323
import javax.inject.Singleton;
2424

25+
import java.util.ArrayList;
26+
import java.util.HashMap;
27+
import java.util.List;
2528
import java.util.Map;
2629
import java.util.Optional;
30+
import java.util.Set;
31+
import java.util.stream.Collectors;
2732

2833
import org.apache.maven.api.Packaging;
2934
import org.apache.maven.api.Type;
35+
import org.apache.maven.api.model.Dependency;
36+
import org.apache.maven.api.model.InputLocation;
37+
import org.apache.maven.api.model.InputSource;
38+
import org.apache.maven.api.model.Plugin;
39+
import org.apache.maven.api.model.PluginContainer;
40+
import org.apache.maven.api.model.PluginExecution;
3041
import org.apache.maven.api.services.PackagingRegistry;
3142
import org.apache.maven.api.services.TypeRegistry;
43+
import org.apache.maven.api.spi.PackagingProvider;
44+
import org.apache.maven.lifecycle.internal.DefaultLifecyclePluginAnalyzer;
3245
import org.apache.maven.lifecycle.mapping.LifecycleMapping;
46+
import org.apache.maven.lifecycle.mapping.LifecycleMojo;
47+
import org.apache.maven.lifecycle.mapping.LifecyclePhase;
48+
import org.slf4j.Logger;
49+
import org.slf4j.LoggerFactory;
3350

3451
/**
3552
* TODO: this is session scoped as SPI can contribute.
3653
*/
3754
@Named
3855
@Singleton
39-
public class DefaultPackagingRegistry implements PackagingRegistry {
56+
public class DefaultPackagingRegistry
57+
extends ExtensibleEnumRegistries.DefaultExtensibleEnumRegistry<Packaging, PackagingProvider>
58+
implements PackagingRegistry {
59+
60+
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPackagingRegistry.class);
61+
4062
private final Map<String, LifecycleMapping> lifecycleMappings;
4163

4264
private final TypeRegistry typeRegistry;
4365

4466
@Inject
45-
public DefaultPackagingRegistry(Map<String, LifecycleMapping> lifecycleMappings, TypeRegistry typeRegistry) {
67+
public DefaultPackagingRegistry(
68+
Map<String, LifecycleMapping> lifecycleMappings,
69+
TypeRegistry typeRegistry,
70+
List<PackagingProvider> providers) {
71+
super(providers);
4672
this.lifecycleMappings = lifecycleMappings;
4773
this.typeRegistry = typeRegistry;
4874
}
@@ -57,17 +83,111 @@ public Optional<Packaging> lookup(String id) {
5783
if (type == null) {
5884
return Optional.empty();
5985
}
86+
return Optional.of(new DefaultPackaging(id, type, getPlugins(lifecycleMapping)));
87+
}
6088

61-
return Optional.of(new Packaging() {
62-
@Override
63-
public String id() {
64-
return id;
65-
}
89+
private PluginContainer getPlugins(LifecycleMapping lifecycleMapping) {
90+
Map<String, Plugin> plugins = new HashMap<>();
91+
lifecycleMapping.getLifecycles().forEach((id, lifecycle) -> lifecycle
92+
.getLifecyclePhases()
93+
.forEach((phase, lifecyclePhase) -> parseLifecyclePhaseDefinitions(plugins, phase, lifecyclePhase)));
94+
return PluginContainer.newBuilder().plugins(plugins.values()).build();
95+
}
96+
97+
private void parseLifecyclePhaseDefinitions(Map<String, Plugin> plugins, String phase, LifecyclePhase goals) {
98+
InputSource inputSource =
99+
new InputSource(DefaultLifecyclePluginAnalyzer.DEFAULTLIFECYCLEBINDINGS_MODELID, null);
100+
InputLocation location = new InputLocation(-1, -1, inputSource, 0);
101+
102+
List<LifecycleMojo> mojos = goals.getMojos();
103+
if (mojos != null) {
104+
for (int i = 0; i < mojos.size(); i++) {
105+
LifecycleMojo mojo = mojos.get(i);
106+
107+
// Compute goal coordinates
108+
String groupId, artifactId, version, goal;
109+
String[] p = mojo.getGoal().trim().split(":");
110+
if (p.length == 3) {
111+
// <groupId>:<artifactId>:<goal>
112+
groupId = p[0];
113+
artifactId = p[1];
114+
version = null;
115+
goal = p[2];
116+
} else if (p.length == 4) {
117+
// <groupId>:<artifactId>:<version>:<goal>
118+
groupId = p[0];
119+
artifactId = p[1];
120+
version = p[2];
121+
goal = p[3];
122+
} else {
123+
// invalid
124+
LOGGER.warn(
125+
"Ignored invalid goal specification '{}' from lifecycle mapping for phase {}",
126+
mojo.getGoal(),
127+
phase);
128+
continue;
129+
}
130+
131+
String key = groupId + ":" + artifactId;
132+
133+
// Build plugin
134+
List<PluginExecution> execs = new ArrayList<>();
135+
List<Dependency> deps = new ArrayList<>();
66136

67-
@Override
68-
public Type getType() {
69-
return type;
137+
Plugin existing = plugins.get(key);
138+
if (existing != null) {
139+
if (version == null) {
140+
version = existing.getVersion();
141+
}
142+
execs.addAll(existing.getExecutions());
143+
deps.addAll(existing.getDependencies());
144+
}
145+
146+
PluginExecution execution = PluginExecution.newBuilder()
147+
.id(getExecutionId(existing, goal))
148+
.priority(i - mojos.size())
149+
.phase(phase)
150+
.goals(List.of(goal))
151+
.configuration(mojo.getConfiguration())
152+
.location("", location)
153+
.location("id", location)
154+
.location("phase", location)
155+
.location("goals", location)
156+
.build();
157+
execs.add(execution);
158+
159+
if (mojo.getDependencies() != null) {
160+
mojo.getDependencies().forEach(d -> deps.add(d.getDelegate()));
161+
}
162+
163+
Plugin plugin = Plugin.newBuilder()
164+
.groupId(groupId)
165+
.artifactId(artifactId)
166+
.version(version)
167+
.location("", location)
168+
.location("groupId", location)
169+
.location("artifactId", location)
170+
.location("version", location)
171+
.executions(execs)
172+
.dependencies(deps)
173+
.build();
174+
175+
plugins.put(key, plugin);
70176
}
71-
});
177+
}
72178
}
179+
180+
private static String getExecutionId(Plugin plugin, String goal) {
181+
Set<String> existingIds = plugin != null
182+
? plugin.getExecutions().stream().map(PluginExecution::getId).collect(Collectors.toSet())
183+
: Set.of();
184+
String base = "default-" + goal;
185+
String id = base;
186+
for (int index = 1; existingIds.contains(id); index++) {
187+
id = base + '-' + index;
188+
}
189+
return id;
190+
}
191+
192+
private record DefaultPackaging(String id, Type type, PluginContainer plugins) implements Packaging {}
73193
}

0 commit comments

Comments
 (0)