001/* 002 * Copyright 2017-2022 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven.services; 017 018import io.micronaut.core.util.StringUtils; 019import io.micronaut.testresources.buildtools.MavenDependency; 020import org.apache.maven.execution.MavenSession; 021import org.apache.maven.project.MavenProject; 022import org.eclipse.aether.RepositorySystem; 023import org.eclipse.aether.RepositorySystemSession; 024import org.eclipse.aether.artifact.Artifact; 025import org.eclipse.aether.artifact.DefaultArtifact; 026import org.eclipse.aether.collection.CollectRequest; 027import org.eclipse.aether.graph.Dependency; 028import org.eclipse.aether.graph.DependencyFilter; 029import org.eclipse.aether.resolution.ArtifactResult; 030import org.eclipse.aether.resolution.DependencyRequest; 031import org.eclipse.aether.resolution.DependencyResolutionException; 032import org.eclipse.aether.resolution.DependencyResult; 033import org.eclipse.aether.util.artifact.JavaScopes; 034import org.eclipse.aether.util.filter.DependencyFilterUtils; 035 036import javax.inject.Inject; 037import javax.inject.Singleton; 038import java.io.File; 039import java.util.ArrayList; 040import java.util.HashMap; 041import java.util.List; 042import java.util.stream.Stream; 043 044/** 045 * Utility methods for performing dependency resolution. 046 */ 047@Singleton 048public class DependencyResolutionService { 049 050 public static final String TEST_RESOURCES_GROUP = "io.micronaut.testresources"; 051 public static final String TEST_RESOURCES_ARTIFACT_ID_PREFIX = "micronaut-test-resources-"; 052 053 private static final String JAR_EXTENSION = "jar"; 054 055 private final MavenSession mavenSession; 056 057 private final MavenProject mavenProject; 058 059 private final RepositorySystem repositorySystem; 060 061 @Inject 062 public DependencyResolutionService(MavenSession mavenSession, MavenProject mavenProject, RepositorySystem repositorySystem) { 063 this.mavenSession = mavenSession; 064 this.mavenProject = mavenProject; 065 this.repositorySystem = repositorySystem; 066 } 067 068 private static Stream<File> streamClasspath(List<ArtifactResult> resolutionResult) { 069 return resolutionResult 070 .stream() 071 .map(ArtifactResult::getArtifact) 072 .map(Artifact::getFile); 073 } 074 075 public static List<String> toClasspath(List<ArtifactResult> resolutionResult) { 076 return streamClasspath(resolutionResult) 077 .map(File::getAbsolutePath) 078 .toList(); 079 } 080 081 public static List<File> toClasspathFiles(List<ArtifactResult> resolutionResult) { 082 return streamClasspath(resolutionResult) 083 .toList(); 084 } 085 086 public static Dependency mavenDependencyToAetherDependency(org.apache.maven.model.Dependency d) { 087 Artifact artifact = mavenDependencyToAetherArtifact(d); 088 return new Dependency(artifact, d.getScope(), Boolean.valueOf(d.getOptional())); 089 } 090 091 public static Artifact mavenDependencyToAetherArtifact(org.apache.maven.model.Dependency d) { 092 return new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getClassifier(), d.getType(), d.getVersion()); 093 } 094 095 public static MavenDependency mavenDependencyToTestResourcesDependency(org.apache.maven.model.Dependency d) { 096 return new MavenDependency(d.getGroupId(), d.getArtifactId(), d.getVersion()); 097 } 098 099 public static Artifact testResourcesDependencyToAetherArtifact(MavenDependency d) { 100 return new DefaultArtifact(d.getGroup(), d.getArtifact(), JAR_EXTENSION, d.getVersion()); 101 } 102 103 /** 104 * Performs a dependency request to compute the transitive dependencies of the given artifacts. 105 * 106 * @param artifacts The artifacts to resolve 107 * @param applyManagedDependencies Whether to apply the managed dependencies of the project 108 * @return The resolution result 109 */ 110 public List<ArtifactResult> artifactResultsFor(Stream<Artifact> artifacts, boolean applyManagedDependencies) throws DependencyResolutionException { 111 RepositorySystemSession repositorySession = mavenSession.getRepositorySession(); 112 DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME); 113 var collectRequest = new CollectRequest(); 114 collectRequest.setRepositories(mavenProject.getRemoteProjectRepositories()); 115 116 if (applyManagedDependencies) { 117 List<org.apache.maven.model.Dependency> dependencies = mavenProject.getDependencyManagement().getDependencies(); 118 var dependencyMap = new HashMap<String, Dependency>(dependencies.size()); 119 for (org.apache.maven.model.Dependency dependency : dependencies) { 120 String ga = dependency.getGroupId() + ":" + dependency.getArtifactId(); 121 dependencyMap.putIfAbsent(ga, DependencyResolutionService.mavenDependencyToAetherDependency(dependency)); 122 } 123 collectRequest.setManagedDependencies(new ArrayList<>(dependencyMap.values())); 124 125 artifacts.forEach(a -> { 126 if (StringUtils.isEmpty(a.getVersion())) { 127 dependencyMap.computeIfPresent(a.getGroupId() + ":" + a.getArtifactId(), (coord, d) -> { 128 collectRequest.addDependency(new Dependency(new DefaultArtifact(a.getGroupId(), a.getArtifactId(), a.getExtension(), d.getArtifact().getVersion()), JavaScopes.RUNTIME)); 129 return d; 130 }); 131 } else { 132 collectRequest.addDependency(new Dependency(a, JavaScopes.RUNTIME)); 133 } 134 }); 135 } else { 136 artifacts.map(a -> new Dependency(a, JavaScopes.RUNTIME)).forEach(collectRequest::addDependency); 137 } 138 139 var dependencyRequest = new DependencyRequest(collectRequest, classpathFilter); 140 141 DependencyResult dependencyResult = repositorySystem.resolveDependencies(repositorySession, dependencyRequest); 142 return dependencyResult.getArtifactResults(); 143 } 144}