[MNG-7966] Augment api to provide a Map<Dependency, Path> in the resolution result (#1343)

This commit is contained in:
Guillaume Nodet 2023-12-15 07:34:19 +01:00 committed by GitHub
parent d9a49e6ff7
commit 2cccc0a476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 174 additions and 99 deletions

View File

@ -20,7 +20,9 @@
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import org.apache.maven.api.Dependency;
import org.apache.maven.api.Node;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
@ -32,8 +34,11 @@ public interface DependencyResolverResult extends DependencyCollectorResult {
* The ordered list of the flattened dependency nodes.
*/
@Nonnull
List<Node> getDependencies();
List<Node> getNodes();
@Nonnull
List<Path> getPaths();
@Nonnull
Map<Dependency, Path> getDependencies();
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.maven.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@ -30,7 +29,6 @@
import org.apache.maven.api.services.ArtifactDeployer;
import org.apache.maven.api.services.ArtifactDeployerException;
import org.apache.maven.api.services.ArtifactDeployerRequest;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.deployment.DeployRequest;
import org.eclipse.aether.deployment.DeployResult;
import org.eclipse.aether.deployment.DeploymentException;
@ -43,12 +41,6 @@
@Named
@Singleton
public class DefaultArtifactDeployer implements ArtifactDeployer {
private final @Nonnull RepositorySystem repositorySystem;
@Inject
DefaultArtifactDeployer(@Nonnull RepositorySystem repositorySystem) {
this.repositorySystem = nonNull(repositorySystem, "repositorySystem");
}
@Override
public void deploy(@Nonnull ArtifactDeployerRequest request) {
@ -61,7 +53,7 @@ public void deploy(@Nonnull ArtifactDeployerRequest request) {
.setRepository(session.toRepository(repository))
.setArtifacts(session.toArtifacts(artifacts));
DeployResult result = repositorySystem.deploy(session.getSession(), deployRequest);
DeployResult result = session.getRepositorySystem().deploy(session.getSession(), deployRequest);
} catch (DeploymentException e) {
throw new ArtifactDeployerException("Unable to deploy artifacts", e);
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.maven.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@ -30,13 +29,11 @@
import org.apache.maven.api.Artifact;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.services.ArtifactManager;
import org.apache.maven.api.services.ArtifactResolver;
import org.apache.maven.api.services.ArtifactResolverException;
import org.apache.maven.api.services.ArtifactResolverRequest;
import org.apache.maven.api.services.ArtifactResolverResult;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
@ -47,12 +44,6 @@
@Named
@Singleton
public class DefaultArtifactResolver implements ArtifactResolver {
private final RepositorySystem repositorySystem;
@Inject
DefaultArtifactResolver(@Nonnull RepositorySystem repositorySystem) {
this.repositorySystem = nonNull(repositorySystem, "repositorySystem");
}
@Override
public ArtifactResolverResult resolve(ArtifactResolverRequest request)
@ -75,7 +66,8 @@ public ArtifactResolverResult resolve(ArtifactResolverRequest request)
}
}
if (!requests.isEmpty()) {
List<ArtifactResult> results = repositorySystem.resolveArtifacts(session.getSession(), requests);
List<ArtifactResult> results =
session.getRepositorySystem().resolveArtifacts(session.getSession(), requests);
for (ArtifactResult result : results) {
Artifact artifact = session.getArtifact(result.getArtifact());
Path path = result.getArtifact().getFile().toPath();

View File

@ -18,7 +18,6 @@
*/
package org.apache.maven.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@ -31,7 +30,6 @@
import org.apache.maven.api.services.DependencyCollectorRequest;
import org.apache.maven.api.services.DependencyCollectorResult;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.collection.CollectRequest;
@ -47,13 +45,6 @@
@Singleton
public class DefaultDependencyCollector implements DependencyCollector {
private final RepositorySystem repositorySystem;
@Inject
DefaultDependencyCollector(@Nonnull RepositorySystem repositorySystem) {
this.repositorySystem = repositorySystem;
}
@Nonnull
@Override
public DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest request)
@ -79,7 +70,8 @@ public DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest req
}
try {
final CollectResult result = repositorySystem.collectDependencies(systemSession, collectRequest);
final CollectResult result =
session.getRepositorySystem().collectDependencies(systemSession, collectRequest);
return new DependencyCollectorResult() {
@Override
public List<Exception> getExceptions() {

View File

@ -18,7 +18,6 @@
*/
package org.apache.maven.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@ -26,15 +25,17 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.api.Artifact;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.Dependency;
import org.apache.maven.api.Node;
import org.apache.maven.api.Project;
import org.apache.maven.api.ResolutionScope;
@ -43,8 +44,8 @@
import org.apache.maven.api.services.*;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
import org.apache.maven.project.DependencyResolutionResult;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.graph.DependencyVisitor;
@ -59,9 +60,6 @@
@Singleton
public class DefaultDependencyResolver implements DependencyResolver {
@Inject
public DefaultDependencyResolver() {}
@Override
public List<Node> flatten(Session s, Node node, ResolutionScope scope) throws DependencyResolverException {
InternalSession session = InternalSession.from(s);
@ -81,7 +79,7 @@ public List<Node> flatten(Session s, Node node, ResolutionScope scope) throws De
private static DependencyFilter getScopeDependencyFilter(ResolutionScope scope) {
Set<String> scopes = scope.scopes().stream().map(Scope::id).collect(Collectors.toSet());
return (n, p) -> {
Dependency d = n.getDependency();
org.eclipse.aether.graph.Dependency d = n.getDependency();
return d == null || scopes.contains(d.getScope());
};
}
@ -93,51 +91,59 @@ public DependencyResolverResult resolve(DependencyResolverRequest request)
InternalSession session = InternalSession.from(request.getSession());
if (request.getProject().isPresent()) {
List<Artifact> artifacts = resolveDependencies(
DependencyResolutionResult result = resolveDependencies(
request.getSession(), request.getProject().get(), request.getResolutionScope());
List<Path> paths = artifacts.stream()
.map(a -> request.getSession()
.getService(ArtifactManager.class)
.getPath(a)
.get())
.collect(Collectors.toList());
return new DefaultDependencyResolverResult(Collections.emptyList(), null, Collections.emptyList(), paths);
Map<org.eclipse.aether.graph.Dependency, org.eclipse.aether.graph.DependencyNode> nodes = stream(
result.getDependencyGraph())
.filter(n -> n.getDependency() != null)
.collect(Collectors.toMap(DependencyNode::getDependency, n -> n));
Node root = session.getNode(result.getDependencyGraph());
List<Node> dependencies = new ArrayList<>();
Map<Dependency, Path> artifacts = new LinkedHashMap<>();
List<Path> paths = new ArrayList<>();
for (org.eclipse.aether.graph.Dependency dep : result.getResolvedDependencies()) {
dependencies.add(session.getNode(nodes.get(dep)));
Path path = dep.getArtifact().getFile().toPath();
artifacts.put(session.getDependency(dep), path);
paths.add(path);
}
return new DefaultDependencyResolverResult(
result.getCollectionErrors(), root, dependencies, paths, artifacts);
}
DependencyCollectorResult collectorResult =
session.getService(DependencyCollector.class).collect(request);
List<Node> dependencies = flatten(session, collectorResult.getRoot(), request.getResolutionScope());
List<ArtifactCoordinate> coordinates = dependencies.stream()
.map(Node::getDependency)
.filter(Objects::nonNull)
.map(Artifact::toCoordinate)
.collect(Collectors.toList());
List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope());
List<Dependency> deps =
nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList());
List<ArtifactCoordinate> coordinates =
deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList());
Map<Artifact, Path> artifacts = session.resolveArtifacts(coordinates);
List<Path> paths = dependencies.stream()
.map(Node::getDependency)
.filter(Objects::nonNull)
.map(artifacts::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Dependency, Path> dependencies = deps.stream().collect(Collectors.toMap(d -> d, artifacts::get));
List<Path> paths = new ArrayList<>(dependencies.values());
return new DefaultDependencyResolverResult(
collectorResult.getExceptions(), collectorResult.getRoot(), dependencies, paths);
collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies);
}
private List<Artifact> resolveDependencies(Session session, Project project, ResolutionScope scope) {
private Stream<DependencyNode> stream(DependencyNode node) {
return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream));
}
private DependencyResolutionResult resolveDependencies(Session session, Project project, ResolutionScope scope) {
Collection<String> toResolve = toScopes(scope);
try {
LifecycleDependencyResolver lifecycleDependencyResolver =
session.getService(Lookup.class).lookup(LifecycleDependencyResolver.class);
Set<org.apache.maven.artifact.Artifact> artifacts = lifecycleDependencyResolver.resolveProjectArtifacts(
return lifecycleDependencyResolver.getProjectDependencyResolutionResult(
getMavenProject(project),
toResolve,
toResolve,
InternalSession.from(session).getMavenSession(),
false,
Collections.emptySet());
return map(artifacts, a -> InternalSession.from(session).getArtifact(RepositoryUtils.toArtifact(a)));
} catch (LifecycleExecutionException e) {
throw new DependencyResolverException("Unable to resolve project dependencies", e);
}
@ -154,15 +160,21 @@ private Collection<String> toScopes(ResolutionScope scope) {
static class DefaultDependencyResolverResult implements DependencyResolverResult {
private final List<Exception> exceptions;
private final Node root;
private final List<Node> dependencies;
private final List<Node> nodes;
private final List<Path> paths;
private final Map<Dependency, Path> dependencies;
DefaultDependencyResolverResult(
List<Exception> exceptions, Node root, List<Node> dependencies, List<Path> paths) {
List<Exception> exceptions,
Node root,
List<Node> nodes,
List<Path> paths,
Map<Dependency, Path> dependencies) {
this.exceptions = exceptions;
this.root = root;
this.dependencies = dependencies;
this.nodes = nodes;
this.paths = paths;
this.dependencies = dependencies;
}
@Override
@ -176,13 +188,18 @@ public Node getRoot() {
}
@Override
public List<Node> getDependencies() {
return dependencies;
public List<Node> getNodes() {
return nodes;
}
@Override
public List<Path> getPaths() {
return paths;
}
@Override
public Map<Dependency, Path> getDependencies() {
return dependencies;
}
}
}

View File

@ -169,6 +169,24 @@ public void resolveProjectDependencies(
}
}
public DependencyResolutionResult getProjectDependencyResolutionResult(
MavenProject project,
Collection<String> scopesToCollect,
Collection<String> scopesToResolve,
MavenSession session,
boolean aggregating,
Set<Artifact> projectArtifacts)
throws LifecycleExecutionException {
Set<Artifact> resolvedArtifacts = resolveProjectArtifacts(
project, scopesToCollect, scopesToResolve, session, aggregating, projectArtifacts);
if (resolvedArtifacts instanceof ProjectArtifactsCache.ArtifactsSetWithResult) {
return ((ProjectArtifactsCache.ArtifactsSetWithResult) resolvedArtifacts).getResult();
} else {
throw new IllegalStateException();
}
}
public Set<Artifact> resolveProjectArtifacts(
MavenProject project,
Collection<String> scopesToCollect,
@ -216,7 +234,7 @@ private Set<Artifact> getDependencies(
}
if (scopesToCollect.isEmpty() && scopesToResolve.isEmpty()) {
return new LinkedHashSet<>();
return new SetWithResolutionResult(null, new LinkedHashSet<>());
}
scopesToCollect = new HashSet<>(scopesToCollect);
@ -270,7 +288,7 @@ private Set<Artifact> getDependencies(
Collections.singletonList(project.getArtifact().getId()),
collectionFilter);
}
return artifacts;
return new SetWithResolutionResult(result, artifacts);
}
private boolean areAllDependenciesInReactor(

View File

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.maven.lifecycle.internal;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.DependencyResolutionResult;
import org.apache.maven.project.artifact.ProjectArtifactsCache;
public class SetWithResolutionResult extends AbstractSet<Artifact>
implements ProjectArtifactsCache.ArtifactsSetWithResult {
final DependencyResolutionResult result;
final Set<Artifact> artifacts;
public SetWithResolutionResult(DependencyResolutionResult result, Set<Artifact> artifacts) {
this.result = result;
this.artifacts = Collections.unmodifiableSet(artifacts);
}
@Override
public Iterator<Artifact> iterator() {
return artifacts.iterator();
}
@Override
public int size() {
return artifacts.size();
}
@Override
public DependencyResolutionResult getResult() {
return result;
}
}

View File

@ -35,6 +35,7 @@
import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.internal.SetWithResolutionResult;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.LocalRepository;
@ -140,13 +141,10 @@ public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof CacheKey)) {
return false;
}
CacheKey that = (CacheKey) o;
return Objects.equals(groupId, that.groupId)
&& Objects.equals(artifactId, that.artifactId)
&& Objects.equals(version, that.version)
@ -181,24 +179,38 @@ public Key createKey(
@Override
public CacheRecord get(Key key) throws LifecycleExecutionException {
CacheRecord cacheRecord = cache.get(key);
if (cacheRecord != null && cacheRecord.getException() != null) {
throw cacheRecord.getException();
}
return cacheRecord;
}
@Override
public CacheRecord put(Key key, Set<Artifact> projectArtifacts) {
Objects.requireNonNull(projectArtifacts, "projectArtifacts cannot be null");
assertUniqueKey(key);
CacheRecord record = new CacheRecord(Collections.unmodifiableSet(new LinkedHashSet<>(projectArtifacts)));
SetWithResolutionResult artifacts;
if (projectArtifacts instanceof SetWithResolutionResult) {
artifacts = (SetWithResolutionResult) projectArtifacts;
} else if (projectArtifacts instanceof ArtifactsSetWithResult) {
artifacts = new SetWithResolutionResult(
((ArtifactsSetWithResult) projectArtifacts).getResult(), projectArtifacts);
} else {
throw new IllegalArgumentException("projectArtifacts must implement ArtifactsSetWithResult");
}
CacheRecord record = new CacheRecord(artifacts);
cache.put(key, record);
return record;
}
@Override
public CacheRecord put(Key key, LifecycleExecutionException exception) {
Objects.requireNonNull(exception, "exception cannot be null");
assertUniqueKey(key);
CacheRecord record = new CacheRecord(exception);
cache.put(key, record);
return record;
}
@ -208,19 +220,6 @@ protected void assertUniqueKey(Key key) {
}
}
@Override
public CacheRecord put(Key key, LifecycleExecutionException exception) {
Objects.requireNonNull(exception, "exception cannot be null");
assertUniqueKey(key);
CacheRecord record = new CacheRecord(exception);
cache.put(key, record);
return record;
}
@Override
public void flush() {
cache.clear();

View File

@ -23,6 +23,7 @@
import org.apache.maven.artifact.Artifact;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.project.DependencyResolutionResult;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystemSession;
@ -41,21 +42,17 @@ interface Key {
// marker interface for cache keys
}
interface ArtifactsSetWithResult extends Set<Artifact> {
DependencyResolutionResult getResult();
}
/**
* CacheRecord
*/
class CacheRecord {
public Set<Artifact> getArtifacts() {
return artifacts;
}
private final Set<Artifact> artifacts;
public LifecycleExecutionException getException() {
return exception;
}
private final LifecycleExecutionException exception;
CacheRecord(Set<Artifact> artifacts) {
@ -67,6 +64,14 @@ public LifecycleExecutionException getException() {
this.artifacts = null;
this.exception = exception;
}
public Set<Artifact> getArtifacts() {
return artifacts;
}
public LifecycleExecutionException getException() {
return exception;
}
}
Key createKey(

View File

@ -23,6 +23,7 @@
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.lifecycle.internal.SetWithResolutionResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -47,7 +48,7 @@ void testProjectDependencyOrder() throws Exception {
artifacts.add(new DefaultArtifact("g", "a3", "v", "compile", "jar", "", null));
artifacts.add(new DefaultArtifact("g", "a4", "v", "compile", "jar", "", null));
cache.put(project1, artifacts);
cache.put(project1, new SetWithResolutionResult(null, artifacts));
assertArrayEquals(
artifacts.toArray(new Artifact[0]),
@ -61,7 +62,7 @@ void testProjectDependencyOrder() throws Exception {
artifacts.add(new DefaultArtifact("g", "a2", "v", "compile", "jar", "", null));
artifacts.add(new DefaultArtifact("g", "a1", "v", "compile", "jar", "", null));
cache.put(project2, reversedArtifacts);
cache.put(project2, new SetWithResolutionResult(null, reversedArtifacts));
assertArrayEquals(
reversedArtifacts.toArray(new Artifact[0]),