diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolutionResult.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolutionResult.java index 52bb45637..302b9f560 100644 --- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolutionResult.java +++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolutionResult.java @@ -16,7 +16,6 @@ import com.github.bazelbuild.rules_jvm_external.Coordinates; import com.google.common.graph.Graph; -import java.nio.file.Path; import java.util.Map; import java.util.Set; @@ -28,15 +27,15 @@ public class ResolutionResult { private final Graph resolution; private final Set conflicts; - private final Map paths; + private final Map artifacts; public ResolutionResult( Graph resolution, Set conflicts, - Map artifactPaths) { + Map artifacts) { this.resolution = resolution; this.conflicts = Set.copyOf(conflicts); - this.paths = artifactPaths != null ? Map.copyOf(artifactPaths) : Map.of(); + this.artifacts = artifacts != null ? Map.copyOf(artifacts) : Map.of(); } public Graph getResolution() { @@ -47,7 +46,7 @@ public Set getConflicts() { return conflicts; } - public Map getPaths() { - return paths; + public Map getArtifacts() { + return artifacts; } } diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolvedArtifact.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolvedArtifact.java new file mode 100644 index 000000000..5ad3e428d --- /dev/null +++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/ResolvedArtifact.java @@ -0,0 +1,66 @@ +// Copyright 2026 The Bazel Authors. All rights reserved. +// +// 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 com.github.bazelbuild.rules_jvm_external.resolver; + +import com.github.bazelbuild.rules_jvm_external.Coordinates; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * A node in a {@link ResolutionResult}: a coordinate that was resolved, together with the local + * path to its artifact if one is known. The path is absent when the resolver has not (yet) fetched + * a file for the coordinate. + */ +public final class ResolvedArtifact { + + private final Coordinates coordinates; + private final Optional path; + + public ResolvedArtifact(Coordinates coordinates, Path path) { + this.coordinates = Objects.requireNonNull(coordinates); + this.path = Optional.ofNullable(path); + } + + public Coordinates getCoordinates() { + return coordinates; + } + + public Optional getPath() { + return path; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ResolvedArtifact)) { + return false; + } + ResolvedArtifact that = (ResolvedArtifact) o; + return coordinates.equals(that.coordinates) && path.equals(that.path); + } + + @Override + public int hashCode() { + return Objects.hash(coordinates, path); + } + + @Override + public String toString() { + return "ResolvedArtifact{" + coordinates + ", path=" + path.orElse(null) + "}"; + } +} diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java index d33cacd7b..d7898538e 100644 --- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java +++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/cmd/AbstractMain.java @@ -99,6 +99,12 @@ private static Set fulfillDependencyInfos( cacheResults = "1".equals(rjeUnsafeCache) || Boolean.parseBoolean(rjeUnsafeCache); } + Map knownPaths = new LinkedHashMap<>(); + resolutionResult + .getArtifacts() + .forEach( + (coords, artifact) -> artifact.getPath().ifPresent(p -> knownPaths.put(coords, p))); + Downloader downloader = new Downloader( config.getNetrc(), @@ -106,7 +112,7 @@ private static Set fulfillDependencyInfos( request.getRepositories(), listener, cacheResults, - resolutionResult.getPaths()); + knownPaths); List>> futures = new LinkedList<>(); diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java index eb9578b03..79e9414e3 100644 --- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java +++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java @@ -19,6 +19,7 @@ import com.github.bazelbuild.rules_jvm_external.resolver.Conflict; import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionRequest; import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionResult; +import com.github.bazelbuild.rules_jvm_external.resolver.ResolvedArtifact; import com.github.bazelbuild.rules_jvm_external.resolver.Resolver; import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener; import com.github.bazelbuild.rules_jvm_external.resolver.events.LogEvent; @@ -324,7 +325,12 @@ private ResolutionResult parseDependencies( // Only include paths for coordinates that are actually in the final resolved graph paths.keySet().retainAll(graph.nodes()); - return new ResolutionResult(graph, conflicts, paths); + Map artifacts = new HashMap<>(); + for (Coordinates node : graph.nodes()) { + artifacts.put(node, new ResolvedArtifact(node, paths.get(node))); + } + + return new ResolutionResult(graph, conflicts, artifacts); } private String makeDepKey(String group, String artifact, String version) { diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenResolver.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenResolver.java index 82bfe74fe..d5c660451 100644 --- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenResolver.java +++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/maven/MavenResolver.java @@ -18,6 +18,7 @@ import com.github.bazelbuild.rules_jvm_external.resolver.Conflict; import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionRequest; import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionResult; +import com.github.bazelbuild.rules_jvm_external.resolver.ResolvedArtifact; import com.github.bazelbuild.rules_jvm_external.resolver.Resolver; import com.github.bazelbuild.rules_jvm_external.resolver.events.EventListener; import com.github.bazelbuild.rules_jvm_external.resolver.events.LogEvent; @@ -274,7 +275,13 @@ public ResolutionResult resolve(ResolutionRequest request) { getConflicts(request.getDependencies(), resolvedDependencies), graphNormalizationResult.getConflicts()); - return new ResolutionResult(graphNormalizationResult.getNormalizedGraph(), conflicts, Map.of()); + Graph normalizedGraph = graphNormalizationResult.getNormalizedGraph(); + Map artifacts = new HashMap<>(); + for (Coordinates node : normalizedGraph.nodes()) { + artifacts.put(node, new ResolvedArtifact(node, null)); + } + + return new ResolutionResult(normalizedGraph, conflicts, artifacts); } private GraphNormalizationResult makeVersionsConsistent(Graph dependencyGraph) { diff --git a/private/tools/prebuilt/lock_file_converter_deploy.jar b/private/tools/prebuilt/lock_file_converter_deploy.jar index 666b6004e..0697a457e 100755 Binary files a/private/tools/prebuilt/lock_file_converter_deploy.jar and b/private/tools/prebuilt/lock_file_converter_deploy.jar differ diff --git a/tests/com/github/bazelbuild/rules_jvm_external/resolver/ResolverTestBase.java b/tests/com/github/bazelbuild/rules_jvm_external/resolver/ResolverTestBase.java index db55e004e..52498d2f6 100644 --- a/tests/com/github/bazelbuild/rules_jvm_external/resolver/ResolverTestBase.java +++ b/tests/com/github/bazelbuild/rules_jvm_external/resolver/ResolverTestBase.java @@ -877,9 +877,10 @@ public void shouldRespectForceVersionWhenResolvingConflicts() throws IOException // Validate that the downloaded artifact has the correct SHA for the forced version. // This catches bugs where the resolver fetches artifacts via detached configurations // that bypass force_version, resulting in the wrong file being downloaded. - Map paths = result.getPaths(); - if (paths.containsKey(lowerVersion)) { - Path downloadedArtifact = paths.get(lowerVersion); + Map artifacts = result.getArtifacts(); + ResolvedArtifact lower = artifacts.get(lowerVersion); + if (lower != null && lower.getPath().isPresent()) { + Path downloadedArtifact = lower.getPath().get(); Path expectedArtifact = repo.resolve(lowerVersion.toRepoPath()); // Compare SHA256 of downloaded file vs expected file in repo diff --git a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java index b249b185e..a5cef5709 100644 --- a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java +++ b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java @@ -22,6 +22,7 @@ import com.github.bazelbuild.rules_jvm_external.Coordinates; import com.github.bazelbuild.rules_jvm_external.resolver.MavenRepo; import com.github.bazelbuild.rules_jvm_external.resolver.ResolutionResult; +import com.github.bazelbuild.rules_jvm_external.resolver.ResolvedArtifact; import com.github.bazelbuild.rules_jvm_external.resolver.Resolver; import com.github.bazelbuild.rules_jvm_external.resolver.ResolverTestBase; import com.github.bazelbuild.rules_jvm_external.resolver.cmd.ResolverConfig; @@ -284,10 +285,11 @@ public void shouldRecordCorrectShaForResolvedVersionNotConflictingVersion() { assertEquals("Should resolve to exactly one version", 1, conflictedNodes.size()); assertTrue("Should resolve to higher version", conflictedNodes.contains(higherVersion)); - // Verify paths map contains only the resolved (higher) version, not the lower version - Map paths = result.getPaths(); - assertTrue("Paths should contain resolved version", paths.containsKey(higherVersion)); + // Verify the resolved artifacts contain only the resolved (higher) version, not the lower one + Map artifacts = result.getArtifacts(); + assertTrue("Artifacts should contain resolved version", artifacts.containsKey(higherVersion)); assertFalse( - "Paths should not contain conflicting lower version", paths.containsKey(lowerVersion)); + "Artifacts should not contain conflicting lower version", + artifacts.containsKey(lowerVersion)); } }