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