From 99b3f38649dc82efde6c570e80ce4f3abbc4ac43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?X=C3=B9d=C5=8Dng=20Y=C3=A1ng?= Date: Tue, 28 Mar 2023 05:34:00 +1100 Subject: [PATCH] [6.2.0] Add native.module_{name,version} (#17893) * Remove BzlmodRepoRuleHelper The helper logic is only used in the BzlmodRepoRuleFunction so no need to have it in a separate place. - Remove BzlmodRepoRuleHelper Interface & its implementations - Refactor BzlmodRepoRuleFunction to use the helper logic - Update tests and Build files accordingly PiperOrigin-RevId: 486712547 Change-Id: I9a274a6a0afcc77be56bbe20e0c4d17c41c31c58 * Separate selection from bazel dependency graph * Created new K/F/V for Bazel dependency graph named "BazelDepGraph" * Refactored "BazelModuleResolution" to only run resolution (discovery, selection and checks) to create pruned and unpruned graph and not create any dependency value * BazelDepGraphResolution calls BazelModuleResolution and extracts the dependency graph from it * Updated tests PiperOrigin-RevId: 499026445 Change-Id: Id1237f9d09015ffe8987d933431fccfcfa0c0963 * Add native.module_{name,version} Extension authors often want to write some macro and change its behavior depending on which module is using it. For example, for rules_go, they want to look at the `go_deps` tags in a certain module and only allow access to repos generated from those tags. We do this by introducing two new methods on `native`, callable only during the loading phase. They return the name and version of the module associated with the current repo. If the repo is from WORKSPACE, they return `None`. If the repo is generated by an extension, they return info about the module hosting the extension. The implementation works by storing the "associated module" information in `RepositoryMappingValue`. I had attempted to store them in `BzlmodRepoRuleValue` or even `RepositoryDirectoryValue`, but those are not the right places since they might happen before we even evaluate the MODULE.bazel file (i.e. for non-registry overrides). Fixes https://github.com/bazelbuild/bazel/issues/17652. RELNOTES: Added `native.module_name()` and `native.module_version()` to allow BUILD macro authors to acquire information about which Bazel module the current repo is associated with. PiperOrigin-RevId: 518849334 Change-Id: I06b4bc95b5a57de2412ee02544240b054c708165 * fix BUILD * remove test case that was accidentally cherry-picked --------- Co-authored-by: salma-samy Co-authored-by: kshyanashree <109167932+kshyanashree@users.noreply.github.com> --- .../lib/bazel/BazelRepositoryModule.java | 4 +- .../devtools/build/lib/bazel/bzlmod/BUILD | 20 +- .../bazel/bzlmod/BazelDepGraphFunction.java | 120 ++++++ .../lib/bazel/bzlmod/BazelDepGraphValue.java | 100 +++++ .../bzlmod/BazelModuleInspectorFunction.java | 2 +- .../bzlmod/BazelModuleResolutionFunction.java | 181 +++------ .../bzlmod/BazelModuleResolutionValue.java | 95 +---- .../bazel/bzlmod/BzlmodRepoRuleHelper.java | 26 -- .../bzlmod/BzlmodRepoRuleHelperImpl.java | 110 ------ .../build/lib/bazel/bzlmod/Module.java | 2 +- .../build/lib/bazel/bzlmod/Selection.java | 36 +- .../bzlmod/SingleExtensionUsagesFunction.java | 14 +- .../bzlmod/SingleExtensionUsagesValue.java | 3 +- .../devtools/build/lib/packages/Package.java | 66 +++- .../build/lib/packages/PackageFactory.java | 5 + .../lib/packages/StarlarkNativeModule.java | 14 + .../RepositoryDelegatorFunction.java | 10 +- .../google/devtools/build/lib/skyframe/BUILD | 3 +- .../lib/skyframe/BzlmodRepoRuleFunction.java | 107 ++++- .../build/lib/skyframe/PackageFunction.java | 2 + .../RegisteredExecutionPlatformsFunction.java | 12 +- .../RegisteredToolchainsFunction.java | 12 +- .../skyframe/RepositoryMappingFunction.java | 105 ++--- .../lib/skyframe/RepositoryMappingValue.java | 88 +++-- .../build/lib/skyframe/SkyFunctions.java | 2 + .../build/lib/skyframe/SkyframeExecutor.java | 3 +- .../packages/AbstractPackageLoader.java | 4 +- .../build/lib/skyframe/packages/BUILD | 1 - .../StarlarkNativeModuleApi.java | 27 ++ .../FakeStarlarkNativeModuleApi.java | 12 + .../build/lib/analysis/util/AnalysisMock.java | 3 + .../devtools/build/lib/bazel/bzlmod/BUILD | 2 - .../bzlmod/BazelDepGraphFunctionTest.java | 348 ++++++++++++++++ .../BazelModuleResolutionFunctionTest.java | 188 +-------- .../bzlmod/BzlmodRepoRuleFunctionTest.java | 310 +++++++-------- .../bzlmod/BzlmodRepoRuleHelperTest.java | 374 ------------------ .../build/lib/bazel/bzlmod/DiscoveryTest.java | 3 +- .../bzlmod/FakeBzlmodRepoRuleHelper.java | 36 -- .../bzlmod/ModuleExtensionResolutionTest.java | 20 +- .../bazel/bzlmod/ModuleFileFunctionTest.java | 3 +- .../build/lib/bazel/bzlmod/SelectionTest.java | 23 +- .../build/lib/packages/PackageTest.java | 5 +- .../build/lib/packages/RuleClassTest.java | 3 + .../build/lib/packages/RuleFactoryTest.java | 3 + .../devtools/build/lib/rules/repository/BUILD | 1 - .../repository/RepositoryDelegatorTest.java | 12 +- .../RepositoryMappingFunctionTest.java | 117 +++--- src/test/py/bazel/bzlmod/bazel_module_test.py | 107 +++++ 48 files changed, 1353 insertions(+), 1391 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java create mode 100644 src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphValue.java delete mode 100644 src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java delete mode 100644 src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java create mode 100644 src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java delete mode 100644 src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java delete mode 100644 src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeBzlmodRepoRuleHelper.java diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java index 60a1becf68679a..219cb430b92706 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorFunction; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule.ResolutionReason; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction; @@ -248,8 +249,9 @@ public ResolutionReason getResolutionReason() { .addSkyFunction( SkyFunctions.MODULE_FILE, new ModuleFileFunction(registryFactory, directories.getWorkspace(), builtinModules)) - .addSkyFunction(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) + .addSkyFunction(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) .addSkyFunction(SkyFunctions.BAZEL_MODULE_INSPECTION, new BazelModuleInspectorFunction()) + .addSkyFunction(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) .addSkyFunction(SkyFunctions.SINGLE_EXTENSION_EVAL, singleExtensionEvalFunction) .addSkyFunction(SkyFunctions.SINGLE_EXTENSION_USAGES, new SingleExtensionUsagesFunction()); filesystem = runtime.getFileSystem(); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD index e6a4c7ddac6fc7..169711f8d1285a 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD @@ -85,6 +85,7 @@ java_library( srcs = [ "AbridgedModule.java", "ArchiveOverride.java", + "BazelDepGraphValue.java", "BazelModuleResolutionValue.java", "GitOverride.java", "LocalPathOverride.java", @@ -125,6 +126,7 @@ java_library( java_library( name = "resolution_impl", srcs = [ + "BazelDepGraphFunction.java", "BazelModuleResolutionFunction.java", "Discovery.java", "ModuleExtensionContext.java", @@ -191,24 +193,6 @@ java_library( ], ) -java_library( - name = "repo_rule_helper", - srcs = [ - "BzlmodRepoRuleHelper.java", - "BzlmodRepoRuleHelperImpl.java", - ], - deps = [ - ":common", - ":registry", - ":resolution", - "//src/main/java/com/google/devtools/build/lib/cmdline", - "//src/main/java/com/google/devtools/build/lib/events", - "//src/main/java/com/google/devtools/build/skyframe", - "//third_party:guava", - "//third_party:jsr305", - ], -) - java_library( name = "repo_rule_creator", srcs = ["BzlmodRepoRuleCreator.java"], 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 new file mode 100644 index 00000000000000..3091a04226fb96 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunction.java @@ -0,0 +1,120 @@ +// Copyright 2022 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.google.devtools.build.lib.bazel.bzlmod; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableTable; +import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction.BazelModuleResolutionFunctionException; +import com.google.devtools.build.lib.cmdline.LabelSyntaxException; +import com.google.devtools.build.lib.cmdline.PackageIdentifier; +import com.google.devtools.build.lib.cmdline.RepositoryName; +import com.google.devtools.build.lib.packages.LabelConverter; +import com.google.devtools.build.lib.server.FailureDetails.ExternalDeps.Code; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyFunctionException; +import com.google.devtools.build.skyframe.SkyFunctionException.Transience; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import javax.annotation.Nullable; + +/** + * This function runs Bazel module resolution, extracts the dependency graph from it and creates a + * value containing all Bazel modules, along with a few lookup maps that help with further usage. By + * this stage, module extensions are not evaluated yet. + */ +public class BazelDepGraphFunction implements SkyFunction { + + @Override + @Nullable + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + + BazelModuleResolutionValue selectionResult = + (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); + if (env.valuesMissing()) { + return null; + } + + ImmutableMap depGraph = selectionResult.getResolvedDepGraph(); + ImmutableMap canonicalRepoNameLookup = + depGraph.keySet().stream() + .collect(toImmutableMap(ModuleKey::getCanonicalRepoName, key -> key)); + + // For each extension usage, we resolve (i.e. canonicalize) its bzl file label. Then we can + // group all usages by the label + name (the ModuleExtensionId). + ImmutableTable.Builder + extensionUsagesTableBuilder = ImmutableTable.builder(); + for (Module module : depGraph.values()) { + LabelConverter labelConverter = + new LabelConverter( + PackageIdentifier.create(module.getCanonicalRepoName(), PathFragment.EMPTY_FRAGMENT), + module.getRepoMappingWithBazelDepsOnly()); + for (ModuleExtensionUsage usage : module.getExtensionUsages()) { + try { + ModuleExtensionId moduleExtensionId = + ModuleExtensionId.create( + labelConverter.convert(usage.getExtensionBzlFile()), usage.getExtensionName()); + extensionUsagesTableBuilder.put(moduleExtensionId, module.getKey(), usage); + } catch (LabelSyntaxException e) { + throw new BazelModuleResolutionFunctionException( + ExternalDepsException.withCauseAndMessage( + Code.BAD_MODULE, + e, + "invalid label for module extension found at %s", + usage.getLocation()), + Transience.PERSISTENT); + } + } + } + ImmutableTable extensionUsagesById = + extensionUsagesTableBuilder.buildOrThrow(); + + // Calculate a unique name for each used extension id. + BiMap extensionUniqueNames = HashBiMap.create(); + for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) { + // Ensure that the resulting extension name (and thus the repository names derived from it) do + // not start with a tilde. + RepositoryName repository = id.getBzlFileLabel().getRepository(); + String nonEmptyRepoPart; + if (repository.isMain()) { + nonEmptyRepoPart = "_main"; + } else { + nonEmptyRepoPart = repository.getName(); + } + String bestName = nonEmptyRepoPart + "~" + id.getExtensionName(); + if (extensionUniqueNames.putIfAbsent(bestName, id) == null) { + continue; + } + int suffix = 2; + while (extensionUniqueNames.putIfAbsent(bestName + suffix, id) != null) { + suffix++; + } + } + + return BazelDepGraphValue.create( + depGraph, + canonicalRepoNameLookup, + depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList()), + extensionUsagesById, + ImmutableMap.copyOf(extensionUniqueNames.inverse())); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphValue.java new file mode 100644 index 00000000000000..fab2435d52d307 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphValue.java @@ -0,0 +1,100 @@ +// Copyright 2022 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.google.devtools.build.lib.bazel.bzlmod; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableTable; +import com.google.devtools.build.lib.cmdline.RepositoryMapping; +import com.google.devtools.build.lib.cmdline.RepositoryName; +import com.google.devtools.build.lib.skyframe.SkyFunctions; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import java.util.Map; + +/** + * The result of running Bazel module resolution, containing the Bazel module dependency graph + * post-version-resolution. + */ +@AutoValue +public abstract class BazelDepGraphValue implements SkyValue { + @SerializationConstant public static final SkyKey KEY = () -> SkyFunctions.BAZEL_DEP_GRAPH; + + public static BazelDepGraphValue create( + ImmutableMap depGraph, + ImmutableMap canonicalRepoNameLookup, + ImmutableList abridgedModules, + ImmutableTable extensionUsagesTable, + ImmutableMap extensionUniqueNames) { + return new AutoValue_BazelDepGraphValue( + depGraph, + canonicalRepoNameLookup, + abridgedModules, + extensionUsagesTable, + extensionUniqueNames); + } + + /** + * The post-selection dep graph. Must have BFS iteration order, starting from the root module. For + * any KEY in the returned map, it's guaranteed that {@code depGraph[KEY].getKey() == KEY}. + */ + public abstract ImmutableMap getDepGraph(); + + /** A mapping from a canonical repo name to the key of the module backing it. */ + public abstract ImmutableMap getCanonicalRepoNameLookup(); + + /** All modules in the same order as {@link #getDepGraph}, but with limited information. */ + public abstract ImmutableList getAbridgedModules(); + + /** + * All module extension usages grouped by the extension's ID and the key of the module where this + * usage occurs. For each extension identifier ID, extensionUsagesTable[ID][moduleKey] is the + * ModuleExtensionUsage of ID in the module keyed by moduleKey. + */ + public abstract ImmutableTable + getExtensionUsagesTable(); + + /** + * A mapping from the ID of a module extension to a unique string that serves as its "name". This + * is not the same as the extension's declared name, as the declared name is only unique within + * the .bzl file, whereas this unique name is guaranteed to be unique across the workspace. + */ + public abstract ImmutableMap getExtensionUniqueNames(); + + /** + * Returns the full {@link RepositoryMapping} for the given module, including repos from Bazel + * module deps and module extensions. + */ + public final RepositoryMapping getFullRepoMapping(ModuleKey key) { + ImmutableMap.Builder mapping = ImmutableMap.builder(); + for (Map.Entry e : + getExtensionUsagesTable().column(key).entrySet()) { + ModuleExtensionId extensionId = e.getKey(); + ModuleExtensionUsage usage = e.getValue(); + for (Map.Entry entry : usage.getImports().entrySet()) { + String canonicalRepoName = + getExtensionUniqueNames().get(extensionId) + "~" + entry.getValue(); + mapping.put(entry.getKey(), RepositoryName.createUnvalidated(canonicalRepoName)); + } + } + return getDepGraph() + .get(key) + .getRepoMappingWithBazelDepsOnly() + .withAdditionalMappings(mapping.buildOrThrow()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java index 67f8cfdfb495f1..0394de65277e22 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java @@ -56,7 +56,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) } ImmutableMap overrides = root.getOverrides(); ImmutableMap unprunedDepGraph = resolutionValue.getUnprunedDepGraph(); - ImmutableMap resolvedDepGraph = resolutionValue.getDepGraph(); + ImmutableMap resolvedDepGraph = resolutionValue.getResolvedDepGraph(); ImmutableMap depGraph = computeAugmentedGraph(unprunedDepGraph, resolvedDepGraph.keySet(), overrides); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java index 033f02894dd6d1..c44ca83ea57bc7 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java @@ -1,4 +1,4 @@ -// Copyright 2021 The Bazel Authors. All rights reserved. +// Copyright 2022 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. @@ -15,38 +15,26 @@ package com.google.devtools.build.lib.bazel.bzlmod; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.collect.ImmutableMap.toImmutableMap; - -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.base.Strings; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableTable; import com.google.devtools.build.lib.analysis.BlazeVersionInfo; import com.google.devtools.build.lib.bazel.BazelVersion; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; -import com.google.devtools.build.lib.bazel.bzlmod.Selection.SelectionResult; import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; -import com.google.devtools.build.lib.cmdline.LabelSyntaxException; -import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.ExtendedEventHandler; -import com.google.devtools.build.lib.packages.LabelConverter; import com.google.devtools.build.lib.server.FailureDetails.ExternalDeps.Code; import com.google.devtools.build.lib.skyframe.ClientEnvironmentFunction; import com.google.devtools.build.lib.skyframe.ClientEnvironmentValue; import com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed; -import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionException; import com.google.devtools.build.skyframe.SkyFunctionException.Transience; @@ -60,9 +48,8 @@ import javax.annotation.Nullable; /** - * Runs Bazel module resolution. This function produces the dependency graph containing all Bazel - * modules, along with a few lookup maps that help with further usage. By this stage, module - * extensions are not evaluated yet. + * Discovers the whole dependency graph and runs selection algorithm on it to produce the pruned + * dependency graph and runs checks on it. */ public class BazelModuleResolutionFunction implements SkyFunction { @@ -70,15 +57,16 @@ public class BazelModuleResolutionFunction implements SkyFunction { new Precomputed<>("check_direct_dependency"); public static final Precomputed BAZEL_COMPATIBILITY_MODE = new Precomputed<>("bazel_compatibility_mode"); - public static final Precomputed> ALLOWED_YANKED_VERSIONS = new Precomputed<>("allowed_yanked_versions"); + private static final String BZLMOD_ALLOWED_YANKED_VERSIONS_ENV = "BZLMOD_ALLOW_YANKED_VERSIONS"; @Override @Nullable public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException { + ClientEnvironmentValue allowedYankedVersionsFromEnv = (ClientEnvironmentValue) env.getValue(ClientEnvironmentFunction.key(BZLMOD_ALLOWED_YANKED_VERSIONS_ENV)); @@ -94,28 +82,70 @@ public SkyValue compute(SkyKey skyKey, Environment env) if (initialDepGraph == null) { return null; } - ImmutableMap overrides = root.getOverrides(); - SelectionResult selectionResult; + + BazelModuleResolutionValue selectionResultValue; try { - selectionResult = Selection.run(initialDepGraph, overrides); + selectionResultValue = Selection.run(initialDepGraph, root.getOverrides()); } catch (ExternalDepsException e) { throw new BazelModuleResolutionFunctionException(e, Transience.PERSISTENT); } - ImmutableMap resolvedDepGraph = selectionResult.getResolvedDepGraph(); + ImmutableMap resolvedDepGraph = selectionResultValue.getResolvedDepGraph(); + + verifyRootModuleDirectDepsAreAccurate( + initialDepGraph.get(ModuleKey.ROOT), + resolvedDepGraph.get(ModuleKey.ROOT), + Objects.requireNonNull(CHECK_DIRECT_DEPENDENCIES.get(env)), + env.getListener()); checkBazelCompatibility( resolvedDepGraph.values(), Objects.requireNonNull(BAZEL_COMPATIBILITY_MODE.get(env)), env.getListener()); + verifyYankedVersions( resolvedDepGraph, parseYankedVersions( allowedYankedVersionsFromEnv.getValue(), Objects.requireNonNull(ALLOWED_YANKED_VERSIONS.get(env))), env.getListener()); - verifyRootModuleDirectDepsAreAccurate( - env, initialDepGraph.get(ModuleKey.ROOT), resolvedDepGraph.get(ModuleKey.ROOT)); - return createValue(resolvedDepGraph, selectionResult.getUnprunedDepGraph(), overrides); + + return selectionResultValue; + } + + private static void verifyRootModuleDirectDepsAreAccurate( + Module discoveredRootModule, + Module resolvedRootModule, + CheckDirectDepsMode mode, + EventHandler eventHandler) + throws BazelModuleResolutionFunctionException { + if (mode == CheckDirectDepsMode.OFF) { + return; + } + + boolean failure = false; + for (Map.Entry dep : discoveredRootModule.getDeps().entrySet()) { + ModuleKey resolved = resolvedRootModule.getDeps().get(dep.getKey()); + if (!dep.getValue().equals(resolved)) { + String message = + String.format( + "For repository '%s', the root module requires module version %s, but got %s in the" + + " resolved dependency graph.", + dep.getKey(), dep.getValue(), resolved); + if (mode == CheckDirectDepsMode.WARNING) { + eventHandler.handle(Event.warn(message)); + } else { + eventHandler.handle(Event.error(message)); + failure = true; + } + } + } + + if (failure) { + throw new BazelModuleResolutionFunctionException( + ExternalDepsException.withMessage( + Code.VERSION_RESOLUTION_ERROR, "Direct dependency check failed."), + Transience.PERSISTENT); + } } public static void checkBazelCompatibility( @@ -291,109 +321,6 @@ private void verifyYankedVersions( } } - private static void verifyRootModuleDirectDepsAreAccurate( - Environment env, Module discoveredRootModule, Module resolvedRootModule) - throws InterruptedException, BazelModuleResolutionFunctionException { - CheckDirectDepsMode mode = Objects.requireNonNull(CHECK_DIRECT_DEPENDENCIES.get(env)); - if (mode == CheckDirectDepsMode.OFF) { - return; - } - boolean failure = false; - for (Map.Entry dep : discoveredRootModule.getDeps().entrySet()) { - ModuleKey resolved = resolvedRootModule.getDeps().get(dep.getKey()); - if (!dep.getValue().equals(resolved)) { - String message = - String.format( - "For repository '%s', the root module requires module version %s, but got %s in the" - + " resolved dependency graph.", - dep.getKey(), dep.getValue(), resolved); - if (mode == CheckDirectDepsMode.WARNING) { - env.getListener().handle(Event.warn(message)); - } else { - env.getListener().handle(Event.error(message)); - failure = true; - } - } - } - if (failure) { - throw new BazelModuleResolutionFunctionException( - ExternalDepsException.withMessage( - Code.VERSION_RESOLUTION_ERROR, "Direct dependency check failed."), - Transience.PERSISTENT); - } - } - - @VisibleForTesting - static BazelModuleResolutionValue createValue( - ImmutableMap depGraph, - ImmutableMap unprunedDepGraph, - ImmutableMap overrides) - throws BazelModuleResolutionFunctionException { - // Build some reverse lookups for later use. - ImmutableMap canonicalRepoNameLookup = - depGraph.keySet().stream() - .collect(toImmutableMap(ModuleKey::getCanonicalRepoName, key -> key)); - - // For each extension usage, we resolve (i.e. canonicalize) its bzl file label. Then we can - // group all usages by the label + name (the ModuleExtensionId). - ImmutableTable.Builder - extensionUsagesTableBuilder = ImmutableTable.builder(); - for (Module module : depGraph.values()) { - LabelConverter labelConverter = - new LabelConverter( - PackageIdentifier.create(module.getCanonicalRepoName(), PathFragment.EMPTY_FRAGMENT), - module.getRepoMappingWithBazelDepsOnly()); - for (ModuleExtensionUsage usage : module.getExtensionUsages()) { - try { - ModuleExtensionId moduleExtensionId = - ModuleExtensionId.create( - labelConverter.convert(usage.getExtensionBzlFile()), usage.getExtensionName()); - extensionUsagesTableBuilder.put(moduleExtensionId, module.getKey(), usage); - } catch (LabelSyntaxException e) { - throw new BazelModuleResolutionFunctionException( - ExternalDepsException.withCauseAndMessage( - Code.BAD_MODULE, - e, - "invalid label for module extension found at %s", - usage.getLocation()), - Transience.PERSISTENT); - } - } - } - ImmutableTable extensionUsagesById = - extensionUsagesTableBuilder.buildOrThrow(); - - // Calculate a unique name for each used extension id. - BiMap extensionUniqueNames = HashBiMap.create(); - for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) { - // Ensure that the resulting extension name (and thus the repository names derived from it) do - // not start with a tilde. - RepositoryName repository = id.getBzlFileLabel().getRepository(); - String nonEmptyRepoPart; - if (repository.isMain()) { - nonEmptyRepoPart = "_main"; - } else { - nonEmptyRepoPart = repository.getName(); - } - String bestName = nonEmptyRepoPart + "~" + id.getExtensionName(); - if (extensionUniqueNames.putIfAbsent(bestName, id) == null) { - continue; - } - int suffix = 2; - while (extensionUniqueNames.putIfAbsent(bestName + suffix, id) != null) { - suffix++; - } - } - - return BazelModuleResolutionValue.create( - depGraph, - unprunedDepGraph, - canonicalRepoNameLookup, - depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList()), - extensionUsagesById, - ImmutableMap.copyOf(extensionUniqueNames.inverse())); - } - static class BazelModuleResolutionFunctionException extends SkyFunctionException { BazelModuleResolutionFunctionException(ExternalDepsException e, Transience transience) { super(e, transience); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java index f48eee06904a3f..f2c734647478ed 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java @@ -1,4 +1,4 @@ -// Copyright 2021 The Bazel Authors. All rights reserved. +// Copyright 2022 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. @@ -16,96 +16,39 @@ package com.google.devtools.build.lib.bazel.bzlmod; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableTable; -import com.google.devtools.build.lib.cmdline.RepositoryMapping; -import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.skyframe.SkyFunctions; import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; -import java.util.Map; /** - * The result of running Bazel module resolution, containing the Bazel module dependency graph - * post-version-resolution. + * The result of the selection process, containing both the pruned and the un-pruned dependency + * graphs. */ @AutoValue -public abstract class BazelModuleResolutionValue implements SkyValue { +abstract class BazelModuleResolutionValue implements SkyValue { + /* TODO(andreisolo): Also load the modules overridden by {@code single_version_override} or + NonRegistryOverride if we need to detect changes in the dependency graph caused by them. + */ + @SerializationConstant public static final SkyKey KEY = () -> SkyFunctions.BAZEL_MODULE_RESOLUTION; - public static BazelModuleResolutionValue create( - ImmutableMap depGraph, - ImmutableMap unprunedDepGraph, - ImmutableMap canonicalRepoNameLookup, - ImmutableList abridgedModules, - ImmutableTable extensionUsagesTable, - ImmutableMap extensionUniqueNames) { - return new AutoValue_BazelModuleResolutionValue( - depGraph, - unprunedDepGraph, - canonicalRepoNameLookup, - abridgedModules, - extensionUsagesTable, - extensionUniqueNames); - } - - /** - * The post-selection dep graph. Must have BFS iteration order, starting from the root module. For - * any KEY in the returned map, it's guaranteed that {@code depGraph[KEY].getKey() == KEY}. - */ - public abstract ImmutableMap getDepGraph(); + /** Final dep graph sorted in BFS iteration order, with unused modules removed. */ + abstract ImmutableMap getResolvedDepGraph(); /** - * The post-selection un-pruned dep graph, used for in-depth inspection. TODO(andreisolo): decide - * whether to store the un-pruned graph or just the removed modules? Random order (depends on - * SkyFrame execution order). For any KEY in the returned map, it's guaranteed that {@code - * depGraph[KEY].getKey() == KEY}. + * Un-pruned dep graph, with updated dep keys, and additionally containing the unused modules + * which were initially discovered (and their MODULE.bazel files loaded). Does not contain modules + * overridden by {@code single_version_override} or {@link NonRegistryOverride}, only by {@code + * multiple_version_override}. */ - public abstract ImmutableMap getUnprunedDepGraph(); - - /** A mapping from a canonical repo name to the key of the module backing it. */ - public abstract ImmutableMap getCanonicalRepoNameLookup(); + abstract ImmutableMap getUnprunedDepGraph(); - /** All modules in the same order as {@link #getDepGraph}, but with limited information. */ - public abstract ImmutableList getAbridgedModules(); - - /** - * All module extension usages grouped by the extension's ID and the key of the module where this - * usage occurs. For each extension identifier ID, extensionUsagesTable[ID][moduleKey] is the - * ModuleExtensionUsage of ID in the module keyed by moduleKey. - */ - public abstract ImmutableTable - getExtensionUsagesTable(); - - /** - * A mapping from the ID of a module extension to a unique string that serves as its "name". This - * is not the same as the extension's declared name, as the declared name is only unique within - * the .bzl file, whereas this unique name is guaranteed to be unique across the workspace. - */ - public abstract ImmutableMap getExtensionUniqueNames(); - - /** - * Returns the full {@link RepositoryMapping} for the given module, including repos from Bazel - * module deps and module extensions. - */ - public final RepositoryMapping getFullRepoMapping(ModuleKey key) { - ImmutableMap.Builder mapping = ImmutableMap.builder(); - for (Map.Entry e : - getExtensionUsagesTable().column(key).entrySet()) { - ModuleExtensionId extensionId = e.getKey(); - ModuleExtensionUsage usage = e.getValue(); - for (Map.Entry entry : usage.getImports().entrySet()) { - String canonicalRepoName = - getExtensionUniqueNames().get(extensionId) + "~" + entry.getValue(); - mapping.put(entry.getKey(), RepositoryName.createUnvalidated(canonicalRepoName)); - } - } - return getDepGraph() - .get(key) - .getRepoMappingWithBazelDepsOnly() - .withAdditionalMappings(mapping.buildOrThrow()); + static BazelModuleResolutionValue create( + ImmutableMap resolvedDepGraph, + ImmutableMap unprunedDepGraph) { + return new AutoValue_BazelModuleResolutionValue(resolvedDepGraph, unprunedDepGraph); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java deleted file mode 100644 index b180d713a67870..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2021 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.google.devtools.build.lib.bazel.bzlmod; - -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.skyframe.SkyFunction.Environment; -import java.io.IOException; -import java.util.Optional; - -/** A helper to get {@link RepoSpec} for Bzlmod generated repositories. */ -public interface BzlmodRepoRuleHelper { - Optional getRepoSpec(Environment env, RepositoryName repositoryName) - throws InterruptedException, IOException; -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java deleted file mode 100644 index d2cd2807359c81..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2021 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.google.devtools.build.lib.bazel.bzlmod; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.lib.events.ExtendedEventHandler; -import com.google.devtools.build.skyframe.SkyFunction.Environment; -import java.io.IOException; -import java.util.Optional; -import javax.annotation.Nullable; - -/** A helper class to get {@link RepoSpec} for Bzlmod generated repositories. */ -public final class BzlmodRepoRuleHelperImpl implements BzlmodRepoRuleHelper { - - @Override - @Nullable - public Optional getRepoSpec(Environment env, RepositoryName repositoryName) - throws InterruptedException, IOException { - - RootModuleFileValue root = - (RootModuleFileValue) env.getValue(ModuleFileValue.KEY_FOR_ROOT_MODULE); - if (env.valuesMissing()) { - return null; - } - ImmutableMap overrides = root.getOverrides(); - - // Step 1: Look for repositories defined by non-registry overrides. - Optional repoSpec = checkRepoFromNonRegistryOverrides(root, repositoryName); - if (repoSpec.isPresent()) { - return repoSpec; - } - - // BazelModuleResolutionValue is affected by repos found in Step 1, therefore it should NOT be - // requested in Step 1 to avoid cycle dependency. - BazelModuleResolutionValue bazelModuleResolutionValue = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (env.valuesMissing()) { - return null; - } - - // Step 2: Look for repositories derived from Bazel Modules. - return checkRepoFromBazelModules( - bazelModuleResolutionValue, overrides, env.getListener(), repositoryName); - } - - private static Optional checkRepoFromNonRegistryOverrides( - RootModuleFileValue root, RepositoryName repositoryName) { - String moduleName = root.getNonRegistryOverrideCanonicalRepoNameLookup().get(repositoryName); - if (moduleName == null) { - return Optional.empty(); - } - NonRegistryOverride override = (NonRegistryOverride) root.getOverrides().get(moduleName); - return Optional.of(override.getRepoSpec(repositoryName)); - } - - private static Optional checkRepoFromBazelModules( - BazelModuleResolutionValue bazelModuleResolutionValue, - ImmutableMap overrides, - ExtendedEventHandler eventListener, - RepositoryName repositoryName) - throws InterruptedException, IOException { - ModuleKey moduleKey = - bazelModuleResolutionValue.getCanonicalRepoNameLookup().get(repositoryName); - if (moduleKey == null) { - return Optional.empty(); - } - Module module = bazelModuleResolutionValue.getDepGraph().get(moduleKey); - Registry registry = checkNotNull(module.getRegistry()); - RepoSpec repoSpec = registry.getRepoSpec(moduleKey, repositoryName, eventListener); - repoSpec = maybeAppendAdditionalPatches(repoSpec, overrides.get(moduleKey.getName())); - return Optional.of(repoSpec); - } - - private static RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride override) { - if (!(override instanceof SingleVersionOverride)) { - return repoSpec; - } - SingleVersionOverride singleVersion = (SingleVersionOverride) override; - if (singleVersion.getPatches().isEmpty()) { - return repoSpec; - } - ImmutableMap.Builder attrBuilder = ImmutableMap.builder(); - attrBuilder.putAll(repoSpec.attributes()); - attrBuilder.put("patches", singleVersion.getPatches()); - attrBuilder.put("patch_cmds", singleVersion.getPatchCmds()); - attrBuilder.put("patch_args", ImmutableList.of("-p" + singleVersion.getPatchStrip())); - return RepoSpec.builder() - .setBzlFile(repoSpec.bzlFile()) - .setRuleClassName(repoSpec.ruleClassName()) - .setAttributes(attrBuilder.buildOrThrow()) - .build(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java index 807c7118c4a3a8..2952548e851bd5 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java @@ -115,7 +115,7 @@ public final RepositoryName getCanonicalRepoName() { /** * Returns a {@link RepositoryMapping} with only Bazel module repos and no repos from module - * extensions. For the full mapping, see {@link BazelModuleResolutionValue#getFullRepoMapping}. + * extensions. For the full mapping, see {@link BazelDepGraphValue#getFullRepoMapping}. */ public final RepositoryMapping getRepoMappingWithBazelDepsOnly() { ImmutableMap.Builder mapping = ImmutableMap.builder(); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java index 615feac57a776c..bcacb7b1928ba9 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java @@ -67,34 +67,6 @@ final class Selection { private Selection() {} - /** - * The result of the selection process, containing both the pruned and the un-pruned dependency - * graphs. - */ - @AutoValue - abstract static class SelectionResult { - /* TODO(andreisolo): Also load the modules overridden by {@code single_version_override} or - NonRegistryOverride if we need to detect changes in the dependency graph caused by them. - */ - - /** Final dep graph sorted in BFS iteration order, with unused modules removed. */ - abstract ImmutableMap getResolvedDepGraph(); - - /** - * Un-pruned dep graph, with updated dep keys, and additionally containing the unused modules - * which were initially discovered (and their MODULE.bazel files loaded). Does not contain - * modules overridden by {@code single_version_override} or {@link NonRegistryOverride}, only by - * {@code multiple_version_override}. - */ - abstract ImmutableMap getUnprunedDepGraph(); - - static SelectionResult create( - ImmutableMap resolvedDepGraph, - ImmutableMap unprunedDepGraph) { - return new AutoValue_Selection_SelectionResult(resolvedDepGraph, unprunedDepGraph); - } - } - /** During selection, a version is selected for each distinct "selection group". */ @AutoValue abstract static class SelectionGroup { @@ -193,8 +165,10 @@ private static SelectionGroup computeSelectionGroup( allowedVersionSet.ceiling(module.getVersion())); } - /** Runs module selection (aka version resolution). Returns a {@link SelectionResult}. */ - public static SelectionResult run( + /** + * Runs module selection (aka version resolution). Returns a {@link BazelModuleResolutionValue}. + */ + public static BazelModuleResolutionValue run( ImmutableMap depGraph, ImmutableMap overrides) throws ExternalDepsException { // For any multiple-version overrides, build a mapping from (moduleName, compatibilityLevel) to @@ -254,7 +228,7 @@ public static SelectionResult run( new DepGraphWalker(newDepGraph, overrides, selectionGroups).walk(); // Return the result containing both the pruned and un-pruned dep graphs - return SelectionResult.create(prunedDepGraph, unprunedDepGraph); + return BazelModuleResolutionValue.create(prunedDepGraph, unprunedDepGraph); } /** diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesFunction.java index e5f001679bca5a..821c759d258d56 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesFunction.java @@ -44,24 +44,24 @@ public class SingleExtensionUsagesFunction implements SkyFunction { @Nullable public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException { - BazelModuleResolutionValue bazelModuleResolutionValue = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (bazelModuleResolutionValue == null) { + BazelDepGraphValue bazelDepGraphValue = + (BazelDepGraphValue) env.getValue(BazelDepGraphValue.KEY); + if (bazelDepGraphValue == null) { return null; } ModuleExtensionId id = (ModuleExtensionId) skyKey.argument(); ImmutableTable usagesTable = - bazelModuleResolutionValue.getExtensionUsagesTable(); + bazelDepGraphValue.getExtensionUsagesTable(); return SingleExtensionUsagesValue.create( usagesTable.row(id), - bazelModuleResolutionValue.getExtensionUniqueNames().get(id), + bazelDepGraphValue.getExtensionUniqueNames().get(id), // Filter abridged modules down to only those that actually used this extension. - bazelModuleResolutionValue.getAbridgedModules().stream() + bazelDepGraphValue.getAbridgedModules().stream() .filter(module -> usagesTable.contains(id, module.getKey())) .collect(toImmutableList()), // TODO(wyv): Maybe cache these mappings? usagesTable.row(id).keySet().stream() - .collect(toImmutableMap(key -> key, bazelModuleResolutionValue::getFullRepoMapping))); + .collect(toImmutableMap(key -> key, bazelDepGraphValue::getFullRepoMapping))); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesValue.java index 037054bb02d4b9..f00e1bbd4852b3 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionUsagesValue.java @@ -34,8 +34,7 @@ public abstract class SingleExtensionUsagesValue implements SkyValue { public abstract ImmutableMap getExtensionUsages(); /** - * The "unique name" (see {@link BazelModuleResolutionValue#getExtensionUniqueNames} of this - * extension. + * The "unique name" (see {@link BazelDepGraphValue#getExtensionUniqueNames} of this extension. */ public abstract String getExtensionUniqueName(); diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java index d3ea5d14edcc5a..6bad536e19b08c 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Package.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java @@ -128,17 +128,31 @@ private NameConflictException(String message) { private RootedPath filename; /** - * The directory in which this package's BUILD file resides. All InputFile - * members of the packages are located relative to this directory. + * The directory in which this package's BUILD file resides. All InputFile members of the packages + * are located relative to this directory. */ private Path packageDirectory; /** - * The name of the workspace this package is in. Used as a prefix for the runfiles directory. - * This can be set in the WORKSPACE file. This must be a valid target name. + * The name of the workspace this package is in. Used as a prefix for the runfiles directory. This + * can be set in the WORKSPACE file. This must be a valid target name. */ private String workspaceName; + /** + * The name of the Bzlmod module associated with the repo this package is in. If this package is + * not from a Bzlmod repo, this is empty. For repos generated by module extensions, this is the + * name of the module hosting the extension. + */ + private final Optional associatedModuleName; + + /** + * The version of the Bzlmod module associated with the repo this package is in. If this package + * is not from a Bzlmod repo, this is empty. For repos generated by module extensions, this is the + * version of the module hosting the extension. + */ + private final Optional associatedModuleVersion; + /** * The root of the source tree in which this package was found. It is an invariant that {@code * sourceRoot.getRelative(packageId.getSourceRoot()).equals(packageDirectory)}. Returns {@link @@ -147,8 +161,8 @@ private NameConflictException(String message) { private Optional sourceRoot; /** - * The "Make" environment of this package, containing package-local - * definitions of "Make" variables. + * The "Make" environment of this package, containing package-local definitions of "Make" + * variables. */ private ImmutableMap makeEnv; @@ -293,9 +307,15 @@ public ImmutableMap getLoads() { *

{@code name} MUST be a suffix of {@code filename.getParentDirectory())}. */ private Package( - PackageIdentifier packageId, String workspaceName, boolean succinctTargetNotFoundErrors) { + PackageIdentifier packageId, + String workspaceName, + Optional associatedModuleName, + Optional associatedModuleVersion, + boolean succinctTargetNotFoundErrors) { this.packageIdentifier = packageId; this.workspaceName = workspaceName; + this.associatedModuleName = associatedModuleName; + this.associatedModuleVersion = associatedModuleVersion; this.succinctTargetNotFoundErrors = succinctTargetNotFoundErrors; } @@ -887,6 +907,8 @@ public static Builder newExternalPackageBuilder( helper, LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER, workspaceName, + /* associatedModuleName= */ Optional.empty(), + /* associatedModuleVersion= */ Optional.empty(), starlarkSemantics.getBool(BuildLanguageOptions.INCOMPATIBLE_NO_IMPLICIT_FILE_EXPORT), mainRepoMapping, mainRepoMapping) @@ -902,6 +924,8 @@ public static Builder newExternalPackageBuilderForBzlmod( DefaultPackageSettings.INSTANCE, basePackageId, DUMMY_WORKSPACE_NAME_FOR_BZLMOD_PACKAGES, + /* associatedModuleName= */ Optional.empty(), + /* associatedModuleVersion= */ Optional.empty(), starlarkSemantics.getBool(BuildLanguageOptions.INCOMPATIBLE_NO_IMPLICIT_FILE_EXPORT), repoMapping, // This mapping is *not* the main repository's mapping, but since it is only used to @@ -1115,10 +1139,18 @@ public T intern(T sample) { PackageSettings packageSettings, PackageIdentifier id, String workspaceName, + Optional associatedModuleName, + Optional associatedModuleVersion, boolean noImplicitFileExport, RepositoryMapping repositoryMapping, RepositoryMapping mainRepositoryMapping) { - this.pkg = new Package(id, workspaceName, packageSettings.succinctTargetNotFoundErrors()); + this.pkg = + new Package( + id, + workspaceName, + associatedModuleName, + associatedModuleVersion, + packageSettings.succinctTargetNotFoundErrors()); this.noImplicitFileExport = noImplicitFileExport; this.repositoryMapping = repositoryMapping; this.mainRepositoryMapping = mainRepositoryMapping; @@ -1144,6 +1176,24 @@ String getPackageWorkspaceName() { return pkg.getWorkspaceName(); } + /** + * Returns the name of the Bzlmod module associated with the repo this package is in. If this + * package is not from a Bzlmod repo, this is empty. For repos generated by module extensions, + * this is the name of the module hosting the extension. + */ + Optional getAssociatedModuleName() { + return pkg.associatedModuleName; + } + + /** + * Returns the version of the Bzlmod module associated with the repo this package is in. If this + * package is not from a Bzlmod repo, this is empty. For repos generated by module extensions, + * this is the version of the module hosting the extension. + */ + Optional getAssociatedModuleVersion() { + return pkg.associatedModuleVersion; + } + /** * Updates the externalPackageRepositoryMappings entry for {@code repoWithin}. Adds new entry * from {@code localName} to {@code mappedName} in {@code repoWithin}'s map. diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java index 3989b16e2c346a..4b9522da2c077a 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java @@ -52,6 +52,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.OptionalLong; import java.util.Set; import java.util.concurrent.ForkJoinPool; @@ -464,6 +465,8 @@ public Package.Builder newExternalPackageBuilder( public Package.Builder newPackageBuilder( PackageIdentifier packageId, String workspaceName, + Optional associatedModuleName, + Optional associatedModuleVersion, StarlarkSemantics starlarkSemantics, RepositoryMapping repositoryMapping, RepositoryMapping mainRepositoryMapping) { @@ -471,6 +474,8 @@ public Package.Builder newPackageBuilder( packageSettings, packageId, workspaceName, + associatedModuleName, + associatedModuleVersion, starlarkSemantics.getBool(BuildLanguageOptions.INCOMPATIBLE_NO_IMPLICIT_FILE_EXPORT), repositoryMapping, mainRepositoryMapping); diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeModule.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeModule.java index 4d1f7cc8b850ec..ae8902a2e9e9d3 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeModule.java +++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeModule.java @@ -635,6 +635,20 @@ public Label packageRelativeLabel(Object input, StarlarkThread thread) throws Ev } } + @Override + @Nullable + public String moduleName(StarlarkThread thread) throws EvalException { + BazelStarlarkContext.from(thread).checkLoadingPhase("native.module_name"); + return PackageFactory.getContext(thread).getBuilder().getAssociatedModuleName().orElse(null); + } + + @Override + @Nullable + public String moduleVersion(StarlarkThread thread) throws EvalException { + BazelStarlarkContext.from(thread).checkLoadingPhase("native.module_version"); + return PackageFactory.getContext(thread).getBuilder().getAssociatedModuleVersion().orElse(null); + } + private static Dict getRuleDict(Rule rule, Mutability mu) throws EvalException { Dict.Builder values = Dict.builder(); diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java index e0bded5e01f126..b52373016cd737 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java @@ -250,10 +250,6 @@ public SkyValue compute(SkyKey skyKey, Environment env) } Map overrides = REPOSITORY_OVERRIDES.get(env); - boolean doNotFetchUnconditionally = - DONT_FETCH_UNCONDITIONALLY.equals(DEPENDENCY_FOR_UNCONDITIONAL_FETCHING.get(env)); - boolean needsConfiguring = false; - Path repoRoot = RepositoryFunction.getExternalRepositoryDirectory(directories) .getRelative(repositoryName.getName()); @@ -264,7 +260,6 @@ public SkyValue compute(SkyKey skyKey, Environment env) } Rule rule = null; - if (starlarkSemantics.getBool(BuildLanguageOptions.ENABLE_BZLMOD)) { // Tries to get a repository rule instance from Bzlmod generated repos. SkyKey key = BzlmodRepoRuleValue.key(repositoryName); @@ -299,15 +294,18 @@ public SkyValue compute(SkyKey skyKey, Environment env) String.format("'%s' is not a repository rule", repositoryName.getCanonicalForm())); } + boolean needsConfiguring = false; if (handler.isConfigure(rule)) { needsConfiguring = !DONT_FETCH_UNCONDITIONALLY.equals(DEPENDENCY_FOR_UNCONDITIONAL_CONFIGURING.get(env)); } - if (env.valuesMissing()) { return null; } + DigestWriter digestWriter = new DigestWriter(directories, repositoryName, rule); + boolean doNotFetchUnconditionally = + DONT_FETCH_UNCONDITIONALLY.equals(DEPENDENCY_FOR_UNCONDITIONAL_FETCHING.get(env)); // Local repositories are fetched regardless of the marker file because the operation is // generally fast and they do not depend on non-local data, so it does not make much sense to diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index 43fde9cc68ae10..beeaa75a9c5599 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD @@ -284,8 +284,8 @@ java_library( "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:common", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:exception", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:module_extension", + "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:registry", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_creator", - "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_helper", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_value", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:resolution", "//src/main/java/com/google/devtools/build/lib/bazel/repository:repository_options", @@ -2215,6 +2215,7 @@ java_library( srcs = ["RepositoryMappingValue.java"], deps = [ ":sky_functions", + "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:common", "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/lib/concurrent", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec", diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java index 7485617678af6a..fe4977fe1e001b 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java @@ -14,21 +14,30 @@ package com.google.devtools.build.lib.skyframe; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.BlazeDirectories; -import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphValue; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleCreator; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleHelper; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; import com.google.devtools.build.lib.bazel.bzlmod.ModuleExtensionId; +import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue; +import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; +import com.google.devtools.build.lib.bazel.bzlmod.ModuleKey; +import com.google.devtools.build.lib.bazel.bzlmod.ModuleOverride; +import com.google.devtools.build.lib.bazel.bzlmod.NonRegistryOverride; +import com.google.devtools.build.lib.bazel.bzlmod.Registry; import com.google.devtools.build.lib.bazel.bzlmod.RepoSpec; import com.google.devtools.build.lib.bazel.bzlmod.SingleExtensionEvalValue; +import com.google.devtools.build.lib.bazel.bzlmod.SingleVersionOverride; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; +import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Rule; @@ -59,7 +68,7 @@ public final class BzlmodRepoRuleFunction implements SkyFunction { private final RuleClassProvider ruleClassProvider; private final BlazeDirectories directories; - private final BzlmodRepoRuleHelper bzlmodRepoRuleHelper; + /** * An empty repo mapping anchored to the main repo. * @@ -74,13 +83,9 @@ public final class BzlmodRepoRuleFunction implements SkyFunction { ImmutableMap.of("", RepositoryName.MAIN, "bazel_tools", RepositoryName.BAZEL_TOOLS), RepositoryName.MAIN); - public BzlmodRepoRuleFunction( - RuleClassProvider ruleClassProvider, - BlazeDirectories directories, - BzlmodRepoRuleHelper bzlmodRepoRuleHelper) { + public BzlmodRepoRuleFunction(RuleClassProvider ruleClassProvider, BlazeDirectories directories) { this.ruleClassProvider = ruleClassProvider; this.directories = directories; - this.bzlmodRepoRuleHelper = bzlmodRepoRuleHelper; } @Nullable @@ -92,30 +97,47 @@ public SkyValue compute(SkyKey skyKey, Environment env) return null; } + RootModuleFileValue root = + (RootModuleFileValue) env.getValue(ModuleFileValue.KEY_FOR_ROOT_MODULE); + if (env.valuesMissing()) { + return null; + } + RepositoryName repositoryName = ((BzlmodRepoRuleValue.Key) skyKey).argument(); + BazelDepGraphValue bazelDepGraphValue; + + // Try to find a module from this repository name. If not found, try to find + // an extension. If none found, it is an invalid name (return not found) // Look for the repo from Bazel module generated repos. try { - Optional result = bzlmodRepoRuleHelper.getRepoSpec(env, repositoryName); + // Step 1: Look for repositories defined by non-registry overrides. + Optional repoSpec = checkRepoFromNonRegistryOverrides(root, repositoryName); + if (repoSpec.isPresent()) { + return createRuleFromSpec(repoSpec.get(), starlarkSemantics, env); + } + + // BazelDepGraphValue is affected by repos found in Step 1, therefore it should NOT + // be requested in Step 1 to avoid cycle dependency. + bazelDepGraphValue = (BazelDepGraphValue) env.getValue(BazelDepGraphValue.KEY); if (env.valuesMissing()) { return null; } - if (result.isPresent()) { - return createRuleFromSpec(result.get(), starlarkSemantics, env); + + // Step 2: Look for repositories derived from Bazel Modules. + repoSpec = + checkRepoFromBazelModules( + bazelDepGraphValue, root.getOverrides(), env.getListener(), repositoryName); + if (repoSpec.isPresent()) { + return createRuleFromSpec(repoSpec.get(), starlarkSemantics, env); } } catch (IOException e) { throw new BzlmodRepoRuleFunctionException(e, Transience.PERSISTENT); } // Otherwise, look for the repo from module extension evaluation results. - BazelModuleResolutionValue moduleResolution = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (moduleResolution == null) { - return null; - } - Optional extensionId = - moduleResolution.getExtensionUniqueNames().entrySet().stream() + bazelDepGraphValue.getExtensionUniqueNames().entrySet().stream() .filter(e -> repositoryName.getName().startsWith(e.getValue() + "~")) .map(Entry::getKey) .findFirst(); @@ -140,6 +162,54 @@ public SkyValue compute(SkyKey skyKey, Environment env) return new BzlmodRepoRuleValue(pkg, repositoryName.getName()); } + private static Optional checkRepoFromNonRegistryOverrides( + RootModuleFileValue root, RepositoryName repositoryName) { + String moduleName = root.getNonRegistryOverrideCanonicalRepoNameLookup().get(repositoryName); + if (moduleName == null) { + return Optional.empty(); + } + NonRegistryOverride override = (NonRegistryOverride) root.getOverrides().get(moduleName); + return Optional.of(override.getRepoSpec(repositoryName)); + } + + private Optional checkRepoFromBazelModules( + BazelDepGraphValue bazelDepGraphValue, + ImmutableMap overrides, + ExtendedEventHandler eventListener, + RepositoryName repositoryName) + throws InterruptedException, IOException { + ModuleKey moduleKey = bazelDepGraphValue.getCanonicalRepoNameLookup().get(repositoryName); + if (moduleKey == null) { + return Optional.empty(); + } + com.google.devtools.build.lib.bazel.bzlmod.Module module = + bazelDepGraphValue.getDepGraph().get(moduleKey); + Registry registry = checkNotNull(module.getRegistry()); + RepoSpec repoSpec = registry.getRepoSpec(moduleKey, repositoryName, eventListener); + repoSpec = maybeAppendAdditionalPatches(repoSpec, overrides.get(moduleKey.getName())); + return Optional.of(repoSpec); + } + + private RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride override) { + if (!(override instanceof SingleVersionOverride)) { + return repoSpec; + } + SingleVersionOverride singleVersion = (SingleVersionOverride) override; + if (singleVersion.getPatches().isEmpty()) { + return repoSpec; + } + ImmutableMap.Builder attrBuilder = ImmutableMap.builder(); + attrBuilder.putAll(repoSpec.attributes()); + attrBuilder.put("patches", singleVersion.getPatches()); + attrBuilder.put("patch_cmds", singleVersion.getPatchCmds()); + attrBuilder.put("patch_args", ImmutableList.of("-p" + singleVersion.getPatchStrip())); + return RepoSpec.builder() + .setBzlFile(repoSpec.bzlFile()) + .setRuleClassName(repoSpec.ruleClassName()) + .setAttributes(attrBuilder.buildOrThrow()) + .build(); + } + @Nullable private BzlmodRepoRuleValue createRuleFromSpec( RepoSpec repoSpec, StarlarkSemantics starlarkSemantics, Environment env) @@ -161,6 +231,7 @@ private BzlmodRepoRuleValue createRuleFromSpec( } ruleClass = getStarlarkRuleClass(repoSpec, loadedModules); } + try { Rule rule = BzlmodRepoRuleCreator.createRule( diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java index a8e4ee4f94b2e6..4e8f3732eb466a 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java @@ -1348,6 +1348,8 @@ private LoadedPackage loadPackage( .newPackageBuilder( packageId, workspaceName, + repositoryMappingValue.getAssociatedModuleName(), + repositoryMappingValue.getAssociatedModuleVersion(), starlarkBuiltinsValue.starlarkSemantics, repositoryMapping, mainRepositoryMappingValue.getRepositoryMapping()) diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java index 93c972bdc3d615..457eb02212e25c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java @@ -24,7 +24,7 @@ import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.platform.PlatformInfo; import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils; -import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphValue; import com.google.devtools.build.lib.bazel.bzlmod.Module; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelConstants; @@ -162,18 +162,18 @@ private static ImmutableList getBzlmodExecutionPlatforms( if (!semantics.getBool(BuildLanguageOptions.ENABLE_BZLMOD)) { return ImmutableList.of(); } - BazelModuleResolutionValue bazelModuleResolutionValue = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (bazelModuleResolutionValue == null) { + BazelDepGraphValue bazelDepGraphValue = + (BazelDepGraphValue) env.getValue(BazelDepGraphValue.KEY); + if (bazelDepGraphValue == null) { return null; } ImmutableList.Builder executionPlatforms = ImmutableList.builder(); - for (Module module : bazelModuleResolutionValue.getDepGraph().values()) { + for (Module module : bazelDepGraphValue.getDepGraph().values()) { TargetPattern.Parser parser = new TargetPattern.Parser( PathFragment.EMPTY_FRAGMENT, module.getCanonicalRepoName(), - bazelModuleResolutionValue.getFullRepoMapping(module.getKey())); + bazelDepGraphValue.getFullRepoMapping(module.getKey())); for (String pattern : module.getExecutionPlatformsToRegister()) { try { executionPlatforms.add(parser.parse(pattern)); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java index cb2e3b51f3c0c9..f45e43b1ee1c33 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java @@ -24,7 +24,7 @@ import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.platform.DeclaredToolchainInfo; import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils; -import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphValue; import com.google.devtools.build.lib.bazel.bzlmod.ExternalDepsException; import com.google.devtools.build.lib.bazel.bzlmod.Module; import com.google.devtools.build.lib.cmdline.Label; @@ -151,18 +151,18 @@ private static ImmutableList getBzlmodToolchains( if (!semantics.getBool(BuildLanguageOptions.ENABLE_BZLMOD)) { return ImmutableList.of(); } - BazelModuleResolutionValue bazelModuleResolutionValue = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (bazelModuleResolutionValue == null) { + BazelDepGraphValue bazelDepGraphValue = + (BazelDepGraphValue) env.getValue(BazelDepGraphValue.KEY); + if (bazelDepGraphValue == null) { return null; } ImmutableList.Builder toolchains = ImmutableList.builder(); - for (Module module : bazelModuleResolutionValue.getDepGraph().values()) { + for (Module module : bazelDepGraphValue.getDepGraph().values()) { TargetPattern.Parser parser = new TargetPattern.Parser( PathFragment.EMPTY_FRAGMENT, module.getCanonicalRepoName(), - bazelModuleResolutionValue.getFullRepoMapping(module.getKey())); + bazelDepGraphValue.getFullRepoMapping(module.getKey())); for (String pattern : module.getToolchainsToRegister()) { try { toolchains.add(parser.parse(pattern)); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java index b75288426fa71f..36363780e1e1a0 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunction.java @@ -15,10 +15,12 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphValue; +import com.google.devtools.build.lib.bazel.bzlmod.Module; import com.google.devtools.build.lib.bazel.bzlmod.ModuleExtensionId; import com.google.devtools.build.lib.bazel.bzlmod.ModuleKey; import com.google.devtools.build.lib.bazel.bzlmod.SingleExtensionEvalValue; +import com.google.devtools.build.lib.bazel.bzlmod.Version; import com.google.devtools.build.lib.cmdline.LabelConstants; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; @@ -61,24 +63,26 @@ public SkyValue compute(SkyKey skyKey, Environment env) return null; } // We need to make sure that @_builtins maps to @_builtins too. - return RepositoryMappingValue.withMapping( + return RepositoryMappingValue.createForBzlmodRepo( RepositoryMapping.create( ImmutableMap.of( StarlarkBuiltinsValue.BUILTINS_NAME, StarlarkBuiltinsValue.BUILTINS_REPO, - // TODO(wyv): Google internal tests that have blzmod enabled fail because + // TODO(wyv): Google internal tests that have Bzlmod enabled fail because // they try to access cpp tools targets in the main repo from inside the // @_builtin repo. This is just a workaround and needs a proper way to // inject this mapping for google internal tests only. "", RepositoryName.MAIN), StarlarkBuiltinsValue.BUILTINS_REPO) - .withAdditionalMappings(bazelToolsMapping.getRepositoryMapping())); + .withAdditionalMappings(bazelToolsMapping.getRepositoryMapping()), + "bazel_tools", + Version.EMPTY); } - BazelModuleResolutionValue bazelModuleResolutionValue = - (BazelModuleResolutionValue) env.getValue(BazelModuleResolutionValue.KEY); - if (bazelModuleResolutionValue == null) { + BazelDepGraphValue bazelDepGraphValue = + (BazelDepGraphValue) env.getValue(BazelDepGraphValue.KEY); + if (bazelDepGraphValue == null) { return null; } @@ -101,26 +105,25 @@ public SkyValue compute(SkyKey skyKey, Environment env) .collect( Collectors.toMap( Entry::getKey, entry -> RepositoryName.createUnvalidated(entry.getKey()))); - return RepositoryMappingValue.withMapping( - computeForBazelModuleRepo(repositoryName, bazelModuleResolutionValue) - .get() - // For the transitional period, we need to map the workspace name to the main repo. - .withAdditionalMappings( - ImmutableMap.of( - externalPackageValue.getPackage().getWorkspaceName(), RepositoryName.MAIN)) - .withAdditionalMappings(additionalMappings)); + return computeForBazelModuleRepo(repositoryName, bazelDepGraphValue) + .get() + // For the transitional period, we need to map the workspace name to the main repo. + .withAdditionalMappings( + ImmutableMap.of( + externalPackageValue.getPackage().getWorkspaceName(), RepositoryName.MAIN)) + .withAdditionalMappings(additionalMappings); } // Try and see if this is a repo generated from a Bazel module. - Optional mapping = - computeForBazelModuleRepo(repositoryName, bazelModuleResolutionValue); - if (mapping.isPresent()) { - return RepositoryMappingValue.withMapping(mapping.get()); + Optional mappingValue = + computeForBazelModuleRepo(repositoryName, bazelDepGraphValue); + if (mappingValue.isPresent()) { + return mappingValue.get(); } // Now try and see if this is a repo generated from a module extension. Optional moduleExtensionId = - maybeGetModuleExtensionForRepo(repositoryName, bazelModuleResolutionValue); + maybeGetModuleExtensionForRepo(repositoryName, bazelDepGraphValue); if (moduleExtensionId.isPresent()) { SingleExtensionEvalValue extensionEvalValue = @@ -129,12 +132,8 @@ public SkyValue compute(SkyKey skyKey, Environment env) if (extensionEvalValue == null) { return null; } - return RepositoryMappingValue.withMapping( - computeForModuleExtensionRepo( - repositoryName, - moduleExtensionId.get(), - extensionEvalValue, - bazelModuleResolutionValue)); + return computeForModuleExtensionRepo( + repositoryName, moduleExtensionId.get(), extensionEvalValue, bazelDepGraphValue); } } @@ -157,53 +156,62 @@ public SkyValue compute(SkyKey skyKey, Environment env) } /** - * Calculate repo mappings for a repo generated from a Bazel module. Such a repo can see all its + * Calculates repo mappings for a repo generated from a Bazel module. Such a repo can see all its * {@code bazel_dep}s, as well as any repos generated by an extension it has a {@code use_repo} * clause for. * * @return the repo mappings for the repo if it's generated from a Bazel module, otherwise return * Optional.empty(). */ - private Optional computeForBazelModuleRepo( - RepositoryName repositoryName, BazelModuleResolutionValue bazelModuleResolutionValue) { - ModuleKey moduleKey = - bazelModuleResolutionValue.getCanonicalRepoNameLookup().get(repositoryName); + private Optional computeForBazelModuleRepo( + RepositoryName repositoryName, BazelDepGraphValue bazelDepGraphValue) { + ModuleKey moduleKey = bazelDepGraphValue.getCanonicalRepoNameLookup().get(repositoryName); if (moduleKey == null) { return Optional.empty(); } - return Optional.of(bazelModuleResolutionValue.getFullRepoMapping(moduleKey)); + Module module = bazelDepGraphValue.getDepGraph().get(moduleKey); + return Optional.of( + RepositoryMappingValue.createForBzlmodRepo( + bazelDepGraphValue.getFullRepoMapping(moduleKey), + module.getName(), + module.getVersion())); } /** - * Calculate repo mappings for a repo generated from a module extension. Such a repo can see all + * Calculates repo mappings for a repo generated from a module extension. Such a repo can see all * repos generated by the same module extension, as well as all repos that the Bazel module * hosting the extension can see (see above). - * - * @return the repo mappings for the repo if it's generated from a module extension, otherwise - * return Optional.empty(). */ - private RepositoryMapping computeForModuleExtensionRepo( + private RepositoryMappingValue computeForModuleExtensionRepo( RepositoryName repositoryName, ModuleExtensionId extensionId, SingleExtensionEvalValue extensionEvalValue, - BazelModuleResolutionValue bazelModuleResolutionValue) { + BazelDepGraphValue bazelDepGraphValue) { // Find the key of the module containing this extension. This will be used to compute additional // mappings -- any repo generated by an extension contained in the module "foo" can additionally // see all repos that "foo" can see. ModuleKey moduleKey = - bazelModuleResolutionValue + bazelDepGraphValue .getCanonicalRepoNameLookup() .get(extensionId.getBzlFileLabel().getRepository()); + Module module = bazelDepGraphValue.getDepGraph().get(moduleKey); // NOTE(wyv): This means that if "foo" has a bazel_dep with the repo name "bar", and the // extension generates an internal repo name "bar", then within a repo generated by the // extension, "bar" will refer to the latter. We should explore a way to differentiate between // the two to avoid any surprises. - return RepositoryMapping.create( - extensionEvalValue.getCanonicalRepoNameToInternalNames().inverse(), repositoryName) - .withAdditionalMappings(bazelModuleResolutionValue.getFullRepoMapping(moduleKey)); + return RepositoryMappingValue.createForBzlmodRepo( + RepositoryMapping.create( + extensionEvalValue.getCanonicalRepoNameToInternalNames().inverse(), repositoryName) + .withAdditionalMappings(bazelDepGraphValue.getFullRepoMapping(moduleKey)), + module.getName(), + module.getVersion()); } - private SkyValue computeFromWorkspace( + /** + * Calculate repo mappings for a repo generated from WORKSPACE. Such a repo is not subject to + * strict deps, and can additionally see all repos that the root module can see. + */ + private RepositoryMappingValue computeFromWorkspace( RepositoryName repositoryName, PackageValue externalPackageValue, @Nullable RepositoryMapping rootModuleRepoMapping) @@ -217,17 +225,18 @@ private SkyValue computeFromWorkspace( externalPackage.getRepositoryMapping(repositoryName)); if (rootModuleRepoMapping == null) { // This means Bzlmod is disabled. - return RepositoryMappingValue.withMapping(workspaceMapping); + return RepositoryMappingValue.createForWorkspaceRepo(workspaceMapping); } - // If Bzlmod is in play, we need to make sure that WORKSPACE repos see all repos that root + // If Bzlmod is in play, we need to make sure that WORKSPACE repos see all repos that the root // module can see, taking care to compose the existing WORKSPACE mapping with the main repo // mapping from Bzlmod. - return RepositoryMappingValue.withMapping(workspaceMapping.composeWith(rootModuleRepoMapping)); + return RepositoryMappingValue.createForWorkspaceRepo( + workspaceMapping.composeWith(rootModuleRepoMapping)); } private static Optional maybeGetModuleExtensionForRepo( - RepositoryName repositoryName, BazelModuleResolutionValue bazelModuleResolutionValue) { - return bazelModuleResolutionValue.getExtensionUniqueNames().entrySet().stream() + RepositoryName repositoryName, BazelDepGraphValue bazelDepGraphValue) { + return bazelDepGraphValue.getExtensionUniqueNames().entrySet().stream() .filter(e -> repositoryName.getName().startsWith(e.getValue() + "~")) .map(Entry::getKey) .findFirst(); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java index 1ed0f2f48e3dce..289e4947345760 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RepositoryMappingValue.java @@ -15,7 +15,7 @@ package com.google.devtools.build.lib.skyframe; import com.google.auto.value.AutoValue; -import com.google.common.base.Preconditions; +import com.google.devtools.build.lib.bazel.bzlmod.Version; import com.google.common.collect.Interner; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; @@ -26,7 +26,8 @@ import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; -import java.util.Objects; +import java.util.Map; +import java.util.Optional; /** * A value that represents the 'mappings' of an external Bazel workspace, as defined in the main @@ -50,53 +51,68 @@ * changes to things in the WORKSPACE other than the mappings (and name) won't require reloading all * packages. If the mappings are changed then the external packages need to be reloaded. */ -public class RepositoryMappingValue implements SkyValue { +@AutoValue +public abstract class RepositoryMappingValue implements SkyValue { public static final Key KEY_FOR_ROOT_MODULE_WITHOUT_WORKSPACE_REPOS = - Key.create(RepositoryName.MAIN, /*rootModuleShouldSeeWorkspaceRepos=*/ false); + Key.create(RepositoryName.MAIN, /* rootModuleShouldSeeWorkspaceRepos= */ false); public static final RepositoryMappingValue VALUE_FOR_ROOT_MODULE_WITHOUT_REPOS = - new RepositoryMappingValue(RepositoryMapping.ALWAYS_FALLBACK); + RepositoryMappingValue.createForWorkspaceRepo(RepositoryMapping.ALWAYS_FALLBACK); - private final RepositoryMapping repositoryMapping; - - private RepositoryMappingValue(RepositoryMapping repositoryMapping) { - Preconditions.checkNotNull(repositoryMapping); - this.repositoryMapping = repositoryMapping; + /** + * Returns a {@link RepositoryMappingValue} for a repo defined in MODULE.bazel, which has an + * associated module. + */ + public static RepositoryMappingValue createForBzlmodRepo( + RepositoryMapping repositoryMapping, + String associatedModuleName, + Version associatedModuleVersion) { + return new AutoValue_RepositoryMappingValue( + repositoryMapping, + Optional.of(associatedModuleName), + Optional.of(associatedModuleVersion.getOriginal())); } - /** Returns the workspace mappings. */ - public RepositoryMapping getRepositoryMapping() { - return repositoryMapping; + /** + * Returns a {@link RepositoryMappingValue} for a repo defined in WORKSPACE, which has no + * associated module. + */ + public static RepositoryMappingValue createForWorkspaceRepo(RepositoryMapping repositoryMapping) { + return new AutoValue_RepositoryMappingValue( + repositoryMapping, Optional.empty(), Optional.empty()); } - /** Returns the {@link Key} for {@link RepositoryMappingValue}s. */ - public static Key key(RepositoryName repositoryName) { - return RepositoryMappingValue.Key.create( - repositoryName, /*rootModuleShouldSeeWorkspaceRepos=*/ true); - } + public abstract RepositoryMapping getRepositoryMapping(); - /** Returns a {@link RepositoryMappingValue} for a workspace with the given name. */ - public static RepositoryMappingValue withMapping(RepositoryMapping repositoryMapping) { - return new RepositoryMappingValue(Preconditions.checkNotNull(repositoryMapping)); - } + /** + * Returns the name of the Bzlmod module associated with the requested repo. If the requested repo + * is defined in WORKSPACE, this is empty. For repos generated by module extensions, this is the + * name of the module hosting the extension. + */ + public abstract Optional getAssociatedModuleName(); - @Override - public boolean equals(Object o) { - if (!(o instanceof RepositoryMappingValue)) { - return false; - } - RepositoryMappingValue other = (RepositoryMappingValue) o; - return Objects.equals(repositoryMapping, other.repositoryMapping); - } + /** + * Returns the version of the Bzlmod module associated with the requested repo. If the requested + * repo is defined in WORKSPACE, this is empty. For repos generated by module extensions, this is + * the version of the module hosting the extension. + */ + public abstract Optional getAssociatedModuleVersion(); - @Override - public int hashCode() { - return Objects.hash(repositoryMapping); + /** + * Replaces the inner {@link #getRepositoryMapping() repository mapping} with one returned by + * calling its {@link RepositoryMapping#withAdditionalMappings} method. + */ + public final RepositoryMappingValue withAdditionalMappings(Map mappings) { + return new AutoValue_RepositoryMappingValue( + getRepositoryMapping().withAdditionalMappings(mappings), + getAssociatedModuleName(), + getAssociatedModuleVersion()); } - @Override - public String toString() { - return repositoryMapping.toString(); + /** Returns the {@link Key} for {@link RepositoryMappingValue}s. */ + public static Key key(RepositoryName repositoryName) { + return RepositoryMappingValue.Key.create( + repositoryName, /* rootModuleShouldSeeWorkspaceRepos= */ true); } /** {@link SkyKey} for {@link RepositoryMappingValue}. */ diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java index aadb01b42ac508..863a9d472976c3 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java @@ -151,6 +151,8 @@ public final class SkyFunctions { SkyFunctionName.createHermetic("SINGLE_EXTENSION_USAGES"); public static final SkyFunctionName SINGLE_EXTENSION_EVAL = SkyFunctionName.createNonHermetic("SINGLE_EXTENSION_EVAL"); + public static final SkyFunctionName BAZEL_DEP_GRAPH = + SkyFunctionName.createHermetic("BAZEL_DEP_GRAPH"); public static Predicate isSkyFunction(SkyFunctionName functionName) { return key -> key.functionName().equals(functionName); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java index 834db7ade29f73..cab49ab361b123 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java @@ -107,7 +107,6 @@ import com.google.devtools.build.lib.analysis.starlark.StarlarkBuildSettingsDetailsValue; import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition; import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleHelperImpl; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; import com.google.devtools.build.lib.bugreport.BugReport; import com.google.devtools.build.lib.bugreport.BugReporter; @@ -606,7 +605,7 @@ private ImmutableMap skyFunctions() { map.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction(externalPackageHelper)); map.put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction(ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())); + new BzlmodRepoRuleFunction(ruleClassProvider, directories)); map.put( SkyFunctions.TARGET_COMPLETION, TargetCompletor.targetCompletionFunction( diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java index 5682f70f798304..682d26c420cdf5 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/AbstractPackageLoader.java @@ -29,7 +29,6 @@ import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ServerDirectories; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleHelperImpl; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; import com.google.devtools.build.lib.clock.BlazeClock; import com.google.devtools.build.lib.cmdline.PackageIdentifier; @@ -500,8 +499,7 @@ public String getBaseNameForLoadedPackage(PackageIdentifier packageName) { .put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction(getExternalPackageHelper())) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) .put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction()) .put( SkyFunctions.PACKAGE, diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD index b6ea15117a81c2..fb19a8cc9aa4b5 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/packages/BUILD @@ -33,7 +33,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", "//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories", "//src/main/java/com/google/devtools/build/lib/analysis:server_directories", - "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_helper", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_value", "//src/main/java/com/google/devtools/build/lib/clock", "//src/main/java/com/google/devtools/build/lib/cmdline", diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkNativeModuleApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkNativeModuleApi.java index f61f0b993596e7..e23efd7389dd16 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkNativeModuleApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkNativeModuleApi.java @@ -16,6 +16,7 @@ import com.google.devtools.build.docgen.annot.DocCategory; import com.google.devtools.build.lib.cmdline.Label; +import javax.annotation.Nullable; import net.starlark.java.annot.Param; import net.starlark.java.annot.ParamType; import net.starlark.java.annot.StarlarkBuiltin; @@ -274,6 +275,32 @@ NoneType exportsFiles(Sequence srcs, Object visibility, Object licenses, Star useStarlarkThread = true) Label packageRelativeLabel(Object input, StarlarkThread thread) throws EvalException; + @StarlarkMethod( + name = "module_name", + doc = + "The name of the Bazel module associated with the repo this package is in. If this" + + " package is from a repo defined in WORKSPACE instead of MODULE.bazel, this is" + + " empty. For repos generated by module extensions, this is the name of the module" + + " hosting the extension. It's the same as the module.name field seen" + + " in module_ctx.modules.", + allowReturnNones = true, + useStarlarkThread = true) + @Nullable + String moduleName(StarlarkThread thread) throws EvalException; + + @StarlarkMethod( + name = "module_version", + doc = + "The version of the Bazel module associated with the repo this package is in. If this" + + " package is from a repo defined in WORKSPACE instead of MODULE.bazel, this is" + + " empty. For repos generated by module extensions, this is the version of the" + + " module hosting the extension. It's the same as the module.version" + + " field seen in module_ctx.modules.", + allowReturnNones = true, + useStarlarkThread = true) + @Nullable + String moduleVersion(StarlarkThread thread) throws EvalException; + @StarlarkMethod( name = "subpackages", doc = diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStarlarkNativeModuleApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStarlarkNativeModuleApi.java index e2e58aea15b662..44d58039cc1dfb 100644 --- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStarlarkNativeModuleApi.java +++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStarlarkNativeModuleApi.java @@ -83,6 +83,18 @@ public Label packageRelativeLabel(Object input, StarlarkThread thread) throws Ev return Label.parseCanonicalUnchecked("//:fake_label"); } + @Nullable + @Override + public String moduleName(StarlarkThread thread) throws EvalException { + return null; + } + + @Nullable + @Override + public String moduleVersion(StarlarkThread thread) throws EvalException { + return null; + } + @Override public Sequence subpackages( Sequence include, Sequence exclude, boolean allowEmpty, StarlarkThread thread) diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisMock.java index 55fca945220288..2501f17dc55937 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisMock.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisMock.java @@ -17,6 +17,7 @@ import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction; import com.google.devtools.build.lib.bazel.bzlmod.FakeRegistry; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileFunction; @@ -140,6 +141,8 @@ public ImmutableMap getSkyFunctions(BlazeDirectori FakeRegistry.DEFAULT_FACTORY, directories.getWorkspace(), getBuiltinModules(directories)), + SkyFunctions.BAZEL_DEP_GRAPH, + new BazelDepGraphFunction(), SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction(), SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD index 71844cb648f166..34491a53c96890 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD @@ -36,7 +36,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:inspection_impl", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:module_extension", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:registry", - "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_helper", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_value", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:resolution", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:resolution_impl", @@ -64,7 +63,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_function", "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value", "//src/main/java/com/google/devtools/build/lib/skyframe:repository_mapping_function", - "//src/main/java/com/google/devtools/build/lib/skyframe:repository_mapping_value", "//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions", "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster", "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/repository", diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java new file mode 100644 index 00000000000000..bdba9bca8400e3 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java @@ -0,0 +1,348 @@ +// Copyright 2022 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.google.devtools.build.lib.bazel.bzlmod; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping; +import static org.junit.Assert.fail; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.FileValue; +import com.google.devtools.build.lib.analysis.BlazeDirectories; +import com.google.devtools.build.lib.analysis.ServerDirectories; +import com.google.devtools.build.lib.analysis.util.AnalysisMock; +import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; +import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; +import com.google.devtools.build.lib.clock.BlazeClock; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.cmdline.RepositoryName; +import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants; +import com.google.devtools.build.lib.skyframe.ClientEnvironmentFunction; +import com.google.devtools.build.lib.skyframe.ExternalFilesHelper; +import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; +import com.google.devtools.build.lib.skyframe.FileFunction; +import com.google.devtools.build.lib.skyframe.FileStateFunction; +import com.google.devtools.build.lib.skyframe.PrecomputedFunction; +import com.google.devtools.build.lib.skyframe.PrecomputedValue; +import com.google.devtools.build.lib.skyframe.SkyFunctions; +import com.google.devtools.build.lib.testutil.FoundationTestCase; +import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; +import com.google.devtools.build.lib.vfs.FileStateKey; +import com.google.devtools.build.lib.vfs.Root; +import com.google.devtools.build.lib.vfs.SyscallCache; +import com.google.devtools.build.skyframe.EvaluationContext; +import com.google.devtools.build.skyframe.EvaluationResult; +import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; +import com.google.devtools.build.skyframe.MemoizingEvaluator; +import com.google.devtools.build.skyframe.RecordingDifferencer; +import com.google.devtools.build.skyframe.SequencedRecordingDifferencer; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyFunctionException; +import com.google.devtools.build.skyframe.SkyFunctionName; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nullable; +import net.starlark.java.eval.StarlarkSemantics; +import net.starlark.java.syntax.Location; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link BazelDepGraphFunction}. */ +@RunWith(JUnit4.class) +public class BazelDepGraphFunctionTest extends FoundationTestCase { + + private MemoizingEvaluator evaluator; + private RecordingDifferencer differencer; + private EvaluationContext evaluationContext; + private FakeRegistry.Factory registryFactory; + private BazelModuleResolutionFunctionMock resolutionFunctionMock; + + @Before + public void setup() throws Exception { + differencer = new SequencedRecordingDifferencer(); + registryFactory = new FakeRegistry.Factory(); + evaluationContext = + EvaluationContext.newBuilder().setNumThreads(8).setEventHandler(reporter).build(); + + AtomicReference packageLocator = + new AtomicReference<>( + new PathPackageLocator( + outputBase, + ImmutableList.of(Root.fromPath(rootDirectory)), + BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); + BlazeDirectories directories = + new BlazeDirectories( + new ServerDirectories(rootDirectory, outputBase, rootDirectory), + rootDirectory, + /* defaultSystemJavabase= */ null, + AnalysisMock.get().getProductName()); + ExternalFilesHelper externalFilesHelper = + ExternalFilesHelper.createForTesting( + packageLocator, + ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, + directories); + + resolutionFunctionMock = new BazelModuleResolutionFunctionMock(); + + evaluator = + new InMemoryMemoizingEvaluator( + ImmutableMap.builder() + .put(FileValue.FILE, new FileFunction(packageLocator, directories)) + .put( + FileStateKey.FILE_STATE, + new FileStateFunction( + Suppliers.ofInstance( + new TimestampGranularityMonitor(BlazeClock.instance())), + SyscallCache.NO_CACHE, + externalFilesHelper)) + .put( + SkyFunctions.MODULE_FILE, + new ModuleFileFunction(registryFactory, rootDirectory, ImmutableMap.of())) + .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()) + .put(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) + .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, resolutionFunctionMock) + .put( + SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, + new ClientEnvironmentFunction(new AtomicReference<>(ImmutableMap.of()))) + .buildOrThrow(), + differencer); + + PrecomputedValue.STARLARK_SEMANTICS.set( + differencer, + StarlarkSemantics.builder().setBool(BuildLanguageOptions.ENABLE_BZLMOD, true).build()); + ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, false); + ModuleFileFunction.MODULE_OVERRIDES.set(differencer, ImmutableMap.of()); + BazelModuleResolutionFunction.CHECK_DIRECT_DEPENDENCIES.set( + differencer, CheckDirectDepsMode.OFF); + BazelModuleResolutionFunction.BAZEL_COMPATIBILITY_MODE.set( + differencer, BazelCompatibilityMode.ERROR); + BazelModuleResolutionFunction.ALLOWED_YANKED_VERSIONS.set(differencer, ImmutableList.of()); + } + + @Test + public void createValue_basic() throws Exception { + // Root depends on dep@1.0 and dep@2.0 at the same time with a multiple-version override. + // Root also depends on rules_cc as a normal dep. + // dep@1.0 depends on rules_java, which is overridden by a non-registry override (see below). + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + ModuleKey.ROOT, + Module.builder() + .setName("my_root") + .setVersion(Version.parse("1.0")) + .setKey(ModuleKey.ROOT) + .addDep("my_dep_1", createModuleKey("dep", "1.0")) + .addDep("my_dep_2", createModuleKey("dep", "2.0")) + .addDep("rules_cc", createModuleKey("rules_cc", "1.0")) + .build()) + .put( + createModuleKey("dep", "1.0"), + Module.builder() + .setName("dep") + .setVersion(Version.parse("1.0")) + .setKey(createModuleKey("dep", "1.0")) + .addDep("rules_java", createModuleKey("rules_java", "")) + .build()) + .put( + createModuleKey("dep", "2.0"), + Module.builder() + .setName("dep") + .setVersion(Version.parse("2.0")) + .setKey(createModuleKey("dep", "2.0")) + .build()) + .put( + createModuleKey("rules_cc", "1.0"), + Module.builder() + .setName("rules_cc") + .setVersion(Version.parse("1.0")) + .setKey(createModuleKey("rules_cc", "1.0")) + .build()) + .put( + createModuleKey("rules_java", ""), + Module.builder() + .setName("rules_java") + .setVersion(Version.parse("1.0")) + .setKey(createModuleKey("rules_java", "")) + .build()) + .buildOrThrow(); + + // TODO we need to mock bazelModuleResolution function to return depGraph + resolutionFunctionMock.setDepGraph(depGraph); + EvaluationResult result = + evaluator.evaluate(ImmutableList.of(BazelDepGraphValue.KEY), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + BazelDepGraphValue value = result.get(BazelDepGraphValue.KEY); + assertThat(value.getCanonicalRepoNameLookup()) + .containsExactly( + RepositoryName.MAIN, + ModuleKey.ROOT, + RepositoryName.create("dep~1.0"), + createModuleKey("dep", "1.0"), + RepositoryName.create("dep~2.0"), + createModuleKey("dep", "2.0"), + RepositoryName.create("rules_cc~1.0"), + createModuleKey("rules_cc", "1.0"), + RepositoryName.create("rules_java~override"), + createModuleKey("rules_java", "")); + assertThat(value.getAbridgedModules()) + .containsExactlyElementsIn( + depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList())); + } + + private static ModuleExtensionUsage createModuleExtensionUsage( + String bzlFile, String name, String... imports) { + ImmutableBiMap.Builder importsBuilder = ImmutableBiMap.builder(); + for (int i = 0; i < imports.length; i += 2) { + importsBuilder.put(imports[i], imports[i + 1]); + } + return ModuleExtensionUsage.builder() + .setExtensionBzlFile(bzlFile) + .setExtensionName(name) + .setImports(importsBuilder.buildOrThrow()) + .setLocation(Location.BUILTIN) + .build(); + } + + @Test + public void createValue_moduleExtensions() throws Exception { + Module root = + Module.builder() + .setName("root") + .setVersion(Version.parse("1.0")) + .setKey(ModuleKey.ROOT) + .addDep("rje", createModuleKey("rules_jvm_external", "1.0")) + .addDep("rpy", createModuleKey("rules_python", "2.0")) + .addExtensionUsage( + createModuleExtensionUsage("@rje//:defs.bzl", "maven", "av", "autovalue")) + .addExtensionUsage( + createModuleExtensionUsage("@rpy//:defs.bzl", "pip", "numpy", "numpy")) + .build(); + ModuleKey depKey = createModuleKey("dep", "2.0"); + Module dep = + Module.builder() + .setName("dep") + .setVersion(Version.parse("2.0")) + .setKey(depKey) + .addDep("rules_python", createModuleKey("rules_python", "2.0")) + .addExtensionUsage( + createModuleExtensionUsage("@rules_python//:defs.bzl", "pip", "np", "numpy")) + .addExtensionUsage( + createModuleExtensionUsage("//:defs.bzl", "myext", "oneext", "myext")) + .addExtensionUsage( + createModuleExtensionUsage("//incredible:conflict.bzl", "myext", "twoext", "myext")) + .build(); + ImmutableMap depGraph = ImmutableMap.of(ModuleKey.ROOT, root, depKey, dep); + + ModuleExtensionId maven = + ModuleExtensionId.create( + Label.parseCanonical("@@rules_jvm_external~1.0//:defs.bzl"), "maven"); + ModuleExtensionId pip = + ModuleExtensionId.create(Label.parseCanonical("@@rules_python~2.0//:defs.bzl"), "pip"); + ModuleExtensionId myext = + ModuleExtensionId.create(Label.parseCanonical("@@dep~2.0//:defs.bzl"), "myext"); + ModuleExtensionId myext2 = + ModuleExtensionId.create( + Label.parseCanonical("@@dep~2.0//incredible:conflict.bzl"), "myext"); + + resolutionFunctionMock.setDepGraph(depGraph); + EvaluationResult result = + evaluator.evaluate(ImmutableList.of(BazelDepGraphValue.KEY), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + BazelDepGraphValue value = result.get(BazelDepGraphValue.KEY); + + assertThat(value.getExtensionUsagesTable()).hasSize(5); + assertThat(value.getExtensionUsagesTable()) + .containsCell(maven, ModuleKey.ROOT, root.getExtensionUsages().get(0)); + assertThat(value.getExtensionUsagesTable()) + .containsCell(pip, ModuleKey.ROOT, root.getExtensionUsages().get(1)); + assertThat(value.getExtensionUsagesTable()) + .containsCell(pip, depKey, dep.getExtensionUsages().get(0)); + assertThat(value.getExtensionUsagesTable()) + .containsCell(myext, depKey, dep.getExtensionUsages().get(1)); + assertThat(value.getExtensionUsagesTable()) + .containsCell(myext2, depKey, dep.getExtensionUsages().get(2)); + + assertThat(value.getExtensionUniqueNames()) + .containsExactly( + maven, "rules_jvm_external~1.0~maven", + pip, "rules_python~2.0~pip", + myext, "dep~2.0~myext", + myext2, "dep~2.0~myext2"); + + assertThat(value.getFullRepoMapping(ModuleKey.ROOT)) + .isEqualTo( + createRepositoryMapping( + ModuleKey.ROOT, + "", + "", + "root", + "", + "rje", + "rules_jvm_external~1.0", + "rpy", + "rules_python~2.0", + "av", + "rules_jvm_external~1.0~maven~autovalue", + "numpy", + "rules_python~2.0~pip~numpy")); + assertThat(value.getFullRepoMapping(depKey)) + .isEqualTo( + createRepositoryMapping( + depKey, + "dep", + "dep~2.0", + "rules_python", + "rules_python~2.0", + "np", + "rules_python~2.0~pip~numpy", + "oneext", + "dep~2.0~myext~myext", + "twoext", + "dep~2.0~myext2~myext")); + } + + private static class BazelModuleResolutionFunctionMock implements SkyFunction { + + private ImmutableMap depGraph = ImmutableMap.of(); + + public void setDepGraph(ImmutableMap depGraph) { + this.depGraph = depGraph; + } + + @Override + @Nullable + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + + return BazelModuleResolutionValue.create(depGraph, ImmutableMap.of()); + } + } +} diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java index 8ad8b3d995ea34..8d77b6622be04d 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java @@ -15,13 +15,10 @@ package com.google.devtools.build.lib.bazel.bzlmod; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; -import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping; import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.FileValue; @@ -32,8 +29,6 @@ import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; import com.google.devtools.build.lib.clock.BlazeClock; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; import com.google.devtools.build.lib.pkgcache.PathPackageLocator; import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants; @@ -62,7 +57,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import net.starlark.java.eval.StarlarkSemantics; -import net.starlark.java.syntax.Location; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -117,6 +111,7 @@ public void setup() throws Exception { SkyFunctions.MODULE_FILE, new ModuleFileFunction(registryFactory, rootDirectory, ImmutableMap.of())) .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()) + .put(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) .put( SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, @@ -136,187 +131,6 @@ public void setup() throws Exception { BazelModuleResolutionFunction.ALLOWED_YANKED_VERSIONS.set(differencer, ImmutableList.of()); } - @Test - public void createValue_basic() throws Exception { - // Root depends on dep@1.0 and dep@2.0 at the same time with a multiple-version override. - // Root also depends on rules_cc as a normal dep. - // dep@1.0 depends on rules_java, which is overridden by a non-registry override (see below). - ImmutableMap depGraph = - ImmutableMap.builder() - .put( - ModuleKey.ROOT, - Module.builder() - .setName("my_root") - .setVersion(Version.parse("1.0")) - .setKey(ModuleKey.ROOT) - .addDep("my_dep_1", createModuleKey("dep", "1.0")) - .addDep("my_dep_2", createModuleKey("dep", "2.0")) - .addDep("rules_cc", createModuleKey("rules_cc", "1.0")) - .build()) - .put( - createModuleKey("dep", "1.0"), - Module.builder() - .setName("dep") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("dep", "1.0")) - .addDep("rules_java", createModuleKey("rules_java", "")) - .build()) - .put( - createModuleKey("dep", "2.0"), - Module.builder() - .setName("dep") - .setVersion(Version.parse("2.0")) - .setKey(createModuleKey("dep", "2.0")) - .build()) - .put( - createModuleKey("rules_cc", "1.0"), - Module.builder() - .setName("rules_cc") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("rules_cc", "1.0")) - .build()) - .put( - createModuleKey("rules_java", ""), - Module.builder() - .setName("rules_java") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("rules_java", "")) - .build()) - .buildOrThrow(); - ImmutableMap overrides = - ImmutableMap.of( - "dep", - MultipleVersionOverride.create( - ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), ""), - "rules_java", LocalPathOverride.create("bleh")); - - BazelModuleResolutionValue value = - BazelModuleResolutionFunction.createValue(depGraph, depGraph, overrides); - assertThat(value.getCanonicalRepoNameLookup()) - .containsExactly( - RepositoryName.MAIN, - ModuleKey.ROOT, - RepositoryName.create("dep~1.0"), - createModuleKey("dep", "1.0"), - RepositoryName.create("dep~2.0"), - createModuleKey("dep", "2.0"), - RepositoryName.create("rules_cc~1.0"), - createModuleKey("rules_cc", "1.0"), - RepositoryName.create("rules_java~override"), - createModuleKey("rules_java", "")); - assertThat(value.getAbridgedModules()) - .containsExactlyElementsIn( - depGraph.values().stream().map(AbridgedModule::from).collect(toImmutableList())); - } - - private static ModuleExtensionUsage createModuleExtensionUsage( - String bzlFile, String name, String... imports) { - ImmutableBiMap.Builder importsBuilder = ImmutableBiMap.builder(); - for (int i = 0; i < imports.length; i += 2) { - importsBuilder.put(imports[i], imports[i + 1]); - } - return ModuleExtensionUsage.builder() - .setExtensionBzlFile(bzlFile) - .setExtensionName(name) - .setImports(importsBuilder.buildOrThrow()) - .setLocation(Location.BUILTIN) - .build(); - } - - @Test - public void createValue_moduleExtensions() throws Exception { - Module root = - Module.builder() - .setName("root") - .setVersion(Version.parse("1.0")) - .setKey(ModuleKey.ROOT) - .addDep("rje", createModuleKey("rules_jvm_external", "1.0")) - .addDep("rpy", createModuleKey("rules_python", "2.0")) - .addExtensionUsage( - createModuleExtensionUsage("@rje//:defs.bzl", "maven", "av", "autovalue")) - .addExtensionUsage( - createModuleExtensionUsage("@rpy//:defs.bzl", "pip", "numpy", "numpy")) - .build(); - ModuleKey depKey = createModuleKey("dep", "2.0"); - Module dep = - Module.builder() - .setName("dep") - .setVersion(Version.parse("2.0")) - .setKey(depKey) - .addDep("rules_python", createModuleKey("rules_python", "2.0")) - .addExtensionUsage( - createModuleExtensionUsage("@rules_python//:defs.bzl", "pip", "np", "numpy")) - .addExtensionUsage( - createModuleExtensionUsage("//:defs.bzl", "myext", "oneext", "myext")) - .addExtensionUsage( - createModuleExtensionUsage("//incredible:conflict.bzl", "myext", "twoext", "myext")) - .build(); - ImmutableMap depGraph = ImmutableMap.of(ModuleKey.ROOT, root, depKey, dep); - - ModuleExtensionId maven = - ModuleExtensionId.create( - Label.parseCanonical("@@rules_jvm_external~1.0//:defs.bzl"), "maven"); - ModuleExtensionId pip = - ModuleExtensionId.create(Label.parseCanonical("@@rules_python~2.0//:defs.bzl"), "pip"); - ModuleExtensionId myext = - ModuleExtensionId.create(Label.parseCanonical("@@dep~2.0//:defs.bzl"), "myext"); - ModuleExtensionId myext2 = - ModuleExtensionId.create( - Label.parseCanonical("@@dep~2.0//incredible:conflict.bzl"), "myext"); - - BazelModuleResolutionValue value = - BazelModuleResolutionFunction.createValue(depGraph, depGraph, ImmutableMap.of()); - assertThat(value.getExtensionUsagesTable()).hasSize(5); - assertThat(value.getExtensionUsagesTable()) - .containsCell(maven, ModuleKey.ROOT, root.getExtensionUsages().get(0)); - assertThat(value.getExtensionUsagesTable()) - .containsCell(pip, ModuleKey.ROOT, root.getExtensionUsages().get(1)); - assertThat(value.getExtensionUsagesTable()) - .containsCell(pip, depKey, dep.getExtensionUsages().get(0)); - assertThat(value.getExtensionUsagesTable()) - .containsCell(myext, depKey, dep.getExtensionUsages().get(1)); - assertThat(value.getExtensionUsagesTable()) - .containsCell(myext2, depKey, dep.getExtensionUsages().get(2)); - - assertThat(value.getExtensionUniqueNames()) - .containsExactly( - maven, "rules_jvm_external~1.0~maven", - pip, "rules_python~2.0~pip", - myext, "dep~2.0~myext", - myext2, "dep~2.0~myext2"); - - assertThat(value.getFullRepoMapping(ModuleKey.ROOT)) - .isEqualTo( - createRepositoryMapping( - ModuleKey.ROOT, - "", - "", - "root", - "", - "rje", - "rules_jvm_external~1.0", - "rpy", - "rules_python~2.0", - "av", - "rules_jvm_external~1.0~maven~autovalue", - "numpy", - "rules_python~2.0~pip~numpy")); - assertThat(value.getFullRepoMapping(depKey)) - .isEqualTo( - createRepositoryMapping( - depKey, - "dep", - "dep~2.0", - "rules_python", - "rules_python~2.0", - "np", - "rules_python~2.0~pip~numpy", - "oneext", - "dep~2.0~myext~myext", - "twoext", - "dep~2.0~myext2~myext")); - } - @Test public void testBazelInvalidCompatibility() throws Exception { scratch.file( diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleFunctionTest.java index 460a8702c3dbe0..37b92c3609dfcc 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleFunctionTest.java @@ -16,53 +16,40 @@ package com.google.devtools.build.lib.bazel.bzlmod; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; import static org.junit.Assert.fail; -import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.hash.HashFunction; import com.google.devtools.build.lib.actions.FileValue; -import com.google.devtools.build.lib.actions.ThreadStateReceiver; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ServerDirectories; import com.google.devtools.build.lib.analysis.util.AnalysisMock; +import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; +import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; import com.google.devtools.build.lib.bazel.repository.starlark.StarlarkRepositoryModule; import com.google.devtools.build.lib.clock.BlazeClock; -import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.lib.packages.PackageFactory; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.pkgcache.PathPackageLocator; import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants; -import com.google.devtools.build.lib.skyframe.BzlCompileFunction; -import com.google.devtools.build.lib.skyframe.BzlLoadFunction; import com.google.devtools.build.lib.skyframe.BzlmodRepoRuleFunction; -import com.google.devtools.build.lib.skyframe.ContainingPackageLookupFunction; +import com.google.devtools.build.lib.skyframe.ClientEnvironmentFunction; import com.google.devtools.build.lib.skyframe.ExternalFilesHelper; import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; import com.google.devtools.build.lib.skyframe.FileFunction; import com.google.devtools.build.lib.skyframe.FileStateFunction; -import com.google.devtools.build.lib.skyframe.IgnoredPackagePrefixesFunction; -import com.google.devtools.build.lib.skyframe.LocalRepositoryLookupFunction; -import com.google.devtools.build.lib.skyframe.PackageFunction; -import com.google.devtools.build.lib.skyframe.PackageFunction.GlobbingStrategy; -import com.google.devtools.build.lib.skyframe.PackageLookupFunction; -import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy; -import com.google.devtools.build.lib.skyframe.PrecomputedFunction; import com.google.devtools.build.lib.skyframe.PrecomputedValue; -import com.google.devtools.build.lib.skyframe.RepositoryMappingValue; import com.google.devtools.build.lib.skyframe.SkyFunctions; import com.google.devtools.build.lib.starlarkbuildapi.repository.RepositoryBootstrap; import com.google.devtools.build.lib.testutil.FoundationTestCase; import com.google.devtools.build.lib.testutil.TestRuleClassProvider; import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; import com.google.devtools.build.lib.vfs.FileStateKey; -import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.Root; import com.google.devtools.build.lib.vfs.SyscallCache; import com.google.devtools.build.skyframe.EvaluationContext; @@ -84,14 +71,19 @@ @RunWith(JUnit4.class) public final class BzlmodRepoRuleFunctionTest extends FoundationTestCase { + private Path workspaceRoot; private MemoizingEvaluator evaluator; - private final RecordingDifferencer differencer = new SequencedRecordingDifferencer(); + private RecordingDifferencer differencer; private EvaluationContext evaluationContext; + private FakeRegistry.Factory registryFactory; @Before public void setup() throws Exception { + workspaceRoot = scratch.dir("/ws"); + differencer = new SequencedRecordingDifferencer(); evaluationContext = EvaluationContext.newBuilder().setNumThreads(8).setEventHandler(reporter).build(); + registryFactory = new FakeRegistry.Factory(); AtomicReference packageLocator = new AtomicReference<>( new PathPackageLocator( @@ -117,12 +109,6 @@ public void setup() throws Exception { .addStarlarkBootstrap(new RepositoryBootstrap(new StarlarkRepositoryModule())); ConfiguredRuleClassProvider ruleClassProvider = builder.build(); - PackageFactory pkgFactory = - AnalysisMock.get() - .getPackageFactoryBuilderForTesting(directories) - .build(ruleClassProvider, fileSystem); - - HashFunction hashFunction = fileSystem.getDigestFunction().getHashFunction(); evaluator = new InMemoryMemoizingEvaluator( ImmutableMap.builder() @@ -136,204 +122,172 @@ public void setup() throws Exception { externalFilesHelper)) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, getFakeBzlmodRepoRuleHelper())) - .put( - SkyFunctions.LOCAL_REPOSITORY_LOOKUP, - new LocalRepositoryLookupFunction( - BazelSkyframeExecutorConstants.EXTERNAL_PACKAGE_HELPER)) - .put( - SkyFunctions.PACKAGE, - new PackageFunction( - /*packageFactory=*/ null, - /*pkgLocator=*/ null, - /*showLoadingProgress=*/ null, - /*numPackagesSuccessfullyLoaded=*/ null, - /*bzlLoadFunctionForInlining=*/ null, - /*packageProgress=*/ null, - PackageFunction.ActionOnIOExceptionReadingBuildFile.UseOriginalIOException - .INSTANCE, - GlobbingStrategy.SKYFRAME_HYBRID, - ignored -> ThreadStateReceiver.NULL_INSTANCE)) - .put( - SkyFunctions.PACKAGE_LOOKUP, - new PackageLookupFunction( - new AtomicReference<>(ImmutableSet.of()), - CrossRepositoryLabelViolationStrategy.ERROR, - BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY, - BazelSkyframeExecutorConstants.EXTERNAL_PACKAGE_HELPER)) - .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()) - .put(SkyFunctions.BZL_COMPILE, new BzlCompileFunction(pkgFactory, hashFunction)) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) + .put(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) + .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) .put( - SkyFunctions.BZL_LOAD, - BzlLoadFunction.create( - pkgFactory, directories, hashFunction, Caffeine.newBuilder().build())) + SkyFunctions.MODULE_FILE, + new ModuleFileFunction(registryFactory, workspaceRoot, ImmutableMap.of())) .put( - SkyFunctions.BAZEL_MODULE_RESOLUTION, - // Dummy function that returns a dep graph with just the root module in it. - (skyKey, env) -> - BazelModuleResolutionFunction.createValue( - ImmutableMap.of(ModuleKey.ROOT, Module.builder().build()), - ImmutableMap.of(ModuleKey.ROOT, Module.builder().build()), - ImmutableMap.of())) - .put( - SkyFunctions.REPOSITORY_MAPPING, - // Dummy function that always falls back. - (skyKey, env) -> - RepositoryMappingValue.withMapping(RepositoryMapping.ALWAYS_FALLBACK)) - .put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction()) - .put( - SkyFunctions.IGNORED_PACKAGE_PREFIXES, - new IgnoredPackagePrefixesFunction( - /*ignoredPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT)) - .build(), + SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, + new ClientEnvironmentFunction(new AtomicReference<>(ImmutableMap.of()))) + .buildOrThrow(), differencer); PrecomputedValue.STARLARK_SEMANTICS.set(differencer, StarlarkSemantics.DEFAULT); - PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, packageLocator.get()); - - setupRepoRules(); + ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, false); + ModuleFileFunction.MODULE_OVERRIDES.set(differencer, ImmutableMap.of()); + BazelModuleResolutionFunction.ALLOWED_YANKED_VERSIONS.set(differencer, ImmutableList.of()); + BazelModuleResolutionFunction.CHECK_DIRECT_DEPENDENCIES.set( + differencer, CheckDirectDepsMode.WARNING); + BazelModuleResolutionFunction.BAZEL_COMPATIBILITY_MODE.set( + differencer, BazelCompatibilityMode.ERROR); } - private void setupRepoRules() throws Exception { - scratch.file(rootDirectory.getRelative("tools/build_defs/repo/BUILD").getPathString()); - scratch.file( - rootDirectory.getRelative("tools/build_defs/repo/http.bzl").getPathString(), - "def _http_archive_impl(ctx): pass", - "", - "http_archive = repository_rule(", - " implementation = _http_archive_impl,", - " attrs = {", - " \"url\": attr.string(),", - " \"sha256\": attr.string(),", - " })"); - scratch.file(rootDirectory.getRelative("maven/BUILD").getPathString()); + @Test + public void testRepoSpec_bazelModule() throws Exception { scratch.file( - rootDirectory.getRelative("maven/repo.bzl").getPathString(), - "def _maven_repo_impl(ctx): pass", - "", - "maven_repo = repository_rule(", - " implementation = _maven_repo_impl,", - " attrs = {", - " \"artifacts\": attr.string_list(),", - " \"repositories\": attr.string_list(),", - " })"); - } + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='aaa',version='0.1')", + "bazel_dep(name='bbb',version='1.0')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry("/usr/local/modules") + .addModule( + createModuleKey("bbb", "1.0"), + "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") + .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + RepositoryName repo = RepositoryName.create("ccc~2.0"); + EvaluationResult result = + evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(repo)), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(repo)); + Rule repoRule = bzlmodRepoRuleValue.getRule(); - private static FakeBzlmodRepoRuleHelper getFakeBzlmodRepoRuleHelper() { - ImmutableMap.Builder repoSpecs = ImmutableMap.builder(); - repoSpecs - // repos from non-registry overrides - .put( - RepositoryName.createUnvalidated("A"), - RepoSpec.builder() - .setRuleClassName("local_repository") - .setAttributes( - ImmutableMap.of( - "name", "A", - "path", "/foo/bar/A")) - .build()) - // repos from Bazel modules - .put( - RepositoryName.createUnvalidated("B"), - RepoSpec.builder() - .setBzlFile( - // In real world, this will be @bazel_tools//tools/build_defs/repo:http.bzl, - "//tools/build_defs/repo:http.bzl") - .setRuleClassName("http_archive") - .setAttributes( - ImmutableMap.of( - "name", "B", - "url", "https://foo/bar/B.zip", - "sha256", "1234abcd")) - .build()) - // repos from module rules - .put( - RepositoryName.createUnvalidated("C"), - RepoSpec.builder() - .setBzlFile("//maven:repo.bzl") - .setRuleClassName("maven_repo") - .setAttributes( - ImmutableMap.of( - "name", "C", - "artifacts", - ImmutableList.of("junit:junit:4.12", "com.google.guava:guava:19.0"), - "repositories", - ImmutableList.of( - "https://maven.google.com", "https://repo1.maven.org/maven2"))) - .build()); - return new FakeBzlmodRepoRuleHelper(repoSpecs.buildOrThrow()); + assertThat(repoRule.getRuleClassObject().isStarlark()).isFalse(); + assertThat(repoRule.getRuleClass()).isEqualTo("local_repository"); + assertThat(repoRule.getName()).isEqualTo("ccc~2.0"); + assertThat(repoRule.getAttr("path", Type.STRING)).isEqualTo("/usr/local/modules/ccc~2.0"); } @Test - public void createRepoRule_overrides() throws Exception { - RepositoryName a = RepositoryName.create("A"); + public void testRepoSpec_nonRegistryOverride() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='aaa',version='0.1')", + "bazel_dep(name='bbb',version='1.0')", + "local_path_override(module_name='ccc',path='/foo/bar/C')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry("/usr/local/modules") + .addModule( + createModuleKey("bbb", "1.0"), + "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") + .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + RepositoryName repo = RepositoryName.create("ccc~override"); EvaluationResult result = - evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(a)), evaluationContext); + evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(repo)), evaluationContext); if (result.hasError()) { fail(result.getError().toString()); } - BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(a)); + BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(repo)); Rule repoRule = bzlmodRepoRuleValue.getRule(); assertThat(repoRule.getRuleClassObject().isStarlark()).isFalse(); assertThat(repoRule.getRuleClass()).isEqualTo("local_repository"); - assertThat(repoRule.getName()).isEqualTo("A"); - assertThat(repoRule.getAttr("path", Type.STRING)).isEqualTo("/foo/bar/A"); + assertThat(repoRule.getName()).isEqualTo("ccc~override"); + assertThat(repoRule.getAttr("path", Type.STRING)).isEqualTo("/foo/bar/C"); } @Test - public void createRepoRule_bazelModules() throws Exception { - RepositoryName b = RepositoryName.create("B"); - // Using a starlark rule in a RepoSpec requires having run Selection first. - evaluator.evaluate(ImmutableList.of(BazelModuleResolutionValue.KEY), evaluationContext); + public void testRepoSpec_singleVersionOverride() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='aaa',version='0.1')", + "bazel_dep(name='bbb',version='1.0')", + "single_version_override(", + " module_name='ccc',version='3.0')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry("/usr/local/modules") + .addModule( + createModuleKey("bbb", "1.0"), + "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") + .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')") + .addModule(createModuleKey("ccc", "3.0"), "module(name='ccc', version='3.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + RepositoryName repo = RepositoryName.create("ccc~3.0"); EvaluationResult result = - evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(b)), evaluationContext); + evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(repo)), evaluationContext); if (result.hasError()) { fail(result.getError().toString()); } - BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(b)); + BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(repo)); Rule repoRule = bzlmodRepoRuleValue.getRule(); - assertThat(repoRule.getRuleClassObject().isStarlark()).isTrue(); - assertThat(repoRule.getRuleClass()).isEqualTo("http_archive"); - assertThat(repoRule.getName()).isEqualTo("B"); - assertThat(repoRule.getAttr("url", Type.STRING)).isEqualTo("https://foo/bar/B.zip"); - assertThat(repoRule.getAttr("sha256", Type.STRING)).isEqualTo("1234abcd"); + assertThat(repoRule.getRuleClassObject().isStarlark()).isFalse(); + assertThat(repoRule.getRuleClass()).isEqualTo("local_repository"); + assertThat(repoRule.getName()).isEqualTo("ccc~3.0"); + assertThat(repoRule.getAttr("path", Type.STRING)).isEqualTo("/usr/local/modules/ccc~3.0"); } @Test - public void createRepoRule_moduleRules() throws Exception { - RepositoryName c = RepositoryName.create("C"); - // Using a starlark rule in a RepoSpec requires having run Selection first. - evaluator.evaluate(ImmutableList.of(BazelModuleResolutionValue.KEY), evaluationContext); + public void testRepoSpec_multipleVersionOverride() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='aaa',version='0.1')", + "bazel_dep(name='bbb',version='1.0')", + "bazel_dep(name='ccc',version='2.0')", + "multiple_version_override(module_name='ddd',versions=['1.0','2.0'])"); + FakeRegistry registry = + registryFactory + .newFakeRegistry("/usr/local/modules") + .addModule( + createModuleKey("bbb", "1.0"), + "module(name='bbb', version='1.0');bazel_dep(name='ddd',version='1.0')") + .addModule( + createModuleKey("ccc", "2.0"), + "module(name='ccc', version='2.0');bazel_dep(name='ddd',version='2.0')") + .addModule(createModuleKey("ddd", "1.0"), "module(name='ddd', version='1.0')") + .addModule(createModuleKey("ddd", "2.0"), "module(name='ddd', version='2.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + RepositoryName repo = RepositoryName.create("ddd~2.0"); EvaluationResult result = - evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(c)), evaluationContext); + evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(repo)), evaluationContext); if (result.hasError()) { fail(result.getError().toString()); } - BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(c)); + BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(repo)); Rule repoRule = bzlmodRepoRuleValue.getRule(); - assertThat(repoRule.getRuleClassObject().isStarlark()).isTrue(); - assertThat(repoRule.getRuleClass()).isEqualTo("maven_repo"); - assertThat(repoRule.getName()).isEqualTo("C"); - assertThat(repoRule.getAttr("artifacts", Type.STRING_LIST)) - .isEqualTo(ImmutableList.of("junit:junit:4.12", "com.google.guava:guava:19.0")); - assertThat(repoRule.getAttr("repositories", Type.STRING_LIST)) - .isEqualTo(ImmutableList.of("https://maven.google.com", "https://repo1.maven.org/maven2")); + assertThat(repoRule.getRuleClassObject().isStarlark()).isFalse(); + assertThat(repoRule.getRuleClass()).isEqualTo("local_repository"); + assertThat(repoRule.getName()).isEqualTo("ddd~2.0"); + assertThat(repoRule.getAttr("path", Type.STRING)).isEqualTo("/usr/local/modules/ddd~2.0"); } @Test - public void createRepoRule_notFound() throws Exception { - RepositoryName unknown = RepositoryName.create("unknown"); + public void testRepoSpec_notFound() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='aaa',version='0.1')"); + + RepositoryName repo = RepositoryName.create("ss"); EvaluationResult result = - evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(unknown)), evaluationContext); + evaluator.evaluate(ImmutableList.of(BzlmodRepoRuleValue.key(repo)), evaluationContext); if (result.hasError()) { fail(result.getError().toString()); } - BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(unknown)); - + BzlmodRepoRuleValue bzlmodRepoRuleValue = result.get(BzlmodRepoRuleValue.key(repo)); assertThat(bzlmodRepoRuleValue).isEqualTo(BzlmodRepoRuleValue.REPO_RULE_NOT_FOUND_VALUE); } + } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java deleted file mode 100644 index eece0350e8b8d9..00000000000000 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2021 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.google.devtools.build.lib.bazel.bzlmod; - -import static com.google.common.truth.Truth8.assertThat; -import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; -import static org.junit.Assert.fail; - -import com.google.auto.value.AutoValue; -import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.actions.FileValue; -import com.google.devtools.build.lib.analysis.BlazeDirectories; -import com.google.devtools.build.lib.analysis.ServerDirectories; -import com.google.devtools.build.lib.analysis.util.AnalysisMock; -import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; -import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; -import com.google.devtools.build.lib.clock.BlazeClock; -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.lib.pkgcache.PathPackageLocator; -import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants; -import com.google.devtools.build.lib.skyframe.ClientEnvironmentFunction; -import com.google.devtools.build.lib.skyframe.ExternalFilesHelper; -import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; -import com.google.devtools.build.lib.skyframe.FileFunction; -import com.google.devtools.build.lib.skyframe.FileStateFunction; -import com.google.devtools.build.lib.skyframe.PrecomputedFunction; -import com.google.devtools.build.lib.skyframe.PrecomputedValue; -import com.google.devtools.build.lib.skyframe.SkyFunctions; -import com.google.devtools.build.lib.testutil.FoundationTestCase; -import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; -import com.google.devtools.build.lib.vfs.FileStateKey; -import com.google.devtools.build.lib.vfs.Path; -import com.google.devtools.build.lib.vfs.Root; -import com.google.devtools.build.lib.vfs.SyscallCache; -import com.google.devtools.build.skyframe.AbstractSkyKey; -import com.google.devtools.build.skyframe.EvaluationContext; -import com.google.devtools.build.skyframe.EvaluationResult; -import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; -import com.google.devtools.build.skyframe.MemoizingEvaluator; -import com.google.devtools.build.skyframe.RecordingDifferencer; -import com.google.devtools.build.skyframe.SequencedRecordingDifferencer; -import com.google.devtools.build.skyframe.SkyFunction; -import com.google.devtools.build.skyframe.SkyFunctionException; -import com.google.devtools.build.skyframe.SkyFunctionException.Transience; -import com.google.devtools.build.skyframe.SkyFunctionName; -import com.google.devtools.build.skyframe.SkyKey; -import com.google.devtools.build.skyframe.SkyValue; -import java.io.IOException; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import javax.annotation.Nullable; -import net.starlark.java.eval.StarlarkSemantics; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link BzlmodRepoRuleHelperImpl}. */ -@RunWith(JUnit4.class) -public final class BzlmodRepoRuleHelperTest extends FoundationTestCase { - - private Path workspaceRoot; - private MemoizingEvaluator evaluator; - private RecordingDifferencer differencer; - private EvaluationContext evaluationContext; - private FakeRegistry.Factory registryFactory; - - @Before - public void setup() throws Exception { - workspaceRoot = scratch.dir("/ws"); - differencer = new SequencedRecordingDifferencer(); - evaluationContext = - EvaluationContext.newBuilder().setNumThreads(8).setEventHandler(reporter).build(); - registryFactory = new FakeRegistry.Factory(); - AtomicReference packageLocator = - new AtomicReference<>( - new PathPackageLocator( - outputBase, - ImmutableList.of(Root.fromPath(rootDirectory)), - BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); - BlazeDirectories directories = - new BlazeDirectories( - new ServerDirectories(rootDirectory, outputBase, rootDirectory), - rootDirectory, - /* defaultSystemJavabase= */ null, - AnalysisMock.get().getProductName()); - ExternalFilesHelper externalFilesHelper = - ExternalFilesHelper.createForTesting( - packageLocator, - ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, - directories); - - evaluator = - new InMemoryMemoizingEvaluator( - ImmutableMap.builder() - .put(FileValue.FILE, new FileFunction(packageLocator, directories)) - .put( - FileStateKey.FILE_STATE, - new FileStateFunction( - Suppliers.ofInstance( - new TimestampGranularityMonitor(BlazeClock.instance())), - SyscallCache.NO_CACHE, - externalFilesHelper)) - .put( - SkyFunctions.MODULE_FILE, - new ModuleFileFunction(registryFactory, workspaceRoot, ImmutableMap.of())) - .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) - .put( - GET_REPO_SPEC_BY_NAME_FUNCTION, - new GetRepoSpecByNameFunction(new BzlmodRepoRuleHelperImpl())) - .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()) - .put( - SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, - new ClientEnvironmentFunction(new AtomicReference<>(ImmutableMap.of()))) - .buildOrThrow(), - differencer); - - PrecomputedValue.STARLARK_SEMANTICS.set(differencer, StarlarkSemantics.DEFAULT); - ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, false); - ModuleFileFunction.MODULE_OVERRIDES.set(differencer, ImmutableMap.of()); - BazelModuleResolutionFunction.ALLOWED_YANKED_VERSIONS.set(differencer, ImmutableList.of()); - BazelModuleResolutionFunction.CHECK_DIRECT_DEPENDENCIES.set( - differencer, CheckDirectDepsMode.WARNING); - BazelModuleResolutionFunction.BAZEL_COMPATIBILITY_MODE.set( - differencer, BazelCompatibilityMode.ERROR); - } - - @Test - public void getRepoSpec_bazelModule() throws Exception { - scratch.file( - workspaceRoot.getRelative("MODULE.bazel").getPathString(), - "module(name='aaa',version='0.1')", - "bazel_dep(name='bbb',version='1.0')"); - FakeRegistry registry = - registryFactory - .newFakeRegistry("/usr/local/modules") - .addModule( - createModuleKey("bbb", "1.0"), - "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") - .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')"); - ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); - - EvaluationResult result = - evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("ccc~2.0")), evaluationContext); - if (result.hasError()) { - fail(result.getError().toString()); - } - - Optional repoSpec = result.get(getRepoSpecByNameKey("ccc~2.0")).rule(); - assertThat(repoSpec) - .hasValue( - RepoSpec.builder() - .setRuleClassName("local_repository") - .setAttributes( - ImmutableMap.of("name", "ccc~2.0", "path", "/usr/local/modules/ccc~2.0")) - .build()); - } - - @Test - public void getRepoSpec_nonRegistryOverride() throws Exception { - scratch.file( - workspaceRoot.getRelative("MODULE.bazel").getPathString(), - "module(name='aaa',version='0.1')", - "bazel_dep(name='bbb',version='1.0')", - "local_path_override(module_name='ccc',path='/foo/bar/C')"); - FakeRegistry registry = - registryFactory - .newFakeRegistry("/usr/local/modules") - .addModule( - createModuleKey("bbb", "1.0"), - "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") - .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')"); - ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); - - EvaluationResult result = - evaluator.evaluate( - ImmutableList.of(getRepoSpecByNameKey("ccc~override")), evaluationContext); - if (result.hasError()) { - fail(result.getError().toString()); - } - - Optional repoSpec = result.get(getRepoSpecByNameKey("ccc~override")).rule(); - assertThat(repoSpec) - .hasValue( - RepoSpec.builder() - .setRuleClassName("local_repository") - .setAttributes( - ImmutableMap.of( - "name", "ccc~override", - "path", "/foo/bar/C")) - .build()); - } - - @Test - public void getRepoSpec_singleVersionOverride() throws Exception { - scratch.file( - workspaceRoot.getRelative("MODULE.bazel").getPathString(), - "module(name='aaa',version='0.1')", - "bazel_dep(name='bbb',version='1.0')", - "single_version_override(", - " module_name='ccc',version='3.0',patches=['//:foo.patch'], patch_cmds=['echo hi']," - + " patch_strip=1)"); - FakeRegistry registry = - registryFactory - .newFakeRegistry("/usr/local/modules") - .addModule( - createModuleKey("bbb", "1.0"), - "module(name='bbb', version='1.0');bazel_dep(name='ccc',version='2.0')") - .addModule(createModuleKey("ccc", "2.0"), "module(name='ccc', version='2.0')") - .addModule(createModuleKey("ccc", "3.0"), "module(name='ccc', version='3.0')"); - ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); - - EvaluationResult result = - evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("ccc~3.0")), evaluationContext); - if (result.hasError()) { - fail(result.getError().toString()); - } - - Optional repoSpec = result.get(getRepoSpecByNameKey("ccc~3.0")).rule(); - assertThat(repoSpec) - .hasValue( - RepoSpec.builder() - // This obviously wouldn't work in the real world since local_repository doesn't - // support patches -- but in the real world, registries also don't use - // local_repository. - .setRuleClassName("local_repository") - .setAttributes( - ImmutableMap.of( - "name", - "ccc~3.0", - "path", - "/usr/local/modules/ccc~3.0", - "patches", - ImmutableList.of("//:foo.patch"), - "patch_cmds", - ImmutableList.of("echo hi"), - "patch_args", - ImmutableList.of("-p1"))) - .build()); - } - - @Test - public void getRepoSpec_multipleVersionOverride() throws Exception { - scratch.file( - workspaceRoot.getRelative("MODULE.bazel").getPathString(), - "module(name='aaa',version='0.1')", - "bazel_dep(name='bbb',version='1.0')", - "bazel_dep(name='ccc',version='2.0')", - "multiple_version_override(module_name='ddd',versions=['1.0','2.0'])"); - FakeRegistry registry = - registryFactory - .newFakeRegistry("/usr/local/modules") - .addModule( - createModuleKey("bbb", "1.0"), - "module(name='bbb', version='1.0');bazel_dep(name='ddd',version='1.0')") - .addModule( - createModuleKey("ccc", "2.0"), - "module(name='ccc', version='2.0');bazel_dep(name='ddd',version='2.0')") - .addModule(createModuleKey("ddd", "1.0"), "module(name='ddd', version='1.0')") - .addModule(createModuleKey("ddd", "2.0"), "module(name='ddd', version='2.0')"); - ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); - - EvaluationResult result = - evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("ddd~2.0")), evaluationContext); - if (result.hasError()) { - fail(result.getError().toString()); - } - - Optional repoSpec = result.get(getRepoSpecByNameKey("ddd~2.0")).rule(); - assertThat(repoSpec) - .hasValue( - RepoSpec.builder() - .setRuleClassName("local_repository") - .setAttributes( - ImmutableMap.of("name", "ddd~2.0", "path", "/usr/local/modules/ddd~2.0")) - .build()); - } - - @Test - public void getRepoSpec_notFound() throws Exception { - scratch.file( - workspaceRoot.getRelative("MODULE.bazel").getPathString(), - "module(name='aaa',version='0.1')", - "bazel_dep(name='bbb',version='1.0')"); - FakeRegistry registry = - registryFactory - .newFakeRegistry("/usr/local/modules") - .addModule(createModuleKey("bbb", "1.0"), "module(name='bbb', version='1.0')"); - ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); - - EvaluationResult result = - evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C")), evaluationContext); - if (result.hasError()) { - fail(result.getError().toString()); - } - - Optional repoSpec = result.get(getRepoSpecByNameKey("C")).rule(); - assertThat(repoSpec).isEmpty(); - } - - /** A helper SkyFunction to invoke BzlmodRepoRuleHelper */ - private static final SkyFunctionName GET_REPO_SPEC_BY_NAME_FUNCTION = - SkyFunctionName.createHermetic("GET_REPO_SPEC_BY_NAME_FUNCTION"); - - @AutoValue - abstract static class GetRepoSpecByNameValue implements SkyValue { - abstract Optional rule(); - - static GetRepoSpecByNameValue create(Optional rule) { - return new AutoValue_BzlmodRepoRuleHelperTest_GetRepoSpecByNameValue(rule); - } - } - - private static final class GetRepoSpecByNameFunction implements SkyFunction { - private final BzlmodRepoRuleHelper bzlmodRepoRuleHelper; - - GetRepoSpecByNameFunction(BzlmodRepoRuleHelper bzlmodRepoRuleHelper) { - this.bzlmodRepoRuleHelper = bzlmodRepoRuleHelper; - } - - @Nullable - @Override - public SkyValue compute(SkyKey skyKey, Environment env) - throws SkyFunctionException, InterruptedException { - RepositoryName repositoryName = (RepositoryName) skyKey.argument(); - Optional result; - try { - result = bzlmodRepoRuleHelper.getRepoSpec(env, repositoryName); - if (env.valuesMissing()) { - return null; - } - } catch (IOException e) { - throw new GetRepoSpecByNameFunctionException(e, Transience.PERSISTENT); - } - return GetRepoSpecByNameValue.create(result); - } - } - - private static final class Key extends AbstractSkyKey { - private Key(RepositoryName arg) { - super(arg); - } - - @Override - public SkyFunctionName functionName() { - return GET_REPO_SPEC_BY_NAME_FUNCTION; - } - } - - private static final class GetRepoSpecByNameFunctionException extends SkyFunctionException { - GetRepoSpecByNameFunctionException(IOException e, Transience transience) { - super(e, transience); - } - } - - private static SkyKey getRepoSpecByNameKey(String repositoryName) { - return new Key(RepositoryName.createUnvalidated(repositoryName)); - } -} diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java index 40bf5144d2e318..94fa9f1dae216f 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java @@ -177,8 +177,7 @@ private void setUpWithBuiltinModules(ImmutableMap b BazelSkyframeExecutorConstants.EXTERNAL_PACKAGE_HELPER)) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) .buildOrThrow(), differencer); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeBzlmodRepoRuleHelper.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeBzlmodRepoRuleHelper.java deleted file mode 100644 index 575ab67cb2de7c..00000000000000 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeBzlmodRepoRuleHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021 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.google.devtools.build.lib.bazel.bzlmod; - -import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.skyframe.SkyFunction.Environment; -import java.util.Optional; - -/** A fake {@link BzlmodRepoRuleHelper} */ -public final class FakeBzlmodRepoRuleHelper implements BzlmodRepoRuleHelper { - - private final ImmutableMap repoSpecs; - - FakeBzlmodRepoRuleHelper(ImmutableMap repoSpecs) { - this.repoSpecs = repoSpecs; - } - - @Override - public Optional getRepoSpec(Environment env, RepositoryName repositoryName) { - return Optional.ofNullable(repoSpecs.get(repositoryName)); - } -} diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java index 20479b33349a04..f8ad86388377d7 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java @@ -196,12 +196,12 @@ public void setup() throws Exception { .put( SkyFunctions.PACKAGE, new PackageFunction( - /*packageFactory=*/ null, - /*pkgLocator=*/ null, - /*showLoadingProgress=*/ null, - /*numPackagesSuccessfullyLoaded=*/ new AtomicInteger(), - /*bzlLoadFunctionForInlining=*/ null, - /*packageProgress=*/ null, + /* packageFactory= */ null, + /* pkgLocator= */ null, + /* showLoadingProgress= */ null, + /* numPackagesSuccessfullyLoaded= */ new AtomicInteger(), + /* bzlLoadFunctionForInlining= */ null, + /* packageProgress= */ null, PackageFunction.ActionOnIOExceptionReadingBuildFile.UseOriginalIOException .INSTANCE, GlobbingStrategy.SKYFRAME_HYBRID, @@ -221,7 +221,7 @@ public void setup() throws Exception { .put( SkyFunctions.IGNORED_PACKAGE_PREFIXES, new IgnoredPackagePrefixesFunction( - /*ignoredPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT)) + /* ignoredPackagePrefixesFile= */ PathFragment.EMPTY_FRAGMENT)) .put(SkyFunctions.RESOLVED_HASH_VALUES, new ResolvedHashesFunction()) .put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction()) .put( @@ -234,7 +234,7 @@ public void setup() throws Exception { ruleClassProvider, packageFactory, directories, - /*bzlLoadFunctionForInlining=*/ null)) + /* bzlLoadFunctionForInlining= */ null)) .put( SkyFunctions.REPOSITORY_DIRECTORY, new RepositoryDelegatorFunction( @@ -246,8 +246,8 @@ public void setup() throws Exception { BazelSkyframeExecutorConstants.EXTERNAL_PACKAGE_HELPER)) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) + .put(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) .put(SkyFunctions.SINGLE_EXTENSION_USAGES, new SingleExtensionUsagesFunction()) .put(SkyFunctions.SINGLE_EXTENSION_EVAL, singleExtensionEvalFunction) diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java index cdedc1bd7cb97c..7da2e62ffe4098 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java @@ -151,8 +151,7 @@ private void setUpWithBuiltinModules(ImmutableMap b BazelSkyframeExecutorConstants.EXTERNAL_PACKAGE_HELPER)) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) .buildOrThrow(), differencer); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java index 5316c2bc5e1614..2aed3463828d41 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; -import com.google.devtools.build.lib.bazel.bzlmod.Selection.SelectionResult; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -53,7 +52,8 @@ public void diamond_simple() throws Exception { .put(ModuleBuilder.create("ddd", "2.0", 1).buildEntry()) .buildOrThrow(); - SelectionResult selectionResult = Selection.run(depGraph, /*overrides=*/ ImmutableMap.of()); + BazelModuleResolutionValue selectionResult = + Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -117,7 +117,8 @@ public void diamond_withFurtherRemoval() throws Exception { .put(ModuleBuilder.create("eee", "1.0").buildEntry()) .build(); - SelectionResult selectionResult = Selection.run(depGraph, /*overrides=*/ ImmutableMap.of()); + BazelModuleResolutionValue selectionResult = + Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -180,7 +181,8 @@ public void circularDependencyDueToSelection() throws Exception { .put(ModuleBuilder.create("ddd", "1.0").buildEntry()) .buildOrThrow(); - SelectionResult selectionResult = Selection.run(depGraph, /*overrides=*/ ImmutableMap.of()); + BazelModuleResolutionValue selectionResult = + Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -287,7 +289,8 @@ public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { // \-> ccc 1.1 // \-> ddd 1.0 -> bbb 1.1 // \-> eee 1.0 -> ccc 1.1 - SelectionResult selectionResult = Selection.run(depGraph, /*overrides=*/ ImmutableMap.of()); + BazelModuleResolutionValue selectionResult = + Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", "1.0") @@ -384,7 +387,7 @@ public void multipleVersionOverride_fork_goodCase() throws Exception { MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - SelectionResult selectionResult = Selection.run(depGraph, overrides); + BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -457,7 +460,7 @@ public void multipleVersionOverride_diamond_differentCompatibilityLevels() throw MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - SelectionResult selectionResult = Selection.run(depGraph, overrides); + BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -506,7 +509,7 @@ public void multipleVersionOverride_diamond_sameCompatibilityLevel() throws Exce MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - SelectionResult selectionResult = Selection.run(depGraph, overrides); + BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -584,7 +587,7 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw // \-> bbb3@1.0 -> ccc@1.7 [originally ccc@1.5] // \-> bbb4@1.0 -> ccc@1.7 [allowed] // \-> bbb5@1.0 -> ccc@2.0 [allowed] - SelectionResult selectionResult = Selection.run(depGraph, overrides); + BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) @@ -797,7 +800,7 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t // \ \-> bbb4@1.1 // \-> bbb4@1.1 // ccc@1.5 and ccc@3.0, the versions violating the allowlist, are gone. - SelectionResult selectionResult = Selection.run(depGraph, overrides); + BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( ModuleBuilder.create("aaa", Version.EMPTY) diff --git a/src/test/java/com/google/devtools/build/lib/packages/PackageTest.java b/src/test/java/com/google/devtools/build/lib/packages/PackageTest.java index 6d8b81c4c3452f..464f6e9d1a6109 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/PackageTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/PackageTest.java @@ -31,6 +31,7 @@ import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; import java.util.List; +import java.util.Optional; import net.starlark.java.eval.StarlarkCallable; import net.starlark.java.syntax.Location; import org.junit.Before; @@ -163,7 +164,9 @@ private Package.Builder pkgBuilder(String name) { DefaultPackageSettings.INSTANCE, PackageIdentifier.createInMainRepo(name), "workspace", - /*noImplicitFileExport=*/ true, + Optional.empty(), + Optional.empty(), + /* noImplicitFileExport= */ true, RepositoryMapping.ALWAYS_FALLBACK, RepositoryMapping.ALWAYS_FALLBACK); result.setFilename( diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java index 919d71abe9fed6..b174f97486abe3 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java @@ -69,6 +69,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; import net.starlark.java.eval.StarlarkFunction; @@ -264,6 +265,8 @@ private Package.Builder createDummyPackageBuilder() { .newPackageBuilder( PackageIdentifier.createInMainRepo(TEST_PACKAGE_NAME), "TESTING", + Optional.empty(), + Optional.empty(), StarlarkSemantics.DEFAULT, RepositoryMapping.ALWAYS_FALLBACK, RepositoryMapping.ALWAYS_FALLBACK) diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java index 558e2dd7b4ec3c..ba68d615e0de53 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java @@ -34,6 +34,7 @@ import com.google.devtools.build.lib.vfs.RootedPath; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import net.starlark.java.eval.StarlarkSemantics; import net.starlark.java.eval.StarlarkThread; import net.starlark.java.syntax.Location; @@ -60,6 +61,8 @@ private Package.Builder newBuilder(PackageIdentifier id, Path filename) { .newPackageBuilder( id, "TESTING", + Optional.empty(), + Optional.empty(), StarlarkSemantics.DEFAULT, RepositoryMapping.ALWAYS_FALLBACK, RepositoryMapping.ALWAYS_FALLBACK) diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD b/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD index 6788a8aafc853b..9e2b8f25213f45 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/repository/BUILD @@ -21,7 +21,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", "//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories", "//src/main/java/com/google/devtools/build/lib/analysis:server_directories", - "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_helper", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:repo_rule_value", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:resolution_impl", "//src/main/java/com/google/devtools/build/lib/bazel/repository:repository_options", diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java index 3da83c1234e485..0f359f95a1c11b 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java @@ -30,8 +30,8 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ServerDirectories; import com.google.devtools.build.lib.analysis.util.AnalysisMock; +import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleHelperImpl; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; import com.google.devtools.build.lib.bazel.bzlmod.FakeRegistry; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileFunction; @@ -182,7 +182,7 @@ public void setupDelegator() throws Exception { null, null, null, - /*packageProgress=*/ null, + /* packageProgress= */ null, PackageFunction.ActionOnIOExceptionReadingBuildFile.UseOriginalIOException .INSTANCE, GlobbingStrategy.SKYFRAME_HYBRID, @@ -200,7 +200,7 @@ public void setupDelegator() throws Exception { ruleClassProvider, pkgFactory, directories, - /*bzlLoadFunctionForInlining=*/ null)) + /* bzlLoadFunctionForInlining= */ null)) .put( SkyFunctions.LOCAL_REPOSITORY_LOOKUP, new LocalRepositoryLookupFunction( @@ -219,17 +219,17 @@ public void setupDelegator() throws Exception { .put( SkyFunctions.IGNORED_PACKAGE_PREFIXES, new IgnoredPackagePrefixesFunction( - /*ignoredPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT)) + /* ignoredPackagePrefixesFile= */ PathFragment.EMPTY_FRAGMENT)) .put(SkyFunctions.RESOLVED_HASH_VALUES, new ResolvedHashesFunction()) .put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction()) .put( SkyFunctions.MODULE_FILE, new ModuleFileFunction(registryFactory, rootPath, ImmutableMap.of())) + .put(SkyFunctions.BAZEL_DEP_GRAPH, new BazelDepGraphFunction()) .put(SkyFunctions.BAZEL_MODULE_RESOLUTION, new BazelModuleResolutionFunction()) .put( BzlmodRepoRuleValue.BZLMOD_REPO_RULE, - new BzlmodRepoRuleFunction( - ruleClassProvider, directories, new BzlmodRepoRuleHelperImpl())) + new BzlmodRepoRuleFunction(ruleClassProvider, directories)) .put( SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, new ClientEnvironmentFunction(new AtomicReference<>(ImmutableMap.of()))) diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java index 44c9a3955eca31..3aa18259bdb461 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java @@ -29,6 +29,7 @@ import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionFunction; import com.google.devtools.build.lib.bazel.bzlmod.FakeRegistry; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileFunction; +import com.google.devtools.build.lib.bazel.bzlmod.Version; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.CheckDirectDepsMode; import com.google.devtools.build.lib.cmdline.RepositoryMapping; @@ -108,27 +109,36 @@ public ImmutableMap getSkyFunctions( }; } - public static RepositoryMappingValue withMappingAllowingFallback( + private static RepositoryMappingValue valueForWorkspace( ImmutableMap repositoryMapping) { - return RepositoryMappingValue.withMapping( + return RepositoryMappingValue.createForWorkspaceRepo( RepositoryMapping.createAllowingFallback(repositoryMapping)); } - public static RepositoryMappingValue withMapping( - ImmutableMap repositoryMapping, RepositoryName ownerRepo) { - return RepositoryMappingValue.withMapping( - RepositoryMapping.create(repositoryMapping, ownerRepo)); + private static RepositoryMappingValue valueForBzlmod( + ImmutableMap repositoryMapping, + RepositoryName ownerRepo, + String associatedModuleName, + String associatedModuleVersion) + throws Exception { + return RepositoryMappingValue.createForBzlmodRepo( + RepositoryMapping.create(repositoryMapping, ownerRepo), + associatedModuleName, + Version.parse(associatedModuleVersion)); } - public RepositoryMappingValue withMappingForRootModule( - ImmutableMap repositoryMapping, RepositoryName ownerRepo) { + private RepositoryMappingValue valueForRootModule( + ImmutableMap repositoryMapping, + String rootModuleName, + String rootModuleVersion) + throws Exception { ImmutableMap.Builder allMappings = ImmutableMap.builder(); allMappings.putAll(repositoryMapping); for (String name : analysisMock.getWorkspaceRepos()) { allMappings.put(name, RepositoryName.createUnvalidated(name)); } - return RepositoryMappingValue.withMapping( - RepositoryMapping.create(allMappings.buildOrThrow(), ownerRepo)); + return valueForBzlmod( + allMappings.buildOrThrow(), RepositoryName.MAIN, rootModuleName, rootModuleVersion); } @Test @@ -148,7 +158,7 @@ public void testSimpleMapping() throws Exception { assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of( "a", RepositoryName.create("b"), @@ -166,15 +176,14 @@ public void testRepoNameMapping_asRootModule() throws Exception { "bazel_dep(name='bbb',version='1.0', repo_name = 'com_foo_bar_b')"); registry.addModule(createModuleKey("bbb", "1.0"), "module(name='bbb', version='1.0')"); - RepositoryName name = RepositoryName.MAIN; - SkyKey skyKey = RepositoryMappingValue.key(name); + SkyKey skyKey = RepositoryMappingValue.key(RepositoryName.MAIN); EvaluationResult result = eval(skyKey); assertThat(result.hasError()).isFalse(); assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMappingForRootModule( + valueForRootModule( ImmutableMap.of( "", RepositoryName.MAIN, @@ -184,7 +193,8 @@ public void testRepoNameMapping_asRootModule() throws Exception { RepositoryName.MAIN, "com_foo_bar_b", RepositoryName.create("bbb~1.0")), - name)); + "aaa", + "0.1")); } @Test @@ -195,15 +205,14 @@ public void testRepoNameMapping_asRootModule_withOwnRepoName() throws Exception "bazel_dep(name='bbb',version='1.0', repo_name = 'com_foo_bar_b')"); registry.addModule(createModuleKey("bbb", "1.0"), "module(name='bbb', version='1.0')"); - RepositoryName name = RepositoryName.MAIN; - SkyKey skyKey = RepositoryMappingValue.key(name); + SkyKey skyKey = RepositoryMappingValue.key(RepositoryName.MAIN); EvaluationResult result = eval(skyKey); assertThat(result.hasError()).isFalse(); assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMappingForRootModule( + valueForRootModule( ImmutableMap.of( "", RepositoryName.MAIN, @@ -213,7 +222,8 @@ public void testRepoNameMapping_asRootModule_withOwnRepoName() throws Exception RepositoryName.MAIN, "com_foo_bar_b", RepositoryName.create("bbb~1.0")), - name)); + "aaa", + "0.1")); } @Test @@ -238,11 +248,13 @@ public void testRepoNameMapping_asDependency() throws Exception { assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "ccc", RepositoryName.create("ccc~1.0"), "com_foo_bar_b", RepositoryName.create("bbb~1.0")), - name)); + name, + "ccc", + "1.0")); } @Test @@ -262,10 +274,12 @@ public void testRepoNameMapping_dependencyOnRootModule() throws Exception { assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "bbb", RepositoryName.create("bbb~1.0"), "aaa", RepositoryName.create("")), - name)); + name, + "bbb", + "1.0")); } @Test @@ -280,8 +294,7 @@ public void testRepoNameMapping_multipleVersionOverride_fork() throws Exception .addModule(createModuleKey("bbb", "1.0"), "module(name='bbb', version='1.0')") .addModule(createModuleKey("bbb", "2.0"), "module(name='bbb', version='2.0')"); - RepositoryName name = RepositoryName.MAIN; - SkyKey skyKey = RepositoryMappingValue.key(name); + SkyKey skyKey = RepositoryMappingValue.key(RepositoryName.MAIN); EvaluationResult result = eval(skyKey); if (result.hasError()) { @@ -290,7 +303,7 @@ public void testRepoNameMapping_multipleVersionOverride_fork() throws Exception assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMappingForRootModule( + valueForRootModule( ImmutableMap.of( "", RepositoryName.MAIN, @@ -302,7 +315,8 @@ public void testRepoNameMapping_multipleVersionOverride_fork() throws Exception RepositoryName.create("bbb~1.0"), "bbb2", RepositoryName.create("bbb~2.0")), - name)); + "aaa", + "0.1")); } @Test @@ -333,11 +347,13 @@ public void testRepoNameMapping_multipleVersionOverride_diamond() throws Excepti assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "bbb", RepositoryName.create("bbb~1.0"), "ddd", RepositoryName.create("ddd~1.0")), - name)); + name, + "bbb", + "1.0")); } @Test @@ -366,11 +382,13 @@ public void testRepoNameMapping_multipleVersionOverride_lookup() throws Exceptio assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "bbb", RepositoryName.create("bbb~1.0"), "com_foo_bar_c", RepositoryName.create("ccc~1.0")), - name)); + name, + "bbb", + "1.0")); } @Test @@ -395,7 +413,7 @@ public void testMultipleRepositoriesWithMapping() throws Exception { assertThatEvaluationResult(eval(skyKey1)) .hasEntryThat(skyKey1) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of( "a", RepositoryName.create("b"), @@ -406,7 +424,7 @@ public void testMultipleRepositoriesWithMapping() throws Exception { assertThatEvaluationResult(eval(skyKey2)) .hasEntryThat(skyKey2) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of( "x", RepositoryName.create("y"), @@ -431,7 +449,7 @@ public void testRepositoryWithMultipleMappings() throws Exception { assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of( "a", RepositoryName.create("b"), @@ -473,7 +491,7 @@ public void testMixtureOfBothSystems_workspaceRepo() throws Exception { assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.builder() .put("", RepositoryName.MAIN) .put("aaa", RepositoryName.MAIN) @@ -513,14 +531,15 @@ public void testMixtureOfBothSystems_mainRepo() throws Exception { assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMappingForRootModule( + valueForRootModule( ImmutableMap.of( "", RepositoryName.MAIN, "aaa", RepositoryName.MAIN, "bbb", RepositoryName.create("bbb~1.0"), "root", RepositoryName.MAIN, "ws_repo", RepositoryName.create("ws_repo")), - RepositoryName.MAIN)); + "aaa", + "0.1")); } @Test @@ -543,12 +562,14 @@ public void testMixtureOfBothSystems_mainRepo_shouldNotSeeWorkspaceRepos() throw assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "", RepositoryName.MAIN, "aaa", RepositoryName.MAIN, "bbb", RepositoryName.create("bbb~1.0")), - RepositoryName.MAIN)); + RepositoryName.MAIN, + "aaa", + "0.1")); } @Test @@ -589,7 +610,7 @@ public void testDefaultMainRepoNameInMapping() throws Exception { assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of( TestConstants.WORKSPACE_NAME, RepositoryName.MAIN, "", RepositoryName.MAIN))); } @@ -609,7 +630,7 @@ public void testExplicitMainRepoNameInMapping() throws Exception { assertThatEvaluationResult(eval(skyKey)) .hasEntryThat(skyKey) .isEqualTo( - withMappingAllowingFallback( + valueForWorkspace( ImmutableMap.of("good", RepositoryName.MAIN, "", RepositoryName.MAIN))); } @@ -635,7 +656,7 @@ public void builtinsRepo() throws Exception { assertThatEvaluationResult(result) .hasEntryThat(skyKey) .isEqualTo( - withMapping( + valueForBzlmod( ImmutableMap.of( "bazel_tools", RepositoryName.BAZEL_TOOLS, // bazel_tools is a well-known module @@ -645,18 +666,20 @@ public void builtinsRepo() throws Exception { RepositoryName.create("_builtins"), "", RepositoryName.MAIN), - name)); + name, + "bazel_tools", + "")); } @Test public void testEqualsAndHashCode() throws Exception { new EqualsTester() .addEqualityGroup( - withMappingAllowingFallback(ImmutableMap.of("foo", RepositoryName.create("bar"))), - withMappingAllowingFallback(ImmutableMap.of("foo", RepositoryName.create("bar")))) + valueForWorkspace(ImmutableMap.of("foo", RepositoryName.create("bar"))), + valueForWorkspace(ImmutableMap.of("foo", RepositoryName.create("bar")))) .addEqualityGroup( - withMappingAllowingFallback(ImmutableMap.of("fizz", RepositoryName.create("buzz"))), - withMappingAllowingFallback(ImmutableMap.of("fizz", RepositoryName.create("buzz")))) + valueForWorkspace(ImmutableMap.of("fizz", RepositoryName.create("buzz"))), + valueForWorkspace(ImmutableMap.of("fizz", RepositoryName.create("buzz")))) .testEquals(); } } diff --git a/src/test/py/bazel/bzlmod/bazel_module_test.py b/src/test/py/bazel/bzlmod/bazel_module_test.py index 156cb8dddfe62a..d258624eaa59bb 100644 --- a/src/test/py/bazel/bzlmod/bazel_module_test.py +++ b/src/test/py/bazel/bzlmod/bazel_module_test.py @@ -997,6 +997,113 @@ def testWorkspaceItselfCanSeeRootModuleMappings(self): _, _, stderr = self.RunBazel(['build', ':a'], allow_failure=False) self.assertIn('I LUV U!', '\n'.join(stderr)) + def testNativeModuleNameAndVersion(self): + self.main_registry.setModuleBasePath('projects') + projects_dir = self.main_registry.projects + + self.ScratchFile( + 'MODULE.bazel', + [ + 'module(name="root",version="0.1")', + 'bazel_dep(name="foo",version="1.0")', + 'report_ext = use_extension("@foo//:ext.bzl", "report_ext")', + 'use_repo(report_ext, "report_repo")', + 'bazel_dep(name="bar")', + 'local_path_override(module_name="bar",path="bar")', + ], + ) + self.ScratchFile('WORKSPACE') + self.ScratchFile( + 'WORKSPACE.bzlmod', ['local_repository(name="quux",path="quux")'] + ) + self.ScratchFile( + 'BUILD', + [ + 'load("@foo//:report.bzl", "report")', + 'report()', + ], + ) + # foo: a repo defined by a normal Bazel module. Also hosts the extension + # `report_ext` which generates a repo `report_repo`. + self.main_registry.createLocalPathModule('foo', '1.0', 'foo') + projects_dir.joinpath('foo').mkdir(exist_ok=True) + scratchFile(projects_dir.joinpath('foo', 'WORKSPACE')) + scratchFile( + projects_dir.joinpath('foo', 'BUILD'), + [ + 'load(":report.bzl", "report")', + 'report()', + ], + ) + scratchFile( + projects_dir.joinpath('foo', 'report.bzl'), + [ + 'def report():', + ' repo = native.repository_name()', + ' name = str(native.module_name())', + ' version = str(native.module_version())', + ' print("@" + repo + " reporting in: " + name + "@" + version)', + ' native.filegroup(name="a")', + ], + ) + scratchFile( + projects_dir.joinpath('foo', 'ext.bzl'), + [ + 'def _report_repo(rctx):', + ' rctx.file("BUILD",', + ' "load(\\"@foo//:report.bzl\\", \\"report\\")\\n" +', + ' "report()")', + 'report_repo = repository_rule(_report_repo)', + 'report_ext = module_extension(', + ' lambda mctx: report_repo(name="report_repo"))', + ], + ) + # bar: a repo defined by a Bazel module with a non-registry override + self.ScratchFile('bar/WORKSPACE') + self.ScratchFile( + 'bar/MODULE.bazel', + [ + 'module(name="bar", version="2.0")', + 'bazel_dep(name="foo",version="1.0")', + ], + ) + self.ScratchFile( + 'bar/BUILD', + [ + 'load("@foo//:report.bzl", "report")', + 'report()', + ], + ) + # quux: a repo defined by WORKSPACE + self.ScratchFile('quux/WORKSPACE') + self.ScratchFile( + 'quux/BUILD', + [ + 'load("@foo//:report.bzl", "report")', + 'report()', + ], + ) + + _, _, stderr = self.RunBazel( + [ + 'build', + ':a', + '@foo//:a', + '@report_repo//:a', + '@bar//:a', + '@quux//:a', + ], + allow_failure=False, + ) + stderr = '\n'.join(stderr) + self.assertIn('@@ reporting in: root@0.1', stderr) + self.assertIn('@@foo~1.0 reporting in: foo@1.0', stderr) + self.assertIn( + '@@foo~1.0~report_ext~report_repo reporting in: foo@1.0', stderr + ) + self.assertIn('@@bar~override reporting in: bar@2.0', stderr) + self.assertIn('@@quux reporting in: None@None', stderr) + if __name__ == '__main__': unittest.main()