Skip to content

Commit b1341be

Browse files
benjaminpcopybara-github
authored andcommitted
Perform builtins injection for WORKSPACE-loaded bzl files.
#17713 Closes #18022. PiperOrigin-RevId: 525350732 Change-Id: I869653fcd6d4a82ccca49f14e66245c182062731
1 parent 0a10409 commit b1341be

File tree

7 files changed

+105
-54
lines changed

7 files changed

+105
-54
lines changed

src/main/java/com/google/devtools/build/lib/packages/BazelStarlarkEnvironment.java

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ public final class BazelStarlarkEnvironment {
5050
private final ImmutableMap<String, Object> uninjectedBuildBzlNativeBindings;
5151
/** The "native" module fields for a WORKSPACE-loaded bzl module. */
5252
private final ImmutableMap<String, Object> workspaceBzlNativeBindings;
53-
/** The top-level predeclared symbols for a BUILD-loaded bzl module, before builtins injection. */
53+
/** The top-level predeclared symbols for a BUILD-loaded bzl module before builtins injection. */
5454
private final ImmutableMap<String, Object> uninjectedBuildBzlEnv;
5555
/** The top-level predeclared symbols for BUILD files, before builtins injection and prelude. */
5656
private final ImmutableMap<String, Object> uninjectedBuildEnv;
57-
/** The top-level predeclared symbols for a WORKSPACE-loaded bzl module. */
58-
private final ImmutableMap<String, Object> workspaceBzlEnv;
57+
/**
58+
* The top-level predeclared symbols for a WORKSPACE-loaded bzl module before builtins injection.
59+
*/
60+
private final ImmutableMap<String, Object> uninjectedWorkspaceBzlEnv;
5961
/** The top-level predeclared symbols for a bzl module in the {@code @_builtins} pseudo-repo. */
6062
private final ImmutableMap<String, Object> builtinsBzlEnv;
6163
/** The top-level predeclared symbols for a bzl module in the Bzlmod system. */
@@ -75,7 +77,8 @@ public final class BazelStarlarkEnvironment {
7577
this.workspaceBzlNativeBindings = createWorkspaceBzlNativeBindings(ruleClassProvider, version);
7678
this.uninjectedBuildBzlEnv =
7779
createUninjectedBuildBzlEnv(ruleClassProvider, uninjectedBuildBzlNativeBindings);
78-
this.workspaceBzlEnv = createWorkspaceBzlEnv(ruleClassProvider, workspaceBzlNativeBindings);
80+
this.uninjectedWorkspaceBzlEnv =
81+
createWorkspaceBzlEnv(ruleClassProvider, workspaceBzlNativeBindings);
7982
// TODO(pcloudy): this should be a bzlmod specific environment, but keep using the workspace
8083
// envirnment until we implement module rules.
8184
this.bzlmodBzlEnv = createWorkspaceBzlEnv(ruleClassProvider, workspaceBzlNativeBindings);
@@ -122,9 +125,9 @@ public ImmutableMap<String, Object> getUninjectedBuildEnv() {
122125
return uninjectedBuildEnv;
123126
}
124127

125-
/** Returns the environment for WORKSPACE-loaded bzl files. */
126-
public ImmutableMap<String, Object> getWorkspaceBzlEnv() {
127-
return workspaceBzlEnv;
128+
/** Returns the environment for WORKSPACE-loaded bzl files before builtins injection. */
129+
public ImmutableMap<String, Object> getUninjectedWorkspaceBzlEnv() {
130+
return uninjectedWorkspaceBzlEnv;
128131
}
129132

130133
/** Returns the environment for bzl files in the {@code @_builtins} pseudo-repository. */
@@ -338,17 +341,57 @@ private static boolean injectionApplies(String key, Map<String, Boolean> overrid
338341
* documentation for {@code --experimental_builtins_injection_override}. Non-injected symbols must
339342
* still obey the above constraints.
340343
*
341-
* @see StarlarkBuiltinsFunction
344+
* @see com.google.devtools.build.lib.skyframe.StarlarkBuiltinsFunction
342345
*/
343346
public ImmutableMap<String, Object> createBuildBzlEnvUsingInjection(
344347
Map<String, Object> exportedToplevels,
345348
Map<String, Object> exportedRules,
346349
List<String> overridesList)
347350
throws InjectionException {
351+
return createBzlEnvUsingInjection(
352+
exportedToplevels, exportedRules, overridesList, uninjectedBuildBzlNativeBindings);
353+
}
354+
355+
/**
356+
* Constructs an environment for a WORKSPACE-loaded bzl file based on the default environment, the
357+
* maps corresponding to the {@code exported_toplevels} and {@code exported_rules} dicts, and the
358+
* value of {@code --experimental_builtins_injection_override}.
359+
*
360+
* @see com.google.devtools.build.lib.skyframe.StarlarkBuiltinsFunction
361+
*/
362+
public ImmutableMap<String, Object> createWorkspaceBzlEnvUsingInjection(
363+
Map<String, Object> exportedToplevels,
364+
Map<String, Object> exportedRules,
365+
List<String> overridesList)
366+
throws InjectionException {
367+
return createBzlEnvUsingInjection(
368+
exportedToplevels, exportedRules, overridesList, workspaceBzlNativeBindings);
369+
}
370+
371+
private ImmutableMap<String, Object> createBzlEnvUsingInjection(
372+
Map<String, Object> exportedToplevels,
373+
Map<String, Object> exportedRules,
374+
List<String> overridesList,
375+
Map<String, Object> nativeBase)
376+
throws InjectionException {
348377
Map<String, Boolean> overridesMap = parseInjectionOverridesList(overridesList);
349378

379+
Map<String, Object> env = new HashMap<>(ruleClassProvider.getEnvironment());
380+
381+
// Determine "native" bindings.
382+
// TODO(#11954): See above comment in createUninjectedBuildBzlEnv.
383+
Map<String, Object> nativeBindings = new HashMap<>(nativeBase);
384+
for (Map.Entry<String, Object> entry : exportedRules.entrySet()) {
385+
String key = entry.getKey();
386+
String name = getKeySuffix(key);
387+
validateSymbolIsInjectable(name, nativeBindings.keySet(), ruleFunctions.keySet(), "rule");
388+
if (injectionApplies(key, overridesMap)) {
389+
nativeBindings.put(name, entry.getValue());
390+
}
391+
}
392+
env.put("native", createNativeModule(nativeBindings));
393+
350394
// Determine top-level symbols.
351-
Map<String, Object> env = new HashMap<>(uninjectedBuildBzlEnv);
352395
for (Map.Entry<String, Object> entry : exportedToplevels.entrySet()) {
353396
String key = entry.getKey();
354397
String name = getKeySuffix(key);
@@ -362,19 +405,6 @@ public ImmutableMap<String, Object> createBuildBzlEnvUsingInjection(
362405
}
363406
}
364407

365-
// Determine "native" bindings.
366-
// TODO(#11954): See above comment in createUninjectedBuildBzlEnv.
367-
Map<String, Object> nativeBindings = new HashMap<>(uninjectedBuildBzlNativeBindings);
368-
for (Map.Entry<String, Object> entry : exportedRules.entrySet()) {
369-
String key = entry.getKey();
370-
String name = getKeySuffix(key);
371-
validateSymbolIsInjectable(name, nativeBindings.keySet(), ruleFunctions.keySet(), "rule");
372-
if (injectionApplies(key, overridesMap)) {
373-
nativeBindings.put(name, entry.getValue());
374-
}
375-
}
376-
377-
env.put("native", createNativeModule(nativeBindings));
378408
return ImmutableMap.copyOf(env);
379409
}
380410

src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,21 +572,20 @@ private BzlLoadValue computeInternal(
572572
/**
573573
* Obtain a suitable StarlarkBuiltinsValue.
574574
*
575-
* <p>For BUILD-loaded .bzl files, this is a real builtins value, obtained using either Skyframe
576-
* or inlining of StarlarkBuiltinsFunction (depending on whether {@code inliningState} is
577-
* non-null). The returned value includes the StarlarkSemantics.
575+
* <p>For BUILD-loaded and WORKSPACE-loaded .bzl files, this is a real builtins value, obtained
576+
* using either Skyframe or inlining of StarlarkBuiltinsFunction (depending on whether {@code
577+
* inliningState} is non-null). The returned value includes the StarlarkSemantics.
578578
*
579579
* <p>For other .bzl files, the builtins computation is not needed and would create a Skyframe
580580
* cycle if requested, so we instead return an empty builtins value that just wraps the
581-
* StarlarkSemantics. (NB: In the case of WORKSPACE-loaded .bzl files, the cycle goes through the
582-
* repository remapping value. It's possible this could be avoided if we ever wanted to make this
583-
* kind of .bzl file use builtins injection.)
581+
* StarlarkSemantics.
584582
*/
585583
@Nullable
586584
private StarlarkBuiltinsValue getBuiltins(
587585
BzlLoadValue.Key key, Environment env, @Nullable InliningState inliningState)
588586
throws BzlLoadFailedException, InterruptedException {
589-
if (!(key instanceof BzlLoadValue.KeyForBuild)) {
587+
if (!(key instanceof BzlLoadValue.KeyForBuild)
588+
&& !(key instanceof BzlLoadValue.KeyForWorkspace)) {
590589
StarlarkSemantics starlarkSemantics = PrecomputedValue.STARLARK_SEMANTICS.get(env);
591590
if (starlarkSemantics == null) {
592591
return null;
@@ -1185,7 +1184,15 @@ private ImmutableMap<String, Object> getAndDigestPredeclaredEnvironment(
11851184
fp.addBytes(builtins.transitiveDigest);
11861185
return builtins.predeclaredForBuildBzl;
11871186
} else if (key instanceof BzlLoadValue.KeyForWorkspace) {
1188-
return starlarkEnv.getWorkspaceBzlEnv();
1187+
// TODO(#11437): Remove ability to disable injection by setting flag to empty string.
1188+
if (builtins
1189+
.starlarkSemantics
1190+
.get(BuildLanguageOptions.EXPERIMENTAL_BUILTINS_BZL_PATH)
1191+
.isEmpty()) {
1192+
return starlarkEnv.getUninjectedWorkspaceBzlEnv();
1193+
}
1194+
fp.addBytes(builtins.transitiveDigest);
1195+
return builtins.predeclaredForWorkspaceBzl;
11891196
} else if (key instanceof BzlLoadValue.KeyForBzlmod) {
11901197
return starlarkEnv.getBzlmodBzlEnv();
11911198
} else if (key instanceof BzlLoadValue.KeyForBuiltins) {

src/main/java/com/google/devtools/build/lib/skyframe/StarlarkBuiltinsFunction.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,18 @@ private static StarlarkBuiltinsValue computeInternal(
174174
exportedToplevels,
175175
exportedRules,
176176
starlarkSemantics.get(BuildLanguageOptions.EXPERIMENTAL_BUILTINS_INJECTION_OVERRIDE));
177+
ImmutableMap<String, Object> predeclaredForWorkspaceBzl =
178+
starlarkEnv.createWorkspaceBzlEnvUsingInjection(
179+
exportedToplevels,
180+
exportedRules,
181+
starlarkSemantics.get(BuildLanguageOptions.EXPERIMENTAL_BUILTINS_INJECTION_OVERRIDE));
177182
ImmutableMap<String, Object> predeclaredForBuild =
178183
starlarkEnv.createBuildEnvUsingInjection(
179184
exportedRules,
180185
starlarkSemantics.get(BuildLanguageOptions.EXPERIMENTAL_BUILTINS_INJECTION_OVERRIDE));
181186
return StarlarkBuiltinsValue.create(
182187
predeclaredForBuildBzl,
188+
predeclaredForWorkspaceBzl,
183189
predeclaredForBuild,
184190
exportedToJava,
185191
transitiveDigest,

src/main/java/com/google/devtools/build/lib/skyframe/StarlarkBuiltinsValue.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ static boolean isBuiltinsRepo(RepositoryName repo) {
6464
*/
6565
public final ImmutableMap<String, Object> predeclaredForBuildBzl;
6666

67+
/**
68+
* Top-level predeclared symbols for a .bzl file loaded on behalf of a WORKSPACE file after
69+
* builtins injection has been applied.
70+
*/
71+
public final ImmutableMap<String, Object> predeclaredForWorkspaceBzl;
72+
6773
/**
6874
* Top-level predeclared symbols for a BUILD file, after builtins injection but before any prelude
6975
* file has been applied.
@@ -81,11 +87,13 @@ static boolean isBuiltinsRepo(RepositoryName repo) {
8187

8288
private StarlarkBuiltinsValue(
8389
ImmutableMap<String, Object> predeclaredForBuildBzl,
90+
ImmutableMap<String, Object> predeclaredForWorkspaceBzl,
8491
ImmutableMap<String, Object> predeclaredForBuild,
8592
ImmutableMap<String, Object> exportedToJava,
8693
byte[] transitiveDigest,
8794
StarlarkSemantics starlarkSemantics) {
8895
this.predeclaredForBuildBzl = predeclaredForBuildBzl;
96+
this.predeclaredForWorkspaceBzl = predeclaredForWorkspaceBzl;
8997
this.predeclaredForBuild = predeclaredForBuild;
9098
this.exportedToJava = exportedToJava;
9199
this.transitiveDigest = transitiveDigest;
@@ -94,12 +102,14 @@ private StarlarkBuiltinsValue(
94102

95103
public static StarlarkBuiltinsValue create(
96104
ImmutableMap<String, Object> predeclaredForBuildBzl,
105+
ImmutableMap<String, Object> predeclaredForWorkspaceBzl,
97106
ImmutableMap<String, Object> predeclaredForBuild,
98107
ImmutableMap<String, Object> exportedToJava,
99108
byte[] transitiveDigest,
100109
StarlarkSemantics starlarkSemantics) {
101110
return new StarlarkBuiltinsValue(
102111
predeclaredForBuildBzl,
112+
predeclaredForWorkspaceBzl,
103113
predeclaredForBuild,
104114
exportedToJava,
105115
transitiveDigest,
@@ -116,10 +126,11 @@ public static StarlarkBuiltinsValue create(
116126
*/
117127
public static StarlarkBuiltinsValue createEmpty(StarlarkSemantics starlarkSemantics) {
118128
return new StarlarkBuiltinsValue(
119-
/*predeclaredForBuildBzl=*/ ImmutableMap.of(),
120-
/*predeclaredForBuild=*/ ImmutableMap.of(),
121-
/*exportedToJava=*/ ImmutableMap.of(),
122-
/*transitiveDigest=*/ new byte[] {},
129+
/* predeclaredForBuildBzl= */ ImmutableMap.of(),
130+
/* predeclaredForWorkspaceBzl= */ ImmutableMap.of(),
131+
/* predeclaredForBuild= */ ImmutableMap.of(),
132+
/* exportedToJava= */ ImmutableMap.of(),
133+
/* transitiveDigest= */ new byte[] {},
123134
starlarkSemantics);
124135
}
125136

src/test/java/com/google/devtools/build/lib/packages/BazelStarlarkEnvironmentTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected ConfiguredRuleClassProvider createRuleClassProvider() {
6161
public void buildAndWorkspaceBzlEnvsDeclareSameNames() throws Exception {
6262
BazelStarlarkEnvironment starlarkEnv = pkgFactory.getBazelStarlarkEnvironment();
6363
Set<String> buildBzlNames = starlarkEnv.getUninjectedBuildBzlEnv().keySet();
64-
Set<String> workspaceBzlNames = starlarkEnv.getWorkspaceBzlEnv().keySet();
64+
Set<String> workspaceBzlNames = starlarkEnv.getUninjectedWorkspaceBzlEnv().keySet();
6565
assertThat(buildBzlNames).isEqualTo(workspaceBzlNames);
6666
}
6767

@@ -72,7 +72,7 @@ public void buildAndWorkspaceBzlEnvsAreSameExceptForNative() throws Exception {
7272
buildBzlEnv.putAll(starlarkEnv.getUninjectedBuildBzlEnv());
7373
buildBzlEnv.remove("native");
7474
Map<String, Object> workspaceBzlEnv = new HashMap<>();
75-
workspaceBzlEnv.putAll(starlarkEnv.getWorkspaceBzlEnv());
75+
workspaceBzlEnv.putAll(starlarkEnv.getUninjectedWorkspaceBzlEnv());
7676
workspaceBzlEnv.remove("native");
7777
assertThat(buildBzlEnv).isEqualTo(workspaceBzlEnv);
7878
}

src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
7373
import com.google.devtools.build.lib.skyframe.RepositoryMappingFunction;
7474
import com.google.devtools.build.lib.skyframe.SkyFunctions;
75+
import com.google.devtools.build.lib.skyframe.StarlarkBuiltinsFunction;
7576
import com.google.devtools.build.lib.skyframe.WorkspaceFileFunction;
7677
import com.google.devtools.build.lib.starlarkbuildapi.repository.RepositoryBootstrap;
7778
import com.google.devtools.build.lib.testutil.FoundationTestCase;
@@ -117,7 +118,9 @@ public class RepositoryDelegatorTest extends FoundationTestCase {
117118
public void setupDelegator() throws Exception {
118119
rootPath = scratch.dir("/outputbase");
119120
scratch.file(
120-
rootPath.getRelative("MODULE.bazel").getPathString(), "module(name='test',version='0.1')");
121+
rootPath.getRelative("MODULE.bazel").getPathString(),
122+
"module(name='test',version='0.1')",
123+
"bazel_dep(name='bazel_tools',version='1.0')");
121124
BlazeDirectories directories =
122125
new BlazeDirectories(
123126
new ServerDirectories(rootPath, rootPath, rootPath),
@@ -162,6 +165,13 @@ public void setupDelegator() throws Exception {
162165
.build(ruleClassProvider, fileSystem);
163166

164167
registryFactory = new FakeRegistry.Factory();
168+
FakeRegistry registry =
169+
registryFactory
170+
.newFakeRegistry(scratch.dir("modules").getPathString())
171+
.addModule(
172+
createModuleKey("bazel_tools", "1.0"),
173+
"module(name='bazel_tools', version='1.0');");
174+
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
165175

166176
HashFunction hashFunction = fileSystem.getDigestFunction().getHashFunction();
167177
evaluator =
@@ -217,6 +227,7 @@ public void setupDelegator() throws Exception {
217227
SkyFunctions.BZL_LOAD,
218228
BzlLoadFunction.create(
219229
pkgFactory, directories, hashFunction, Caffeine.newBuilder().build()))
230+
.put(SkyFunctions.STARLARK_BUILTINS, new StarlarkBuiltinsFunction(pkgFactory))
220231
.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction())
221232
.put(
222233
SkyFunctions.IGNORED_PACKAGE_PREFIXES,
@@ -388,14 +399,6 @@ public void loadRepositoryFromBzlmod() throws Exception {
388399
rootPath.getRelative("MODULE.bazel").getPathString(),
389400
"module(name='aaa',version='0.1')",
390401
"bazel_dep(name='bazel_tools',version='1.0')");
391-
FakeRegistry registry =
392-
registryFactory
393-
.newFakeRegistry(scratch.dir("modules").getPathString())
394-
.addModule(
395-
createModuleKey("bazel_tools", "1.0"),
396-
"module(name='bazel_tools', version='1.0');");
397-
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
398-
// Note that bazel_tools is a well-known module, so its repo name will always be "bazel_tools".
399402
scratch.file(rootPath.getRelative("BUILD").getPathString());
400403
scratch.file(
401404
rootPath.getRelative("repo_rule.bzl").getPathString(),

src/test/java/com/google/devtools/build/lib/skyframe/BuiltinsInjectionTest.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -485,13 +485,8 @@ public void exportsBzlMayBeInErrorWhenInjectionIsDisabled() throws Exception {
485485
assertContainsEvent("In BUILD: overridable_rule :: <built-in rule overridable_rule>");
486486
}
487487

488-
// TODO(#11954): Once WORKSPACE- and BUILD-loaded bzls use the exact same environments, we'll want
489-
// to apply injection to both. This is for uniformity, not because we actually care about builtins
490-
// injection for WORKSPACE bzls. In the meantime, assert the status quo: WORKSPACE bzls do not use
491-
// injection. WORKSPACE and BUILD files themselves probably won't be unified, so WORKSPACE will
492-
// likely continue to not use injection.
493488
@Test
494-
public void workspaceAndWorkspaceBzlDoNotUseInjection() throws Exception {
489+
public void workspaceLoadedBzlUsesInjectionButNotWORKSPACE() throws Exception {
495490
writeExportsBzl(
496491
"exported_toplevels = {'overridable_symbol': 'new_value'}",
497492
"exported_rules = {'overridable_rule': 'new_rule'}",
@@ -510,9 +505,8 @@ public void workspaceAndWorkspaceBzlDoNotUseInjection() throws Exception {
510505
"print('In bzl: overridable_symbol :: %s' % overridable_symbol)");
511506

512507
buildAndAssertSuccess();
513-
// Builtins for WORKSPACE bzls are populated essentially the same as for BUILD bzls, except that
514-
// injection doesn't apply.
515-
assertContainsEvent("In bzl: overridable_symbol :: original_value");
508+
// Builtins for WORKSPACE bzls are populated the same as for BUILD bzls.
509+
assertContainsEvent("In bzl: overridable_symbol :: new_value");
516510
// We don't assert that the rule isn't injected because the workspace native object doesn't
517511
// contain our original mock rule. We can test this for WORKSPACE files at the top-level though.
518512
assertContainsEvent("In WORKSPACE: overridable_rule :: <built-in function overridable_rule>");

0 commit comments

Comments
 (0)