diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/BUILD b/src/main/java/com/google/devtools/build/lib/cmdline/BUILD index d9b981f1a72e9c..1467a0650910a4 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/BUILD +++ b/src/main/java/com/google/devtools/build/lib/cmdline/BUILD @@ -17,6 +17,7 @@ java_library( srcs = [ "BazelCompileContext.java", "BazelModuleContext.java", + "BazelModuleKey.java", "IgnoredSubdirectories.java", "Label.java", "LabelConstants.java", diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleContext.java b/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleContext.java index 2fa9e1c6fb1634..f3c0c2ffbf8bd1 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleContext.java @@ -39,7 +39,12 @@ @AutoValue public abstract class BazelModuleContext { /** Label associated with the Starlark {@link net.starlark.java.eval.Module}. */ - public abstract Label label(); + public final Label label() { + return key().getLabel(); + } + + /** {@link com.google.devtools.build.lib.skyframe.BzlLoadValue.Key} used to create the module. */ + public abstract BazelModuleKey key(); /** The repository mapping applicable to the repo where the .bzl file is located in. */ public abstract RepositoryMapping repoMapping(); @@ -158,13 +163,12 @@ public static BazelModuleContext ofInnermostBzlOrFail(StarlarkThread thread, Str } public static BazelModuleContext create( - Label label, + BazelModuleKey key, RepositoryMapping repoMapping, String filename, ImmutableList loads, byte[] bzlTransitiveDigest) { - return new AutoValue_BazelModuleContext( - label, repoMapping, filename, loads, bzlTransitiveDigest); + return new AutoValue_BazelModuleContext(key, repoMapping, filename, loads, bzlTransitiveDigest); } public final Label.PackageContext packageContext() { diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleKey.java b/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleKey.java new file mode 100644 index 00000000000000..34a0bcab37dae1 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/cmdline/BazelModuleKey.java @@ -0,0 +1,58 @@ +// Copyright 2020 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.cmdline; + +import com.google.devtools.build.lib.skyframe.SkyFunctions; +import com.google.devtools.build.skyframe.SkyFunctionName; +import com.google.devtools.build.skyframe.SkyKey; + +/** + * Interface for {@link com.google.devtools.build.lib.skyframe.BzlLoadValue.Key}. + * + *

This exists to break what would otherwise be a circular dependency between {@link Label}, + * {@link BazelModuleContext} and {@link com.google.devtools.build.lib.skyframe.BzlLoadValue.Key}. + */ +public interface BazelModuleKey extends SkyKey { + /** Absolute label of the .bzl file to be loaded. */ + Label getLabel(); + + @Override + default SkyFunctionName functionName() { + return SkyFunctions.BZL_LOAD; + } + + /** Creates a fake instance for testing. */ + static BazelModuleKey createFakeModuleKeyForTesting(Label label) { + return new FakeModuleKey(label); + } + + /** Key for {@link BazelModuleContext}s created outside of Skyframe for testing */ + static final class FakeModuleKey implements BazelModuleKey { + private final Label label; + + private FakeModuleKey(Label label) { + this.label = label; + } + + @Override + public Label getLabel() { + return label; + } + + @Override + public SkyFunctionName functionName() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java index a88865f0aaae8f..17a7f10441c1bd 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java @@ -882,7 +882,7 @@ private BzlLoadValue computeInternalWithCompiledBzl( // including the label and a reified copy of the load DAG. BazelModuleContext bazelModuleContext = BazelModuleContext.create( - label, + key, repoMapping, prog.getFilename(), ImmutableList.copyOf(loadMap.values()), diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadValue.java index c6d70e7885b284..7894f1f7163c64 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadValue.java @@ -20,6 +20,7 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableTable; +import com.google.devtools.build.lib.cmdline.BazelModuleKey; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; @@ -32,7 +33,6 @@ import com.google.devtools.build.lib.util.HashCodes; import com.google.devtools.build.lib.vfs.Root; import com.google.devtools.build.lib.vfs.RootedPath; -import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyKey.SkyKeyInterner; import com.google.devtools.build.skyframe.SkyValue; @@ -102,7 +102,7 @@ public ImmutableTable getRecordedRepoMap private static final SkyKeyInterner keyInterner = SkyKey.newInterner(); /** SkyKey for a Starlark load. */ - public abstract static sealed class Key implements SkyKey + public abstract static sealed class Key implements BazelModuleKey permits KeyForBuild, KeyForWorkspace, KeyForBuiltins, KeyForBzlmod { // Closed, for class-based equals()/hashCode(). private Key() {} @@ -114,6 +114,7 @@ private Key() {} * other keys to use {@code @_builtins}, but since no real repo by that name may be defined, * they won't evaluate to a successful result.) */ + @Override public abstract Label getLabel(); /** Returns true if this is a request for the special BUILD prelude file. */ @@ -158,11 +159,6 @@ final boolean isSclDialect() { */ abstract BzlCompileValue.Key getCompileKey(Root root); - @Override - public SkyFunctionName functionName() { - return SkyFunctions.BZL_LOAD; - } - @Override public final boolean valueIsShareable() { // We don't guarantee that all constructs implement equality, meaning we can't correctly diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD index 285f9b9f4b4e9e..866a8e7b90fc2c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/BUILD @@ -24,6 +24,7 @@ java_library( name = "serialization_registry_setup_helpers", srcs = ["SerializationRegistrySetupHelpers.java"], deps = [ + ":module_codec", ":serialization", "//src/main/java/com/google/devtools/build/lib:runtime", "//src/main/java/com/google/devtools/build/lib/actions:artifacts", @@ -65,6 +66,7 @@ java_library( ["**/*.java"], exclude = [ "AbstractExportedStarlarkSymbolCodec.java", + "ModuleCodec.java", "CodecScanningConstants.java", "SerializationRegistrySetupHelpers.java", "SerializationConstants.java", @@ -124,3 +126,16 @@ java_library( "@com_google_protobuf//:protobuf_java", ], ) + +java_library( + name = "module_codec", + srcs = ["ModuleCodec.java"], + deps = [ + ":serialization", + "//src/main/java/com/google/devtools/build/lib/cmdline", + "//src/main/java/com/google/devtools/build/lib/skyframe:bzl_load_value", + "//src/main/java/net/starlark/java/eval", + "//third_party:guava", + "@com_google_protobuf//:protobuf_java", + ], +) diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodec.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodec.java new file mode 100644 index 00000000000000..05f9b09571cff5 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodec.java @@ -0,0 +1,80 @@ +// Copyright 2024 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.skyframe.serialization; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.devtools.build.lib.skyframe.BzlLoadValue.bzlLoadKeyCodec; + +import com.google.devtools.build.lib.cmdline.BazelModuleContext; +import com.google.devtools.build.lib.skyframe.BzlLoadValue; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.CodedOutputStream; +import java.io.IOException; +import net.starlark.java.eval.Module; + +/** + * Codec for {@link Module}. + * + *

Serializes using the module's associated {@link BzlLoadValue.Key}. + */ +public final class ModuleCodec extends DeferredObjectCodec { + private static final ModuleCodec INSTANCE = new ModuleCodec(); + + public static ModuleCodec moduleCodec() { + return INSTANCE; + } + + @Override + public Class getEncodedClass() { + return Module.class; + } + + @Override + public boolean autoRegister() { + // Unit tests that bypass Skyframe for Module loading cannot use this codec. + return false; + } + + @Override + public void serialize(SerializationContext context, Module obj, CodedOutputStream codedOut) + throws IOException, SerializationException { + var moduleContext = checkNotNull(BazelModuleContext.of(obj), "module %s missing context", obj); + context.serializeLeaf((BzlLoadValue.Key) moduleContext.key(), bzlLoadKeyCodec(), codedOut); + } + + @Override + public DeferredValue deserializeDeferred( + AsyncDeserializationContext context, CodedInputStream codedIn) + throws IOException, SerializationException { + BzlLoadValue.Key bzlLoadKey = context.deserializeLeaf(codedIn, bzlLoadKeyCodec()); + var builder = new DeserializationBuilder(); + context.getSkyValue(bzlLoadKey, builder, DeserializationBuilder::setBzlLoadValue); + return builder; + } + + private static final class DeserializationBuilder implements DeferredValue { + private BzlLoadValue loadValue; + + @Override + public Module call() { + return checkNotNull(loadValue, "Skyframe lookup value not set").getModule(); + } + + private static void setBzlLoadValue(DeserializationBuilder builder, Object value) { + builder.loadValue = (BzlLoadValue) value; + } + } + + private ModuleCodec() {} +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationRegistrySetupHelpers.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationRegistrySetupHelpers.java index 3f23eeec50fdbe..ee78f8dcbd6a5c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationRegistrySetupHelpers.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/SerializationRegistrySetupHelpers.java @@ -127,6 +127,7 @@ public static ObjectCodecRegistry.Builder addStarlarkFunctionality( .add(ArrayCodec.forComponentType(Artifact.class)) .add(new DeferredNestedSetCodec()) .add(Label.valueSharingCodec()) + .add(ModuleCodec.moduleCodec()) .add(PackageIdentifier.valueSharingCodec()) .add(ConfiguredTargetKey.valueSharingCodec()) .add(TransitiveInfoProviderMapImpl.valueSharingCodec()) diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/BuildInfoFileWriteActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/BuildInfoFileWriteActionTest.java index 70e2b025f1933a..9cb620d4b2eefd 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/actions/BuildInfoFileWriteActionTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/BuildInfoFileWriteActionTest.java @@ -34,6 +34,7 @@ import com.google.devtools.build.lib.analysis.util.ActionTester; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import com.google.devtools.build.lib.cmdline.BazelModuleContext; +import com.google.devtools.build.lib.cmdline.BazelModuleKey; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.events.StoredEventHandler; @@ -76,7 +77,8 @@ private static Object exec(String... lines) throws Exception { StarlarkSemantics.DEFAULT, ImmutableMap.of(), BazelModuleContext.create( - Label.parseCanonicalUnchecked("//test:label"), + BazelModuleKey.createFakeModuleKeyForTesting( + Label.parseCanonicalUnchecked("//test:label")), RepositoryMapping.ALWAYS_FALLBACK, "test/label.bzl", /* loads= */ ImmutableList.of(), diff --git a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLineTest.java b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLineTest.java index 002403d9afcfd7..8b3e5b13bc6b37 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLineTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkCustomCommandLineTest.java @@ -39,6 +39,7 @@ import com.google.devtools.build.lib.analysis.config.CoreOptions; import com.google.devtools.build.lib.analysis.starlark.StarlarkCustomCommandLine.VectorArg; import com.google.devtools.build.lib.cmdline.BazelModuleContext; +import com.google.devtools.build.lib.cmdline.BazelModuleKey; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.testutil.Scratch; @@ -451,7 +452,8 @@ private static Object execStarlark(String code) throws Exception { StarlarkSemantics.DEFAULT, ImmutableMap.of(), BazelModuleContext.create( - Label.parseCanonicalUnchecked("//test:label"), + BazelModuleKey.createFakeModuleKeyForTesting( + Label.parseCanonicalUnchecked("//test:label")), RepositoryMapping.ALWAYS_FALLBACK, "test/label.bzl", /* loads= */ ImmutableList.of(), diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/BUILD b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/BUILD index 52fc98b9eb03af..24c050ac2b7b83 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/BUILD +++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/BUILD @@ -313,10 +313,20 @@ java_test( srcs = ["ModuleCodecTest.java"], deps = [ "//src/main/java/com/google/devtools/build/lib/cmdline", + "//src/main/java/com/google/devtools/build/lib/packages", + "//src/main/java/com/google/devtools/build/lib/skyframe:bzl_load_value", + "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization:module_codec", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils", + "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils:round-tripping", + "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", "//src/main/java/net/starlark/java/eval", + "//src/test/java/com/google/devtools/build/lib/analysis/util", "//third_party:guava", + "//third_party:jsr305", "//third_party:junit4", + "//third_party:truth", ], ) diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodecTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodecTest.java index a1445b5b1a2fd8..188c47db9ac378 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodecTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ModuleCodecTest.java @@ -13,10 +13,25 @@ // limitations under the License. package com.google.devtools.build.lib.skyframe.serialization; +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.skyframe.BzlLoadValue.keyForBuild; +import static com.google.devtools.build.lib.skyframe.serialization.ModuleCodec.moduleCodec; + +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.cmdline.PackageIdentifier; +import com.google.devtools.build.lib.packages.NoSuchPackageException; +import com.google.devtools.build.lib.packages.Package; +import com.google.devtools.build.lib.skyframe.BzlLoadValue; +import com.google.devtools.build.lib.skyframe.SkyframeExecutor; +import com.google.devtools.build.lib.skyframe.serialization.testutils.RoundTripping; import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester; import com.google.devtools.build.lib.skyframe.serialization.testutils.TestUtils; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import javax.annotation.Nullable; import net.starlark.java.eval.Module; import net.starlark.java.eval.StarlarkSemantics; import org.junit.Test; @@ -25,9 +40,9 @@ /** Tests for {@link ModuleCodec}. */ @RunWith(JUnit4.class) -public class ModuleCodecTest { +public class ModuleCodecTest extends BuildViewTestCase { @Test - public void testCodec() throws Exception { + public void testDynamicCodec() throws Exception { Module subject1 = Module.create(); Module subject2 = @@ -42,6 +57,66 @@ public void testCodec() throws Exception { .runTestsWithoutStableSerializationCheck(); } + @Test + public void testCodec() throws Exception { + scratch.file("lib/BUILD"); + scratch.file( + "pkg/foo.bzl", + """ + def _impl(ctx): + print("xyz is %s" % ctx.attr.xyz) + my_rule = rule( + implementation=_impl, + attrs = { + "xyz": attr.string(), + }, + ) + """); + scratch.file( + "pkg/BUILD", + """ + load(":foo.bzl", "my_rule") + my_rule( + name = "abc", + xyz = "value", + ) + """); + + // Evaluates pkg to populate pkg/foo.bzl in Skyframe. + assertThat(getPackage("pkg")).isNotNull(); + + // Pulls the module value out of Skyframe from its BzlLoadValue. + BzlLoadValue.Key bzlLoadKey = keyForBuild(Label.parseCanonical("//pkg:foo.bzl")); + var fooBzl = (BzlLoadValue) getDoneValue(bzlLoadKey); + Module module = fooBzl.getModule(); + + var deserialized = + RoundTripping.roundTripWithSkyframe( + new ObjectCodecs().withCodecOverridesForTesting(ImmutableList.of(moduleCodec())), + FingerprintValueService.createForTesting(), + this::getDoneValue, + module); + + assertThat(deserialized).isSameInstanceAs(module); + } + + @Nullable + private Package getPackage(String pkgName) throws InterruptedException { + try { + return getPackageManager().getPackage(reporter, PackageIdentifier.createInMainRepo(pkgName)); + } catch (NoSuchPackageException unused) { + return null; + } + } + + private SkyValue getDoneValue(SkyKey key) { + try { + return skyframeExecutor.getDoneSkyValueForIntrospection(key); + } catch (SkyframeExecutor.FailureToRetrieveIntrospectedValueException e) { + throw new AssertionError(e); + } + } + private static void verifyDeserialization(Module subject, Module deserialized) { // Module doesn't implement proper equality. TestUtils.assertModulesEqual(subject, deserialized); diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java index 20727018447ab5..25543b827c58e1 100644 --- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java +++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java @@ -44,6 +44,7 @@ import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import com.google.devtools.build.lib.analysis.util.TestAspects; import com.google.devtools.build.lib.cmdline.BazelModuleContext; +import com.google.devtools.build.lib.cmdline.BazelModuleKey; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.RepositoryMapping; @@ -3912,7 +3913,8 @@ def impl(ctx): ev.assertContainsError( """ expected value of type 'list(label)' for attribute 'srcs' of 'my_rule', but got \ - "default_files" (string)"""); + "default_files" (string)\ + """); } @Test @@ -6517,7 +6519,7 @@ public void testLabelWithStrictVisibility() throws Exception { PackageIdentifier.create(currentRepo, PathFragment.create("lib")), "label.bzl"); Object clientData = BazelModuleContext.create( - bzlLabel, + BazelModuleKey.createFakeModuleKeyForTesting(bzlLabel), RepositoryMapping.create( ImmutableMap.of("my_module", currentRepo, "dep", otherRepo), currentRepo), "lib/label.bzl", diff --git a/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java index 38c4820937c968..1af91785451241 100644 --- a/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/starlark/util/BazelEvaluationTestCase.java @@ -22,6 +22,7 @@ import com.google.devtools.build.lib.analysis.starlark.StarlarkConfig; import com.google.devtools.build.lib.analysis.starlark.StarlarkGlobalsImpl; import com.google.devtools.build.lib.cmdline.BazelModuleContext; +import com.google.devtools.build.lib.cmdline.BazelModuleKey; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.events.Event; @@ -190,7 +191,7 @@ private Object newModule(ImmutableMap.Builder predeclared) { // Return the module's client data. (This one uses dummy values for tests.) return BazelModuleContext.create( - label, + BazelModuleKey.createFakeModuleKeyForTesting(label), RepositoryMapping.ALWAYS_FALLBACK, "test/label.bzl", /* loads= */ ImmutableList.of(),