View Javadoc
1   /*
2    * Copyright 2017-2022 original authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package io.micronaut.build.services;
17  
18  import io.micronaut.core.util.StringUtils;
19  import io.micronaut.testresources.buildtools.MavenDependency;
20  import org.apache.maven.execution.MavenSession;
21  import org.apache.maven.project.MavenProject;
22  import org.eclipse.aether.RepositorySystem;
23  import org.eclipse.aether.RepositorySystemSession;
24  import org.eclipse.aether.artifact.Artifact;
25  import org.eclipse.aether.artifact.DefaultArtifact;
26  import org.eclipse.aether.collection.CollectRequest;
27  import org.eclipse.aether.graph.Dependency;
28  import org.eclipse.aether.graph.DependencyFilter;
29  import org.eclipse.aether.resolution.ArtifactResult;
30  import org.eclipse.aether.resolution.DependencyRequest;
31  import org.eclipse.aether.resolution.DependencyResolutionException;
32  import org.eclipse.aether.resolution.DependencyResult;
33  import org.eclipse.aether.util.artifact.JavaScopes;
34  import org.eclipse.aether.util.filter.DependencyFilterUtils;
35  
36  import javax.inject.Inject;
37  import javax.inject.Singleton;
38  import java.io.File;
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.stream.Collectors;
44  import java.util.stream.Stream;
45  
46  /**
47   * Utility methods for performing dependency resolution.
48   */
49  @Singleton
50  public class DependencyResolutionService {
51  
52      public static final String TEST_RESOURCES_GROUP = "io.micronaut.testresources";
53      public static final String TEST_RESOURCES_ARTIFACT_ID_PREFIX = "micronaut-test-resources-";
54  
55      private static final String JAR_EXTENSION = "jar";
56  
57      private final MavenSession mavenSession;
58  
59      private final MavenProject mavenProject;
60  
61      private final RepositorySystem repositorySystem;
62  
63      @Inject
64      public DependencyResolutionService(MavenSession mavenSession, MavenProject mavenProject, RepositorySystem repositorySystem) {
65          this.mavenSession = mavenSession;
66          this.mavenProject = mavenProject;
67          this.repositorySystem = repositorySystem;
68      }
69  
70      private static Stream<File> streamClasspath(List<ArtifactResult> resolutionResult) {
71          return resolutionResult
72                  .stream()
73                  .map(ArtifactResult::getArtifact)
74                  .map(Artifact::getFile);
75      }
76  
77      public static List<String> toClasspath(List<ArtifactResult> resolutionResult) {
78          return streamClasspath(resolutionResult)
79                  .map(File::getAbsolutePath)
80                  .collect(Collectors.toList());
81      }
82  
83      public static List<File> toClasspathFiles(List<ArtifactResult> resolutionResult) {
84          return streamClasspath(resolutionResult)
85                  .collect(Collectors.toList());
86      }
87  
88      public static Dependency mavenDependencyToAetherDependency(org.apache.maven.model.Dependency d) {
89          Artifact artifact = mavenDependencyToAetherArtifact(d);
90          return new Dependency(artifact, d.getScope(), Boolean.valueOf(d.getOptional()));
91      }
92  
93      public static Artifact mavenDependencyToAetherArtifact(org.apache.maven.model.Dependency d) {
94          return new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getClassifier(), d.getType(), d.getVersion());
95      }
96  
97      public static MavenDependency mavenDependencyToTestResourcesDependency(org.apache.maven.model.Dependency d) {
98          return new MavenDependency(d.getGroupId(), d.getArtifactId(), d.getVersion());
99      }
100 
101     public static Artifact testResourcesDependencyToAetherArtifact(MavenDependency d) {
102         return new DefaultArtifact(d.getGroup(), d.getArtifact(), JAR_EXTENSION, d.getVersion());
103     }
104 
105     public static Artifact testResourcesModuleToAetherArtifact(String module, String testResourcesVersion) {
106         String coords = String.format(
107                 "%s:%s:%s",
108                 TEST_RESOURCES_GROUP,
109                 TEST_RESOURCES_ARTIFACT_ID_PREFIX + module,
110                 testResourcesVersion
111         );
112         return new DefaultArtifact(coords);
113     }
114 
115     /**
116      * Performs a dependency request to compute the transitive dependencies of the given artifacts.
117      */
118     public List<ArtifactResult> artifactResultsFor(Stream<Artifact> artifacts, boolean applyManagedDependencies) throws DependencyResolutionException {
119         RepositorySystemSession repositorySession = mavenSession.getRepositorySession();
120         DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
121         CollectRequest collectRequest = new CollectRequest();
122         collectRequest.setRepositories(mavenProject.getRemoteProjectRepositories());
123 
124         if (applyManagedDependencies) {
125             List<org.apache.maven.model.Dependency> dependencies = mavenProject.getDependencyManagement().getDependencies();
126             Map<String, Dependency> dependencyMap = new HashMap<>(dependencies.size());
127             for (org.apache.maven.model.Dependency dependency : dependencies) {
128                 String ga = dependency.getGroupId() + ":" + dependency.getArtifactId();
129                 dependencyMap.putIfAbsent(ga, DependencyResolutionService.mavenDependencyToAetherDependency(dependency));
130             }
131             collectRequest.setManagedDependencies(new ArrayList<>(dependencyMap.values()));
132 
133             artifacts.forEach(a -> {
134                 if (StringUtils.isEmpty(a.getVersion())) {
135                     dependencyMap.computeIfPresent(a.getGroupId() + ":" + a.getArtifactId(), (coord, d) -> {
136                         collectRequest.addDependency(new Dependency(new DefaultArtifact(a.getGroupId(), a.getArtifactId(), a.getExtension(), d.getArtifact().getVersion()), JavaScopes.RUNTIME));
137                         return d;
138                     });
139                 } else {
140                     collectRequest.addDependency(new Dependency(a, JavaScopes.RUNTIME));
141                 }
142             });
143         } else {
144             artifacts.map(a -> new Dependency(a, JavaScopes.RUNTIME)).forEach(collectRequest::addDependency);
145         }
146 
147         DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFilter);
148 
149         DependencyResult dependencyResult = repositorySystem.resolveDependencies(repositorySession, dependencyRequest);
150         return dependencyResult.getArtifactResults();
151     }
152 }