From 15b1575cff9ad6e7f22d49cf7df2c7f2a3015f53 Mon Sep 17 00:00:00 2001 From: salma-samy Date: Mon, 7 Aug 2023 03:42:28 -0700 Subject: [PATCH] Use lockfile version to update or error If version is old, update without parsing, or error with requesting user to update PiperOrigin-RevId: 554426312 Change-Id: Ib59b2009595feaf7c9a9e207929df6e794af0b77 --- .../bazel/bzlmod/BazelDepGraphFunction.java | 3 +- .../bazel/bzlmod/BazelLockFileFunction.java | 27 +++++++++++---- .../lib/bazel/bzlmod/BazelLockFileValue.java | 7 ++++ .../bzlmod/BazelLockFileFunctionTest.java | 4 ++- .../py/bazel/bzlmod/bazel_lockfile_test.py | 34 +++++++++++++++++++ 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java index 9e7c0a328e8356..e4341b39fc9db0 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java @@ -129,6 +129,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) if (!lockfileMode.equals(LockfileMode.OFF)) { BazelLockFileValue updateLockfile = lockfile.toBuilder() + .setLockFileVersion(BazelLockFileValue.LOCK_FILE_VERSION) .setModuleFileHash(root.getModuleFileHash()) .setFlags(flags) .setLocalOverrideHashes(localOverrideHashes) @@ -183,7 +184,7 @@ static BzlmodFlagsAndEnvVars getFlagsAndEnvVars(Environment env) throws Interrup ImmutableMap moduleOverrides = ModuleFileFunction.MODULE_OVERRIDES.get(env).entrySet().stream() .collect( - toImmutableMap(e -> e.getKey(), e -> ((LocalPathOverride) e.getValue()).getPath())); + toImmutableMap(Entry::getKey, e -> ((LocalPathOverride) e.getValue()).getPath())); ImmutableList yankedVersions = ImmutableList.copyOf(YankedVersionsUtil.ALLOWED_YANKED_VERSIONS.get(env)); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunction.java index 1451f431cf916f..0a1fa24f017e69 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunction.java @@ -36,6 +36,8 @@ import com.google.gson.JsonSyntaxException; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.Nullable; /** Reads the contents of the lock file into its value. */ @@ -43,6 +45,9 @@ public class BazelLockFileFunction implements SkyFunction { public static final Precomputed LOCKFILE_MODE = new Precomputed<>("lockfile_mode"); + private static final Pattern LOCKFILE_VERSION_PATTERN = + Pattern.compile("\"lockFileVersion\":\\s*(\\d+)"); + private final Path rootDirectory; private static final BzlmodFlagsAndEnvVars EMPTY_FLAGS = @@ -92,13 +97,21 @@ public static BazelLockFileValue getLockfileValue(RootedPath lockfilePath) throw BazelLockFileValue bazelLockFileValue; try { String json = FileSystemUtils.readContent(lockfilePath.asPath(), UTF_8); - bazelLockFileValue = - GsonTypeAdapterUtil.createLockFileGson( - lockfilePath - .asPath() - .getParentDirectory() - .getRelative(LabelConstants.MODULE_DOT_BAZEL_FILE_NAME)) - .fromJson(json, BazelLockFileValue.class); + Matcher matcher = LOCKFILE_VERSION_PATTERN.matcher(json); + int version = matcher.find() ? Integer.parseInt(matcher.group(1)) : -1; + if (version == BazelLockFileValue.LOCK_FILE_VERSION) { + bazelLockFileValue = + GsonTypeAdapterUtil.createLockFileGson( + lockfilePath + .asPath() + .getParentDirectory() + .getRelative(LabelConstants.MODULE_DOT_BAZEL_FILE_NAME)) + .fromJson(json, BazelLockFileValue.class); + } else { + // This is an old version, needs to be updated + // Keep old version to recognize the problem in error mode + bazelLockFileValue = EMPTY_LOCKFILE.toBuilder().setLockFileVersion(version).build(); + } } catch (FileNotFoundException e) { bazelLockFileValue = EMPTY_LOCKFILE; } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java index 26c674fb6bc14f..fc49eaeafde2ea 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileValue.java @@ -92,6 +92,13 @@ public ImmutableList getModuleAndFlagsDiff( ImmutableMap localOverrideHashes, BzlmodFlagsAndEnvVars flags) { ImmutableList.Builder moduleDiff = new ImmutableList.Builder<>(); + if (getLockFileVersion() != BazelLockFileValue.LOCK_FILE_VERSION) { + return moduleDiff + .add( + "the version of the lockfile is not compatible with the current Bazel, please run" + + " with '--lockfile_mode=update'") + .build(); + } if (!moduleFileHash.equals(getModuleFileHash())) { moduleDiff.add("the root MODULE.bazel has been modified"); } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java index 6b04611fdae7d6..8405572d4d08c8 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java @@ -429,7 +429,9 @@ public void invalidLockfileEmptyFile() throws Exception { fail(result.getError().toString()); } - scratch.overwriteFile(rootDirectory.getRelative("MODULE.bazel.lock").getPathString(), "{}"); + scratch.overwriteFile( + rootDirectory.getRelative("MODULE.bazel.lock").getPathString(), + "{\"lockFileVersion\": " + BazelLockFileValue.LOCK_FILE_VERSION + "}"); result = evaluator.evaluate(ImmutableList.of(BazelLockFileValue.KEY), evaluationContext); if (!result.hasError()) { diff --git a/src/test/py/bazel/bzlmod/bazel_lockfile_test.py b/src/test/py/bazel/bzlmod/bazel_lockfile_test.py index c32311812fb4cc..b88881661a0c8d 100644 --- a/src/test/py/bazel/bzlmod/bazel_lockfile_test.py +++ b/src/test/py/bazel/bzlmod/bazel_lockfile_test.py @@ -805,6 +805,40 @@ def testModuleExtensionWithFile(self): _, _, stderr = self.RunBazel(['build', '@hello//:all']) self.assertIn('I have changed now!', ''.join(stderr)) + def testOldVersion(self): + self.ScratchFile('MODULE.bazel') + self.ScratchFile('BUILD', ['filegroup(name = "hello")']) + self.RunBazel(['build', '--nobuild', '//:all']) + + # Set version to old + with open('MODULE.bazel.lock', 'r') as json_file: + data = json.load(json_file) + data['lockFileVersion'] = 0 + with open('MODULE.bazel.lock', 'w') as json_file: + json.dump(data, json_file, indent=4) + + # Run in error mode + exit_code, _, stderr = self.RunBazel( + ['build', '--nobuild', '--lockfile_mode=error', '//:all'], + allow_failure=True, + ) + self.AssertExitCode(exit_code, 48, stderr) + self.assertIn( + ( + 'ERROR: Error computing the main repository mapping: Lock file is' + ' no longer up-to-date because: the version of the lockfile is not' + ' compatible with the current Bazel, please run with' + " '--lockfile_mode=update'" + ), + stderr, + ) + + # Run again with update + self.RunBazel(['build', '--nobuild', '//:all']) + with open('MODULE.bazel.lock', 'r') as json_file: + data = json.load(json_file) + self.assertEqual(data['lockFileVersion'], 1) + if __name__ == '__main__': unittest.main()