From a231b49f8fd81c9d8dfa9a7dacb137e9aca7365e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 3 May 2025 22:19:25 +0200 Subject: [PATCH] track classpath structure and content digests of all external deps GitOrigin-RevId: 1b412b4d2d5ec7742bc0508e97c5b0e08f3f1359 --- .../jetbrains/jps/bazel/BazelIncBuilder.java | 26 +++++++++++++------ .../jps/bazel/impl/PathSnapshotImpl.java | 3 ++- .../org/jetbrains/jps/bazel/impl/Utils.java | 8 +++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/bazel/BazelIncBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/bazel/BazelIncBuilder.java index 242d505072cd..7df4c6341e72 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/bazel/BazelIncBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/bazel/BazelIncBuilder.java @@ -54,6 +54,7 @@ public class BazelIncBuilder { public ExitCode build(BuildContext context) { // todo: support cancellation checks + // todo: additional diagnostics, if necessary GraphUpdater graphUpdater = new GraphUpdater(context.getTargetName()); DiagnosticSink diagnostic = context; @@ -69,8 +70,7 @@ public class BazelIncBuilder { else { ConfigurationState pastState = loadConfigurationState(context); snapshotDelta = new SourceSnapshotDeltaImpl(pastState.getSourceSnapshot(), context.getSources()); - if (!snapshotDelta.isRecompileAll() && !pastState.getDepsDigest().equals(presentState.getDepsDigest())) { - // todo: diagnostic? + if (!snapshotDelta.isRecompileAll() && !pastState.getClasspathStructureDigest().equals(presentState.getClasspathStructureDigest())) { snapshotDelta.markRecompileAll(); } } @@ -260,7 +260,7 @@ public class BazelIncBuilder { private static void saveConfigurationState(BuildContext context, ConfigurationState state) { Path snapshotPath = getSourceSnapshotStoreFile(context); try (var stream = new DataOutputStream(new DeflaterOutputStream(Files.newOutputStream(snapshotPath), new Deflater(Deflater.BEST_SPEED)))) { - stream.writeUTF(state.getDepsDigest()); + stream.writeUTF(state.getClasspathStructureDigest()); state.getSourceSnapshot().write(new GraphDataOutputImpl(stream)); } catch (Throwable e) { @@ -288,6 +288,10 @@ public class BazelIncBuilder { return context.getDataDir().resolve(DEP_GRAPH_FILE_NAME); } + private static boolean isAbiJar(Path path) { + return path.toString().endsWith("-abi.jar"); // todo: better criterion? + } + private static void safeClose(Closeable cl, DiagnosticSink diagnostic) { if (cl == null) { return; @@ -304,11 +308,12 @@ public class BazelIncBuilder { ConfigurationState EMPTY = create(SourceSnapshot.EMPTY, ""); SourceSnapshot getSourceSnapshot(); - - String getDepsDigest(); + + // tracks names and order of classpath entries as well as content digests of all third-party dependencies + String getClasspathStructureDigest(); default ConfigurationState derive(SourceSnapshot snapshot) { - return create(snapshot, getDepsDigest()); + return create(snapshot, getClasspathStructureDigest()); } static ConfigurationState create(SourceSnapshot snapshot, String depsDigest) { @@ -319,7 +324,7 @@ public class BazelIncBuilder { } @Override - public String getDepsDigest() { + public String getClasspathStructureDigest() { return depsDigest; } }; @@ -327,7 +332,12 @@ public class BazelIncBuilder { static ConfigurationState create(BuildContext context) { PathSnapshot deps = context.getBinaryDependencies(); - return create(context.getSources(), Utils.digest(map(deps.getElements(), deps::getDigest))); + + // digest name, count and order of classpath entries as well as content digests of all non-abi deps + Function<@NotNull Path, Iterable> digestMapper = + path -> isAbiJar(path)? List.of(path.toString()) : List.of(path.toString(), deps.getDigest(path)); + + return create(context.getSources(), Utils.digest(flat(map(deps.getElements(), digestMapper)))); } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/PathSnapshotImpl.java b/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/PathSnapshotImpl.java index 2fef21a667da..661e0de7cb3b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/PathSnapshotImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/PathSnapshotImpl.java @@ -5,13 +5,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.bazel.PathSnapshot; import java.nio.file.Path; +import java.util.Collections; import java.util.Map; public class PathSnapshotImpl implements PathSnapshot { private final Map myPaths; public PathSnapshotImpl(Map digestPaths) { - myPaths = Map.copyOf(digestPaths); + myPaths = Collections.unmodifiableMap(digestPaths); // keep all properties of the passed map, i.e. iteration order } @Override diff --git a/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/Utils.java b/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/Utils.java index 585ad72660b8..bf65e06d3ffd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/Utils.java +++ b/jps/jps-builders/src/org/jetbrains/jps/bazel/impl/Utils.java @@ -26,13 +26,13 @@ public class Utils { return Long.toHexString(stream.getAsLong()); } - public static String digest(File file) { - return digest(file.toPath(), null); + public static String timestampDigest(File file) { + return timestampDigest(file.toPath(), null); } - public static String digest(Path path, @Nullable BasicFileAttributes attrs) { + public static String timestampDigest(Path path, @Nullable BasicFileAttributes attrs) { try { - return Long.toHexString((attrs != null? attrs.lastModifiedTime().toMillis() : Files.getLastModifiedTime(path).toMillis())); // todo + return Long.toHexString((attrs != null? attrs.lastModifiedTime().toMillis() : Files.getLastModifiedTime(path).toMillis())); } catch (IOException ignored) { return "";