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.model;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29
30 import org.apache.maven.api.Packaging;
31 import org.apache.maven.api.di.Inject;
32 import org.apache.maven.api.di.Named;
33 import org.apache.maven.api.di.Singleton;
34 import org.apache.maven.api.model.Build;
35 import org.apache.maven.api.model.Model;
36 import org.apache.maven.api.model.Plugin;
37 import org.apache.maven.api.model.PluginContainer;
38 import org.apache.maven.api.model.PluginExecution;
39 import org.apache.maven.api.model.PluginManagement;
40 import org.apache.maven.api.services.BuilderProblem.Severity;
41 import org.apache.maven.api.services.LifecycleRegistry;
42 import org.apache.maven.api.services.ModelBuilderRequest;
43 import org.apache.maven.api.services.ModelProblem.Version;
44 import org.apache.maven.api.services.ModelProblemCollector;
45 import org.apache.maven.api.services.PackagingRegistry;
46 import org.apache.maven.api.services.model.LifecycleBindingsInjector;
47
48
49
50
51
52 @Named
53 @Singleton
54 public class DefaultLifecycleBindingsInjector implements LifecycleBindingsInjector {
55
56 private final LifecycleBindingsMerger merger = new LifecycleBindingsMerger();
57
58 private final LifecycleRegistry lifecycleRegistry;
59 private final PackagingRegistry packagingRegistry;
60
61 @Inject
62 public DefaultLifecycleBindingsInjector(LifecycleRegistry lifecycleRegistry, PackagingRegistry packagingRegistry) {
63 this.lifecycleRegistry = lifecycleRegistry;
64 this.packagingRegistry = packagingRegistry;
65 }
66
67 public Model injectLifecycleBindings(Model model, ModelBuilderRequest request, ModelProblemCollector problems) {
68 String packagingId = model.getPackaging();
69 Packaging packaging = packagingRegistry.lookup(packagingId).orElse(null);
70 if (packaging == null) {
71 problems.add(
72 Severity.ERROR, Version.BASE, "Unknown packaging: " + packagingId, model.getLocation("packaging"));
73 return model;
74 } else {
75 Map<String, PluginContainer> plugins = new HashMap<>(packaging.plugins());
76 lifecycleRegistry.stream()
77 .filter(lf -> !plugins.containsKey(lf.id()))
78 .forEach(lf -> plugins.put(
79 lf.id(),
80 PluginContainer.newBuilder()
81 .plugins(lf.phases().stream()
82 .flatMap(phase -> phase.plugins().stream())
83 .toList())
84 .build()));
85 Map<Plugin, Plugin> allPlugins = new LinkedHashMap<>();
86 plugins.values().stream().flatMap(pc -> pc.getPlugins().stream()).forEach(p -> addPlugin(allPlugins, p));
87 Model lifecycleModel = Model.newBuilder()
88 .build(Build.newBuilder().plugins(allPlugins.values()).build())
89 .build();
90 return merger.merge(model, lifecycleModel);
91 }
92 }
93
94 private void addPlugin(Map<Plugin, Plugin> plugins, Plugin plugin) {
95 Plugin cur = plugins.putIfAbsent(plugin, plugin);
96 if (cur != null) {
97 Map<String, PluginExecution> execs = new LinkedHashMap<>();
98 cur.getExecutions().forEach(e -> execs.put(e.getId(), e));
99 plugin.getExecutions().forEach(e -> {
100 int i = 0;
101 String id = e.getId();
102 while (execs.putIfAbsent(id, e.withId(id)) != null) {
103 id = e.getId() + "-" + (++i);
104 }
105 });
106 Plugin merged = cur.withExecutions(execs.values());
107 plugins.put(merged, merged);
108 }
109 }
110
111 private static String getExecutionId(Plugin plugin, String goal) {
112 Set<String> existingIds = plugin != null
113 ? plugin.getExecutions().stream().map(PluginExecution::getId).collect(Collectors.toSet())
114 : Set.of();
115 String base = "default-" + goal;
116 String id = base;
117 for (int index = 1; existingIds.contains(id); index++) {
118 id = base + '-' + index;
119 }
120 return id;
121 }
122
123
124
125
126 protected static class LifecycleBindingsMerger extends MavenModelMerger {
127
128 private static final String PLUGIN_MANAGEMENT = "plugin-management";
129
130 public Model merge(Model target, Model source) {
131 Build targetBuild = target.getBuild();
132 if (targetBuild == null) {
133 targetBuild = Build.newInstance();
134 }
135
136 Map<Object, Object> context =
137 Collections.singletonMap(PLUGIN_MANAGEMENT, targetBuild.getPluginManagement());
138
139 Build.Builder builder = Build.newBuilder(targetBuild);
140 mergePluginContainer_Plugins(builder, targetBuild, source.getBuild(), false, context);
141
142 return target.withBuild(builder.build());
143 }
144
145 @SuppressWarnings({"checkstyle:methodname"})
146 @Override
147 protected void mergePluginContainer_Plugins(
148 PluginContainer.Builder builder,
149 PluginContainer target,
150 PluginContainer source,
151 boolean sourceDominant,
152 Map<Object, Object> context) {
153 List<Plugin> src = source.getPlugins();
154 if (!src.isEmpty()) {
155 List<Plugin> tgt = target.getPlugins();
156
157 Map<Object, Plugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
158
159 for (Plugin element : tgt) {
160 Object key = getPluginKey().apply(element);
161 merged.put(key, element);
162 }
163
164 Map<Object, Plugin> added = new LinkedHashMap<>();
165
166 for (Plugin element : src) {
167 Object key = getPluginKey().apply(element);
168 Plugin existing = merged.get(key);
169 if (existing != null) {
170 element = mergePlugin(existing, element, sourceDominant, context);
171 } else {
172 added.put(key, element);
173 }
174 merged.put(key, element);
175 }
176
177 if (!added.isEmpty()) {
178 PluginManagement pluginMgmt = (PluginManagement) context.get(PLUGIN_MANAGEMENT);
179 if (pluginMgmt != null) {
180 for (Plugin managedPlugin : pluginMgmt.getPlugins()) {
181 Object key = getPluginKey().apply(managedPlugin);
182 Plugin addedPlugin = added.get(key);
183 if (addedPlugin != null) {
184 Plugin plugin =
185 mergePlugin(managedPlugin, addedPlugin, sourceDominant, Collections.emptyMap());
186 merged.put(key, plugin);
187 }
188 }
189 }
190 }
191
192 List<Plugin> result = new ArrayList<>(merged.values());
193
194 builder.plugins(result);
195 }
196 }
197
198 @Override
199 protected void mergePluginExecution_Priority(
200 PluginExecution.Builder builder,
201 PluginExecution target,
202 PluginExecution source,
203 boolean sourceDominant,
204 Map<Object, Object> context) {
205 if (target.getPriority() > source.getPriority()) {
206 builder.priority(source.getPriority());
207 builder.location("priority", source.getLocation("priority"));
208 }
209 }
210
211 }
212 }