/* * Copyright 2015 Lukas Krejci * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package org.revapi.maven.utils; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import javax.annotation.Nullable; import org.eclipse.aether.RepositoryException; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.graph.DependencyVisitor; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.resolution.DependencyResolutionException; import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.resolution.VersionRangeRequest; import org.eclipse.aether.resolution.VersionRangeResolutionException; import org.eclipse.aether.resolution.VersionRangeResult; import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor; import org.eclipse.aether.version.Version; /** * @author Lukas Krejci * @since 0.3.0 */ public class ArtifactResolver { private final RepositorySystem repositorySystem; private final RepositorySystemSession session; private final List<RemoteRepository> repositories; public ArtifactResolver(RepositorySystem repositorySystem, RepositorySystemSession session, List<RemoteRepository> repositories) { this.repositorySystem = repositorySystem; this.session = session; this.repositories = repositories; } public Artifact resolveArtifact(String gav) throws ArtifactResolutionException { return resolveArtifact(new DefaultArtifact(gav)); } /** * Tries to find the newest version of the artifact that matches given regular expression. * The found version will be older than the {@code upToVersion} or newest available if {@code upToVersion} is null. * * @param gav the coordinates of the artifact. The version part is ignored * @param upToVersion the version up to which the versions will be matched * @param versionMatcher the matcher to match the version * @return * @throws VersionRangeResolutionException */ public Artifact resolveNewestMatching(String gav, @Nullable String upToVersion, Pattern versionMatcher) throws VersionRangeResolutionException, ArtifactResolutionException { Artifact artifact = new DefaultArtifact(gav); artifact = artifact.setVersion(upToVersion == null ? "[,)" : "[," + upToVersion + ")"); VersionRangeRequest rangeRequest = new VersionRangeRequest(artifact, repositories, null); VersionRangeResult result = repositorySystem.resolveVersionRange(session, rangeRequest); List<Version> versions = new ArrayList<>(result.getVersions()); Collections.reverse(versions); for(Version v : versions) { if (versionMatcher.matcher(v.toString()).matches()) { return resolveArtifact(artifact.setVersion(v.toString())); } } throw new VersionRangeResolutionException(result) { @Override public String getMessage() { return "Failed to find a version of artifact '" + gav + "' that would correspond to an expression '" + versionMatcher + "'. The versions found were: " + versions; } }; } public CollectionResult collectTransitiveDeps(String... gavs) throws RepositoryException { Set<Artifact> artifacts = new HashSet<>(); Set<Exception> failures = new HashSet<>(); for (String gav : gavs) { collectTransitiveDeps(gav, artifacts, failures); } return new CollectionResult(failures, artifacts); } protected void collectTransitiveDeps(String gav, Set<Artifact> resolvedArtifacts, Set<Exception> failures) throws RepositoryException { final Artifact rootArtifact = resolveArtifact(gav); CollectRequest collectRequest = new CollectRequest(new Dependency(rootArtifact, null), repositories); DependencyRequest request = new DependencyRequest(collectRequest, null); DependencyResult result; try { result = repositorySystem.resolveDependencies(session, request); } catch (DependencyResolutionException dre) { result = dre.getResult(); } result.getRoot().accept(new TreeDependencyVisitor(new DependencyVisitor() { @Override public boolean visitEnter(DependencyNode node) { return true; } @Override public boolean visitLeave(DependencyNode node) { Dependency dep = node.getDependency(); if (dep == null || dep.getArtifact().equals(rootArtifact)) { return true; } resolvedArtifacts.add(dep.getArtifact()); return true; } })); failures.addAll(result.getCollectExceptions()); } public static final class CollectionResult { private final Set<Artifact> resolvedArtifacts; private final Set<Exception> failures; private CollectionResult(Set<Exception> failures, Set<Artifact> resolvedArtifacts) { this.failures = failures; this.resolvedArtifacts = resolvedArtifacts; } public Set<Exception> getFailures() { return failures; } public Set<Artifact> getResolvedArtifacts() { return resolvedArtifacts; } } private Artifact resolveArtifact(Artifact artifact) throws ArtifactResolutionException { ArtifactRequest request = new ArtifactRequest().setArtifact(artifact) .setRepositories(repositories); ArtifactResult result = repositorySystem.resolveArtifact(session, request); return result.getArtifact(); } }