1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.lifecycle.internal;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.HashSet;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.maven.api.services.Lookup;
32 import org.apache.maven.api.xml.XmlNode;
33 import org.apache.maven.lifecycle.DefaultLifecycles;
34 import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
35 import org.apache.maven.lifecycle.Lifecycle;
36 import org.apache.maven.lifecycle.mapping.LifecycleMapping;
37 import org.apache.maven.lifecycle.mapping.LifecycleMojo;
38 import org.apache.maven.lifecycle.mapping.LifecyclePhase;
39 import org.apache.maven.model.InputLocation;
40 import org.apache.maven.model.InputSource;
41 import org.apache.maven.model.Plugin;
42 import org.apache.maven.model.PluginExecution;
43 import org.codehaus.plexus.util.xml.Xpp3Dom;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import static java.util.Objects.requireNonNull;
48
49
50
51
52
53
54 @Singleton
55 @Named
56 public class DefaultLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer {
57 public static final String DEFAULTLIFECYCLEBINDINGS_MODELID = "org.apache.maven:maven-core:"
58 + DefaultLifecyclePluginAnalyzer.class.getPackage().getImplementationVersion()
59 + ":default-lifecycle-bindings";
60
61 private final Logger logger = LoggerFactory.getLogger(getClass());
62
63 private final Lookup lookup;
64
65 private final DefaultLifecycles defaultLifeCycles;
66
67 @Inject
68 public DefaultLifecyclePluginAnalyzer(Lookup lookup, DefaultLifecycles defaultLifeCycles) {
69 this.lookup = requireNonNull(lookup);
70 this.defaultLifeCycles = requireNonNull(defaultLifeCycles);
71 }
72
73
74
75
76
77
78
79
80
81
82
83 @Override
84 public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
85 if (logger.isDebugEnabled()) {
86 logger.debug("Looking up lifecycle mappings for packaging " + packaging + " from "
87 + Thread.currentThread().getContextClassLoader());
88 }
89
90 LifecycleMapping lifecycleMappingForPackaging = lookupLifecycleMapping(packaging);
91
92 if (lifecycleMappingForPackaging == null) {
93 return null;
94 }
95
96 Map<Plugin, Plugin> plugins = new LinkedHashMap<>();
97
98 for (Lifecycle lifecycle : defaultLifeCycles.getLifeCycles()) {
99 org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
100 lifecycleMappingForPackaging.getLifecycles().get(lifecycle.getId());
101
102 Map<String, LifecyclePhase> phaseToGoalMapping = null;
103
104 if (lifecycleConfiguration != null) {
105 phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases();
106 } else if (lifecycle.getDefaultLifecyclePhases() != null) {
107 phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases();
108 }
109
110 if (phaseToGoalMapping != null) {
111 for (Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet()) {
112 String phase = goalsForLifecyclePhase.getKey();
113 LifecyclePhase goals = goalsForLifecyclePhase.getValue();
114 if (goals != null) {
115 parseLifecyclePhaseDefinitions(plugins, phase, goals);
116 }
117 }
118 }
119 }
120
121 return plugins.keySet();
122 }
123
124
125
126
127
128 private LifecycleMapping lookupLifecycleMapping(final String packaging) {
129 return lookup.lookupOptional(LifecycleMapping.class, packaging).orElse(null);
130 }
131
132 private void parseLifecyclePhaseDefinitions(Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals) {
133 InputSource inputSource = new InputSource();
134 inputSource.setModelId(DEFAULTLIFECYCLEBINDINGS_MODELID);
135 InputLocation location = new InputLocation(-1, -1, inputSource);
136 location.setLocation(0, location);
137
138 List<LifecycleMojo> mojos = goals.getMojos();
139 if (mojos != null) {
140
141 for (int i = 0; i < mojos.size(); i++) {
142 LifecycleMojo mojo = mojos.get(i);
143
144 GoalSpec gs = parseGoalSpec(mojo.getGoal());
145
146 if (gs == null) {
147 logger.warn(
148 "Ignored invalid goal specification '{}' from lifecycle mapping for phase {}",
149 mojo.getGoal(),
150 phase);
151 continue;
152 }
153
154 Plugin plugin = new Plugin();
155 plugin.setGroupId(gs.groupId);
156 plugin.setArtifactId(gs.artifactId);
157 plugin.setVersion(gs.version);
158
159 plugin.setLocation("", location);
160 plugin.setLocation("groupId", location);
161 plugin.setLocation("artifactId", location);
162 plugin.setLocation("version", location);
163
164 Plugin existing = plugins.get(plugin);
165 if (existing != null) {
166 if (existing.getVersion() == null) {
167 existing.setVersion(plugin.getVersion());
168 existing.setLocation("version", location);
169 }
170 plugin = existing;
171 } else {
172 plugins.put(plugin, plugin);
173 }
174
175 PluginExecution execution = new PluginExecution();
176 execution.setId(getExecutionId(plugin, gs.goal));
177 execution.setPhase(phase);
178 execution.setPriority(i - mojos.size());
179 execution.getGoals().add(gs.goal);
180
181 execution.setLocation("", location);
182 execution.setLocation("id", location);
183 execution.setLocation("phase", location);
184 execution.setLocation("goals", location);
185
186 XmlNode lifecycleConfiguration = mojo.getConfiguration();
187 if (lifecycleConfiguration != null) {
188 execution.setConfiguration(new Xpp3Dom(lifecycleConfiguration));
189 }
190
191 if (mojo.getDependencies() != null) {
192 plugin.setDependencies(mojo.getDependencies());
193 }
194 plugin.getExecutions().add(execution);
195 }
196 }
197 }
198
199 private GoalSpec parseGoalSpec(String goalSpec) {
200 GoalSpec gs = new GoalSpec();
201
202 String[] p = goalSpec.trim().split(":");
203
204 if (p.length == 3) {
205
206 gs.groupId = p[0];
207 gs.artifactId = p[1];
208 gs.goal = p[2];
209 } else if (p.length == 4) {
210
211 gs.groupId = p[0];
212 gs.artifactId = p[1];
213 gs.version = p[2];
214 gs.goal = p[3];
215 } else {
216
217 gs = null;
218 }
219
220 return gs;
221 }
222
223 private String getExecutionId(Plugin plugin, String goal) {
224 Set<String> existingIds = new HashSet<>();
225 for (PluginExecution execution : plugin.getExecutions()) {
226 existingIds.add(execution.getId());
227 }
228
229 String base = "default-" + goal;
230 String id = base;
231
232 for (int index = 1; existingIds.contains(id); index++) {
233 id = base + '-' + index;
234 }
235
236 return id;
237 }
238
239 static class GoalSpec {
240
241 String groupId;
242
243 String artifactId;
244
245 String version;
246
247 String goal;
248 }
249 }