Create infrastructure to restrict top-level Starlark objects by flag
As proof of concept, this restricts AnalysisFailureInfo and AnalysisTestResultInfo to be unavailable as top-level symbols without --experimental_analysis_testing_improvements . This is technically a breaking change, but these symbols were unusable before this change, documented as being experimental, and are not included in any binary release of Bazel.
RELNOTES: None.
PiperOrigin-RevId: 217593936
diff --git a/src/test/java/com/google/devtools/build/docgen/SkylarkDocumentationTest.java b/src/test/java/com/google/devtools/build/docgen/SkylarkDocumentationTest.java
index 412a74e..16c0aa8 100644
--- a/src/test/java/com/google/devtools/build/docgen/SkylarkDocumentationTest.java
+++ b/src/test/java/com/google/devtools/build/docgen/SkylarkDocumentationTest.java
@@ -18,7 +18,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-import com.google.devtools.build.docgen.skylark.SkylarkBuiltinMethodDoc;
import com.google.devtools.build.docgen.skylark.SkylarkJavaMethodDoc;
import com.google.devtools.build.docgen.skylark.SkylarkMethodDoc;
import com.google.devtools.build.docgen.skylark.SkylarkModuleDoc;
@@ -87,9 +86,8 @@
Map<String, SkylarkModuleDoc> modules = SkylarkDocumentationCollector.collectModules();
SkylarkModuleDoc topLevel =
modules.remove(SkylarkDocumentationCollector.getTopLevelModule().name());
- for (Map.Entry<String, SkylarkBuiltinMethodDoc> entry :
- topLevel.getBuiltinMethods().entrySet()) {
- docMap.put(entry.getKey(), entry.getValue().getDocumentation());
+ for (SkylarkMethodDoc method : topLevel.getMethods()) {
+ docMap.put(method.getName(), method.getDocumentation());
}
for (Map.Entry<String, SkylarkModuleDoc> entry : modules.entrySet()) {
docMap.put(entry.getKey(), entry.getValue().getDocumentation());
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
index 92b16ec..d89f9fb 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
@@ -2119,7 +2119,9 @@
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//test:r");
- assertContainsEvent("'Provider' object is not callable");
+ assertContainsEvent(
+ "AnalysisTestResultInfo is experimental and thus unavailable with the current flags. "
+ + "It may be enabled by setting --experimental_analysis_testing_improvements");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
index bec987f..071019e 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
@@ -36,6 +36,7 @@
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics.FlagIdentifier;
import com.google.devtools.build.lib.testutil.TestMode;
import java.util.List;
import java.util.Map;
@@ -2296,4 +2297,80 @@
.testIfErrorContains("'AnalysisFailure' has no field 'message'", "val.message")
.testIfErrorContains("'AnalysisFailure' has no field 'label'", "val.label");
}
+
+ @Test
+ public void testExperimentalFlagGuardedValue() throws Exception {
+ // This test uses an arbitrary experimental flag to verify this functionality. If this
+ // experimental flag were to go away, this test may be updated to use any experimental flag.
+ // The flag itself is unimportant to the test.
+ FlagGuardedValue val = FlagGuardedValue.onlyWhenExperimentalFlagIsTrue(
+ FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+ "foo");
+ String errorMessage = "GlobalSymbol is experimental and thus unavailable with the current "
+ + "flags. It may be enabled by setting --experimental_analysis_testing_improvements";
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--experimental_analysis_testing_improvements=true")
+ .setUp("var = GlobalSymbol")
+ .testLookup("var", "foo");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--experimental_analysis_testing_improvements=false")
+ .testIfErrorContains(errorMessage,
+ "var = GlobalSymbol");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--experimental_analysis_testing_improvements=false")
+ .testIfErrorContains(errorMessage,
+ "def my_function():",
+ " var = GlobalSymbol");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--experimental_analysis_testing_improvements=false")
+ .setUp("GlobalSymbol = 'other'",
+ "var = GlobalSymbol")
+ .testLookup("var", "other");
+ }
+
+ @Test
+ public void testIncompatibleFlagGuardedValue() throws Exception {
+ // This test uses an arbitrary incompatible flag to verify this functionality. If this
+ // incompatible flag were to go away, this test may be updated to use any incompatible flag.
+ // The flag itself is unimportant to the test.
+ FlagGuardedValue val = FlagGuardedValue.onlyWhenIncompatibleFlagIsFalse(
+ FlagIdentifier.INCOMPATIBLE_NO_TARGET_OUTPUT_GROUP,
+ "foo");
+ String errorMessage = "GlobalSymbol is deprecated and will be removed soon. It may be "
+ + "temporarily re-enabled by setting --incompatible_no_target_output_group=false";
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--incompatible_no_target_output_group=false")
+ .setUp("var = GlobalSymbol")
+ .testLookup("var", "foo");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--incompatible_no_target_output_group=true")
+ .testIfErrorContains(errorMessage,
+ "var = GlobalSymbol");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--incompatible_no_target_output_group=true")
+ .testIfErrorContains(errorMessage,
+ "def my_function():",
+ " var = GlobalSymbol");
+
+ new SkylarkTest(
+ ImmutableMap.of("GlobalSymbol", val),
+ "--incompatible_no_target_output_group=true")
+ .setUp("GlobalSymbol = 'other'",
+ "var = GlobalSymbol")
+ .testLookup("var", "other");
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
index 4f6c725..ac07655 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/util/EvaluationTestCase.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
import com.google.common.truth.Ordered;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventCollector;
@@ -39,6 +40,7 @@
import com.google.devtools.build.lib.testutil.TestMode;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.junit.Before;
/**
@@ -98,12 +100,17 @@
protected Environment newEnvironmentWithSkylarkOptions(String... skylarkOptions)
throws Exception {
+ return newEnvironmentWithBuiltinsAndSkylarkOptions(ImmutableMap.of(), skylarkOptions);
+ }
+
+ protected Environment newEnvironmentWithBuiltinsAndSkylarkOptions(Map<String, Object> builtins,
+ String... skylarkOptions) throws Exception {
if (testMode == null) {
throw new IllegalArgumentException(
"TestMode is null. Please set a Testmode via setMode() or set the "
+ "Environment manually by overriding newEnvironment()");
}
- return testMode.createEnvironment(getEventHandler(), skylarkOptions);
+ return testMode.createEnvironment(getEventHandler(), builtins, skylarkOptions);
}
/**
@@ -117,6 +124,17 @@
env = newEnvironmentWithSkylarkOptions(skylarkOptions);
}
+ protected void setMode(TestMode testMode, Map<String, Object> builtins,
+ String... skylarkOptions) throws Exception {
+ this.testMode = testMode;
+ env = newEnvironmentWithBuiltinsAndSkylarkOptions(builtins, skylarkOptions);
+ }
+
+ protected void enableSkylarkMode(Map<String, Object> builtins,
+ String... skylarkOptions) throws Exception {
+ setMode(TestMode.SKYLARK, builtins, skylarkOptions);
+ }
+
protected void enableSkylarkMode(String... skylarkOptions) throws Exception {
setMode(TestMode.SKYLARK, skylarkOptions);
}
@@ -589,14 +607,20 @@
*/
protected class SkylarkTest extends ModalTestCase {
private final String[] skylarkOptions;
+ private final Map<String, Object> builtins;
public SkylarkTest(String... skylarkOptions) {
+ this(ImmutableMap.of(), skylarkOptions);
+ }
+
+ public SkylarkTest(Map<String, Object> builtins, String... skylarkOptions) {
+ this.builtins = builtins;
this.skylarkOptions = skylarkOptions;
}
@Override
protected void run(Testable testable) throws Exception {
- enableSkylarkMode(skylarkOptions);
+ enableSkylarkMode(builtins, skylarkOptions);
testable.run();
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/TestMode.java b/src/test/java/com/google/devtools/build/lib/testutil/TestMode.java
index 9b848bd..e850ac6 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/TestMode.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/TestMode.java
@@ -13,13 +13,16 @@
// limitations under the License.
package com.google.devtools.build.lib.testutil;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkModules;
import com.google.devtools.build.lib.events.EventHandler;
-import com.google.devtools.build.lib.packages.BazelLibrary;
import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions;
import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.Environment.GlobalFrame;
import com.google.devtools.build.lib.syntax.Mutability;
import com.google.devtools.build.lib.syntax.SkylarkSemantics;
import com.google.devtools.common.options.OptionsParser;
+import java.util.Map;
/**
* Describes a particular testing mode by determining how the
@@ -36,10 +39,12 @@
public static final TestMode BUILD =
new TestMode() {
@Override
- public Environment createEnvironment(EventHandler eventHandler, String... skylarkOptions)
+ public Environment createEnvironment(EventHandler eventHandler,
+ Map<String, Object> builtins,
+ String... skylarkOptions)
throws Exception {
return Environment.builder(Mutability.create("build test"))
- .setGlobals(BazelLibrary.GLOBALS)
+ .setGlobals(createGlobalFrame(builtins))
.setEventHandler(eventHandler)
.setSemantics(TestMode.parseSkylarkSemantics(skylarkOptions))
.build();
@@ -49,16 +54,26 @@
public static final TestMode SKYLARK =
new TestMode() {
@Override
- public Environment createEnvironment(EventHandler eventHandler, String... skylarkOptions)
+ public Environment createEnvironment(EventHandler eventHandler,
+ Map<String, Object> builtins, String... skylarkOptions)
throws Exception {
return Environment.builder(Mutability.create("skylark test"))
- .setGlobals(BazelLibrary.GLOBALS)
+ .setGlobals(createGlobalFrame(builtins))
.setEventHandler(eventHandler)
.setSemantics(TestMode.parseSkylarkSemantics(skylarkOptions))
.build();
}
};
- public abstract Environment createEnvironment(EventHandler eventHandler, String... skylarkOptions)
- throws Exception;
+ private static GlobalFrame createGlobalFrame(Map<String, Object> builtins) {
+ ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder();
+
+ SkylarkModules.addSkylarkGlobalsToBuilder(envBuilder);
+ envBuilder.putAll(builtins);
+ return GlobalFrame.createForBuiltins(envBuilder.build());
+ }
+
+ public abstract Environment createEnvironment(EventHandler eventHandler,
+ Map<String, Object> builtins,
+ String... skylarkOptions) throws Exception;
}