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.DefaultDependencyNode;
56 import org.eclipse.aether.graph.Dependency;
57 import org.eclipse.aether.graph.DependencyFilter;
58 import org.eclipse.aether.installation.InstallRequest;
59 import org.eclipse.aether.installation.InstallationException;
60 import org.eclipse.aether.repository.LocalRepository;
61 import org.eclipse.aether.repository.LocalRepositoryManager;
62 import org.eclipse.aether.repository.RemoteRepository;
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 | InstallationException | ArtifactResolutionException e) {
176 throw new MojoExecutionException(e.getMessage(), e);
177 }
178 }
179
180 private void resolveProjectArtifacts(Map<String, Artifact> resolvedArtifacts) {
181
182
183 if (project.getArtifact() != null && project.getArtifact().getFile() != null) {
184 Artifact artifact = RepositoryUtils.toArtifact(project.getArtifact());
185 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
186 }
187
188 project.getAttachedArtifacts().stream()
189 .map(RepositoryUtils::toArtifact)
190 .forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
191 }
192
193 private void resolveProjectPoms(MavenProject project, Map<String, Artifact> resolvedArtifacts)
194 throws ArtifactResolutionException {
195
196 if (project == null) {
197 return;
198 }
199
200 Artifact projectPom = RepositoryUtils.toArtifact(new ProjectArtifact(project));
201 if (projectPom.getFile() != null) {
202 resolvedArtifacts.put(projectPom.toString(), projectPom);
203 } else {
204 Artifact artifact = resolveArtifact(projectPom, project.getRemoteProjectRepositories());
205 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
206 }
207 resolveProjectPoms(project.getParent(), resolvedArtifacts);
208 }
209
210 private void resolveProjectDependencies(Map<String, Artifact> resolvedArtifacts)
211 throws ArtifactResolutionException, MojoExecutionException, DependencyResolutionException {
212
213 DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(scope);
214
215 ArtifactTypeRegistry artifactTypeRegistry =
216 session.getRepositorySession().getArtifactTypeRegistry();
217
218 List<Dependency> managedDependencies = Optional.ofNullable(project.getDependencyManagement())
219 .map(DependencyManagement::getDependencies)
220 .orElseGet(Collections::emptyList)
221 .stream()
222 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
223 .collect(Collectors.toList());
224
225 List<Dependency> dependencies = project.getDependencies().stream()
226 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
227 .filter(d -> classpathFilter.accept(new DefaultDependencyNode(d), null))
228 .collect(Collectors.toList());
229
230 CollectRequest collectRequest = new CollectRequest();
231 collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
232 collectRequest.setDependencies(dependencies);
233 collectRequest.setManagedDependencies(managedDependencies);
234
235 collectRequest.setRepositories(project.getRemoteProjectRepositories());
236
237 DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
238
239 DependencyResult dependencyResult =
240 repositorySystem.resolveDependencies(session.getRepositorySession(), request);
241
242 List<Artifact> artifacts = dependencyResult.getArtifactResults().stream()
243 .map(ArtifactResult::getArtifact)
244 .collect(Collectors.toList());
245
246 artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
247 resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
248 }
249
250
251
252
253 private void resolveExtraArtifacts(Map<String, Artifact> resolvedArtifacts)
254 throws MojoExecutionException, DependencyResolutionException, ArtifactResolutionException {
255
256 if (extraArtifacts == null) {
257 return;
258 }
259
260 DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
261
262 for (String extraArtifact : extraArtifacts) {
263 String[] gav = extraArtifact.split(":");
264 if (gav.length < 3 || gav.length > 5) {
265 throw new MojoExecutionException("Invalid artifact " + extraArtifact);
266 }
267
268 String groupId = gav[0];
269 String artifactId = gav[1];
270 String version = gav[2];
271
272 String type = "jar";
273 if (gav.length > 3) {
274 type = gav[3];
275 }
276
277 String classifier = null;
278 if (gav.length == 5) {
279 classifier = gav[4];
280 }
281
282 ArtifactType artifactType =
283 session.getRepositorySession().getArtifactTypeRegistry().get(type);
284
285 List<RemoteRepository> remoteRepositories =
286 artifactType != null && "maven-plugin".equals(artifactType.getId())
287 ? project.getRemotePluginRepositories()
288 : project.getRemoteProjectRepositories();
289
290 Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, null, version, artifactType);
291
292 resolvePomsForArtifacts(Collections.singletonList(artifact), resolvedArtifacts, remoteRepositories);
293
294 CollectRequest collectRequest = new CollectRequest();
295 Dependency root = new Dependency(artifact, JavaScopes.COMPILE);
296 collectRequest.setRoot(root);
297 collectRequest.setRepositories(remoteRepositories);
298
299 DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
300 DependencyResult dependencyResult =
301 repositorySystem.resolveDependencies(session.getRepositorySession(), request);
302
303 List<Artifact> artifacts = dependencyResult.getArtifactResults().stream()
304 .map(ArtifactResult::getArtifact)
305 .collect(Collectors.toList());
306
307 artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
308 resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
309 }
310 }
311
312 private void resolvePomsForArtifacts(
313 List<Artifact> artifacts,
314 Map<String, Artifact> resolvedArtifacts,
315 List<RemoteRepository> remoteRepositories)
316 throws ArtifactResolutionException, MojoExecutionException {
317
318 for (Artifact a : artifacts) {
319 Artifact artifactResult = resolveArtifact(new SubArtifact(a, "", "pom"), remoteRepositories);
320 resolvePomWithParents(artifactResult, resolvedArtifacts, remoteRepositories);
321 }
322 }
323
324 private void resolvePomWithParents(
325 Artifact artifact, Map<String, Artifact> resolvedArtifacts, List<RemoteRepository> remoteRepositories)
326 throws MojoExecutionException, ArtifactResolutionException {
327
328 if (resolvedArtifacts.containsKey(ArtifactIdUtils.toId(artifact))) {
329 return;
330 }
331
332 Model model = PomUtils.loadPom(artifact.getFile());
333 Parent parent = model.getParent();
334 if (parent != null) {
335 DefaultArtifact pom =
336 new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
337 Artifact resolvedPom = resolveArtifact(pom, remoteRepositories);
338 resolvePomWithParents(resolvedPom, resolvedArtifacts, remoteRepositories);
339 }
340
341 resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
342 }
343
344 private Artifact resolveArtifact(Artifact artifact, List<RemoteRepository> remoteRepositories)
345 throws ArtifactResolutionException {
346
347 ArtifactRequest request = new ArtifactRequest();
348 request.setArtifact(artifact);
349 request.setRepositories(remoteRepositories);
350 ArtifactResult artifactResult = repositorySystem.resolveArtifact(session.getRepositorySession(), request);
351 return artifactResult.getArtifact();
352 }
353
354
355
356
357 private void installArtifacts(Map<String, Artifact> resolvedArtifacts) throws InstallationException {
358
359 RepositorySystemSession systemSessionForLocalRepo = createSystemSessionForLocalRepo();
360
361
362
363
364
365 Map<String, List<Artifact>> collect = resolvedArtifacts.values().stream()
366 .filter(a -> !hasTheSamePathAsTarget(a, systemSessionForLocalRepo))
367 .collect(Collectors.groupingBy(
368 a -> String.format("%s:%s:%s", a.getGroupId(), a.getArtifactId(), a.getVersion()),
369 LinkedHashMap::new,
370 Collectors.toList()));
371
372 for (List<Artifact> artifacts : collect.values()) {
373 InstallRequest request = new InstallRequest();
374 request.setArtifacts(artifacts);
375 repositorySystem.install(systemSessionForLocalRepo, request);
376 }
377 }
378
379 private boolean hasTheSamePathAsTarget(Artifact artifact, RepositorySystemSession systemSession) {
380 try {
381 LocalRepositoryManager lrm = systemSession.getLocalRepositoryManager();
382 File targetBasedir = lrm.getRepository().getBasedir();
383 if (targetBasedir == null) {
384 return false;
385 }
386 File targetFile = new File(targetBasedir, lrm.getPathForLocalArtifact(artifact)).getCanonicalFile();
387 File sourceFile = artifact.getFile().getCanonicalFile();
388 if (Objects.equals(targetFile, sourceFile)) {
389 getLog().debug("Skip install the same target " + sourceFile);
390 return true;
391 }
392 return false;
393 } catch (IOException e) {
394 throw new UncheckedIOException(e);
395 }
396 }
397
398
399
400
401 private RepositorySystemSession createSystemSessionForLocalRepo() {
402 RepositorySystemSession repositorySystemSession = session.getRepositorySession();
403 if (localRepositoryPath != null) {
404
405 DefaultRepositorySystemSession newSession =
406 new DefaultRepositorySystemSession(session.getRepositorySession());
407
408 newSession.setCache(new DefaultRepositoryCache());
409
410 String contentType = newSession.getLocalRepository().getContentType();
411 if ("enhanced".equals(contentType)) {
412 contentType = "default";
413 }
414 LocalRepositoryManager localRepositoryManager = repositorySystem.newLocalRepositoryManager(
415 newSession, new LocalRepository(localRepositoryPath, contentType));
416
417 newSession.setLocalRepositoryManager(localRepositoryManager);
418 repositorySystemSession = newSession;
419 getLog().debug("localRepoPath: "
420 + localRepositoryManager.getRepository().getBasedir());
421 }
422
423 return repositorySystemSession;
424 }
425 }