1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.invoker;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.UncheckedIOException;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Optional;
30 import java.util.stream.Collectors;
31
32 import org.apache.maven.RepositoryUtils;
33 import org.apache.maven.execution.MavenSession;
34 import org.apache.maven.model.DependencyManagement;
35 import org.apache.maven.model.Model;
36 import org.apache.maven.model.Parent;
37 import org.apache.maven.plugin.AbstractMojo;
38 import org.apache.maven.plugin.MojoExecutionException;
39 import org.apache.maven.plugins.annotations.Component;
40 import org.apache.maven.plugins.annotations.LifecyclePhase;
41 import org.apache.maven.plugins.annotations.Mojo;
42 import org.apache.maven.plugins.annotations.Parameter;
43 import org.apache.maven.plugins.annotations.ResolutionScope;
44 import org.apache.maven.project.MavenProject;
45 import org.apache.maven.project.artifact.ProjectArtifact;
46 import org.eclipse.aether.DefaultRepositoryCache;
47 import org.eclipse.aether.DefaultRepositorySystemSession;
48 import org.eclipse.aether.RepositorySystem;
49 import org.eclipse.aether.RepositorySystemSession;
50 import org.eclipse.aether.artifact.Artifact;
51 import org.eclipse.aether.artifact.ArtifactType;
52 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
53 import org.eclipse.aether.artifact.DefaultArtifact;
54 import org.eclipse.aether.collection.CollectRequest;
55 import org.eclipse.aether.graph.Dependency;
56 import org.eclipse.aether.graph.DependencyFilter;
57 import org.eclipse.aether.installation.InstallRequest;
58 import org.eclipse.aether.installation.InstallationException;
59 import org.eclipse.aether.repository.LocalRepository;
60 import org.eclipse.aether.repository.LocalRepositoryManager;
61 import org.eclipse.aether.repository.RemoteRepository;
62 import org.eclipse.aether.resolution.ArtifactDescriptorException;
63 import org.eclipse.aether.resolution.ArtifactRequest;
64 import org.eclipse.aether.resolution.ArtifactResolutionException;
65 import org.eclipse.aether.resolution.ArtifactResult;
66 import org.eclipse.aether.resolution.DependencyRequest;
67 import org.eclipse.aether.resolution.DependencyResolutionException;
68 import org.eclipse.aether.resolution.DependencyResult;
69 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
70 import org.eclipse.aether.util.artifact.JavaScopes;
71 import org.eclipse.aether.util.artifact.SubArtifact;
72 import org.eclipse.aether.util.filter.DependencyFilterUtils;
73
74
75
76
77
78
79
80
81
82
83 @Mojo(
84 name = "install",
85 defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST,
86 requiresDependencyResolution = ResolutionScope.TEST,
87 threadSafe = true)
88 public class InstallMojo extends AbstractMojo {
89
90
91
92 @Component
93 private RepositorySystem repositorySystem;
94
95 @Parameter(defaultValue = "${session}", readonly = true, required = true)
96 private MavenSession session;
97
98 @Parameter(defaultValue = "${project}", readonly = true, required = true)
99 private MavenProject project;
100
101
102
103
104
105
106
107 @Parameter(
108 property = "invoker.localRepositoryPath",
109 defaultValue = "${session.localRepository.basedir}",
110 required = true)
111 private File localRepositoryPath;
112
113
114
115
116
117
118
119 @Parameter(property = "invoker.skip", defaultValue = "false")
120 private boolean skipInstallation;
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 @Parameter
144 private String[] extraArtifacts;
145
146
147
148
149
150
151 @Parameter(property = "invoker.install.scope", defaultValue = "runtime")
152 private String scope;
153
154
155
156
157
158
159 public void execute() throws MojoExecutionException {
160 if (skipInstallation) {
161 getLog().info("Skipping artifact installation per configuration.");
162 return;
163 }
164
165 Map<String, Artifact> resolvedArtifacts = new LinkedHashMap<>();
166
167 try {
168
169 resolveProjectArtifacts(resolvedArtifacts);
170 resolveProjectPoms(project, resolvedArtifacts);
171 resolveProjectDependencies(resolvedArtifacts);
172 resolveExtraArtifacts(resolvedArtifacts);
173 installArtifacts(resolvedArtifacts);
174
175 } catch (DependencyResolutionException
176 | InstallationException
177 | ArtifactDescriptorException
178 | ArtifactResolutionException e) {
179 throw new MojoExecutionException(e.getMessage(), e);
180 }
181 }
182
183 private void resolveProjectArtifacts(Map<String, Artifact> resolvedArtifacts) {
184
185
186 if (project.getArtifact() != null && project.getArtifact().getFile() != null) {
187 Artifact artifact = RepositoryUtils.toArtifact(project.getArtifact());
188 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
189 }
190
191 project.getAttachedArtifacts().stream()
192 .map(RepositoryUtils::toArtifact)
193 .forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
194 }
195
196 private void resolveProjectPoms(MavenProject project, Map<String, Artifact> resolvedArtifacts)
197 throws ArtifactResolutionException {
198
199 if (project == null) {
200 return;
201 }
202
203 Artifact projectPom = RepositoryUtils.toArtifact(new ProjectArtifact(project));
204 if (projectPom.getFile() != null) {
205 resolvedArtifacts.put(projectPom.toString(), projectPom);
206 } else {
207 Artifact artifact = resolveArtifact(projectPom, project.getRemoteProjectRepositories());
208 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
209 }
210 resolveProjectPoms(project.getParent(), resolvedArtifacts);
211 }
212
213 private void resolveProjectDependencies(Map<String, Artifact> resolvedArtifacts)
214 throws ArtifactResolutionException, MojoExecutionException, DependencyResolutionException {
215
216 DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(scope);
217
218 ArtifactTypeRegistry artifactTypeRegistry =
219 session.getRepositorySession().getArtifactTypeRegistry();
220
221 List<Dependency> managedDependencies = Optional.ofNullable(project.getDependencyManagement())
222 .map(DependencyManagement::getDependencies)
223 .orElseGet(Collections::emptyList)
224 .stream()
225 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
226 .collect(Collectors.toList());
227
228 List<Dependency> dependencies = project.getDependencies().stream()
229 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
230 .collect(Collectors.toList());
231
232 CollectRequest collectRequest = new CollectRequest();
233 collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
234 collectRequest.setDependencies(dependencies);
235 collectRequest.setManagedDependencies(managedDependencies);
236
237 collectRequest.setRepositories(project.getRemoteProjectRepositories());
238
239 DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
240
241 DependencyResult dependencyResult =
242 repositorySystem.resolveDependencies(session.getRepositorySession(), request);
243
244 List<Artifact> artifacts = dependencyResult.getArtifactResults().stream()
245 .map(ArtifactResult::getArtifact)
246 .collect(Collectors.toList());
247
248 artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
249 resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
250 }
251
252
253
254
255
256
257 private void resolveExtraArtifacts(Map<String, Artifact> resolvedArtifacts)
258 throws MojoExecutionException, DependencyResolutionException, ArtifactDescriptorException,
259 ArtifactResolutionException {
260
261 if (extraArtifacts == null) {
262 return;
263 }
264
265 DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
266
267 for (String extraArtifact : extraArtifacts) {
268 String[] gav = extraArtifact.split(":");
269 if (gav.length < 3 || gav.length > 5) {
270 throw new MojoExecutionException("Invalid artifact " + extraArtifact);
271 }
272
273 String groupId = gav[0];
274 String artifactId = gav[1];
275 String version = gav[2];
276
277 String type = "jar";
278 if (gav.length > 3) {
279 type = gav[3];
280 }
281
282 String classifier = null;
283 if (gav.length == 5) {
284 classifier = gav[4];
285 }
286
287 ArtifactType artifactType =
288 session.getRepositorySession().getArtifactTypeRegistry().get(type);
289
290 List<RemoteRepository> remoteRepositories =
291 artifactType != null && "maven-plugin".equals(artifactType.getId())
292 ? project.getRemotePluginRepositories()
293 : project.getRemoteProjectRepositories();
294
295 Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, null, version, artifactType);
296
297 resolvePomsForArtifacts(Collections.singletonList(artifact), resolvedArtifacts, remoteRepositories);
298
299 CollectRequest collectRequest = new CollectRequest();
300 Dependency root = new Dependency(artifact, JavaScopes.COMPILE);
301 collectRequest.setRoot(root);
302 collectRequest.setRepositories(remoteRepositories);
303
304 DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
305 DependencyResult dependencyResult =
306 repositorySystem.resolveDependencies(session.getRepositorySession(), request);
307
308 List<Artifact> artifacts = dependencyResult.getArtifactResults().stream()
309 .map(ArtifactResult::getArtifact)
310 .collect(Collectors.toList());
311
312 artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
313 resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
314 }
315 }
316
317 private void resolvePomsForArtifacts(
318 List<Artifact> artifacts,
319 Map<String, Artifact> resolvedArtifacts,
320 List<RemoteRepository> remoteRepositories)
321 throws ArtifactResolutionException, MojoExecutionException {
322
323 for (Artifact a : artifacts) {
324 Artifact artifactResult = resolveArtifact(new SubArtifact(a, "", "pom"), remoteRepositories);
325 resolvePomWithParents(artifactResult, resolvedArtifacts, remoteRepositories);
326 }
327 }
328
329 private void resolvePomWithParents(
330 Artifact artifact, Map<String, Artifact> resolvedArtifacts, List<RemoteRepository> remoteRepositories)
331 throws MojoExecutionException, ArtifactResolutionException {
332
333 if (resolvedArtifacts.containsKey(ArtifactIdUtils.toId(artifact))) {
334 return;
335 }
336
337 Model model = PomUtils.loadPom(artifact.getFile());
338 Parent parent = model.getParent();
339 if (parent != null) {
340 DefaultArtifact pom =
341 new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
342 Artifact resolvedPom = resolveArtifact(pom, remoteRepositories);
343 resolvePomWithParents(resolvedPom, resolvedArtifacts, remoteRepositories);
344 }
345
346 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
347 }
348
349 private Artifact resolveArtifact(Artifact artifact, List<RemoteRepository> remoteRepositories)
350 throws ArtifactResolutionException {
351
352 ArtifactRequest request = new ArtifactRequest();
353 request.setArtifact(artifact);
354 request.setRepositories(remoteRepositories);
355 ArtifactResult artifactResult = repositorySystem.resolveArtifact(session.getRepositorySession(), request);
356 return artifactResult.getArtifact();
357 }
358
359
360
361
362 private void installArtifacts(Map<String, Artifact> resolvedArtifacts) throws InstallationException {
363
364 RepositorySystemSession systemSessionForLocalRepo = createSystemSessionForLocalRepo();
365
366
367
368
369
370 Map<String, List<Artifact>> collect = resolvedArtifacts.values().stream()
371 .filter(a -> !hasTheSamePathAsTarget(a, systemSessionForLocalRepo))
372 .collect(Collectors.groupingBy(
373 a -> String.format("%s:%s:%s", a.getGroupId(), a.getArtifactId(), a.getVersion()),
374 LinkedHashMap::new,
375 Collectors.toList()));
376
377 for (List<Artifact> artifacts : collect.values()) {
378 InstallRequest request = new InstallRequest();
379 request.setArtifacts(artifacts);
380 repositorySystem.install(systemSessionForLocalRepo, request);
381 }
382 }
383
384 private boolean hasTheSamePathAsTarget(Artifact artifact, RepositorySystemSession systemSession) {
385 try {
386 LocalRepositoryManager lrm = systemSession.getLocalRepositoryManager();
387 File targetBasedir = lrm.getRepository().getBasedir();
388 if (targetBasedir == null) {
389 return false;
390 }
391 File targetFile = new File(targetBasedir, lrm.getPathForLocalArtifact(artifact)).getCanonicalFile();
392 File sourceFile = artifact.getFile().getCanonicalFile();
393 if (Objects.equals(targetFile, sourceFile)) {
394 getLog().debug("Skip install the same target " + sourceFile);
395 return true;
396 }
397 return false;
398 } catch (IOException e) {
399 throw new UncheckedIOException(e);
400 }
401 }
402
403
404
405
406 private RepositorySystemSession createSystemSessionForLocalRepo() {
407 RepositorySystemSession repositorySystemSession = session.getRepositorySession();
408 if (localRepositoryPath != null) {
409
410 DefaultRepositorySystemSession newSession =
411 new DefaultRepositorySystemSession(session.getRepositorySession());
412
413 newSession.setCache(new DefaultRepositoryCache());
414
415 String contentType = newSession.getLocalRepository().getContentType();
416 if ("enhanced".equals(contentType)) {
417 contentType = "default";
418 }
419 LocalRepositoryManager localRepositoryManager = repositorySystem.newLocalRepositoryManager(
420 newSession, new LocalRepository(localRepositoryPath, contentType));
421
422 newSession.setLocalRepositoryManager(localRepositoryManager);
423 repositorySystemSession = newSession;
424 getLog().debug("localRepoPath: "
425 + localRepositoryManager.getRepository().getBasedir());
426 }
427
428 return repositorySystemSession;
429 }
430 }