From 8ab83f9109cdca7942d54eb092304faacc5a4311 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Mon, 8 Apr 2024 20:52:12 +0200 Subject: [PATCH] Include module file globals in `builtin.proto` This allows consumers of the proto to learn about globals only available in `MODULE.bazel` under a new `ApiContext`. Also adds a smoke test to verify that common symbols are contained in the proto for each API context. --- .../devtools/build/docgen/ApiExporter.java | 6 +++ .../com/google/devtools/build/docgen/BUILD | 1 + .../devtools/build/docgen/SymbolFamilies.java | 30 ++++++++++++- src/main/protobuf/builtin.proto | 1 + .../java/com/google/devtools/build/lib/BUILD | 12 +++++ .../build/lib/BuiltinProtoSmokeTest.java | 45 +++++++++++++++++++ 6 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/google/devtools/build/lib/BuiltinProtoSmokeTest.java diff --git a/src/main/java/com/google/devtools/build/docgen/ApiExporter.java b/src/main/java/com/google/devtools/build/docgen/ApiExporter.java index 2c2c5811ef592f..c8ac24d3263a35 100644 --- a/src/main/java/com/google/devtools/build/docgen/ApiExporter.java +++ b/src/main/java/com/google/devtools/build/docgen/ApiExporter.java @@ -375,6 +375,12 @@ public static void main(String[] args) { builtins, symbols.getGlobals(), globalToDoc, typeNameToConstructor, ApiContext.ALL); appendGlobals( builtins, symbols.getBzlGlobals(), globalToDoc, typeNameToConstructor, ApiContext.BZL); + appendGlobals( + builtins, + symbols.getModuleFileGlobals(), + globalToDoc, + typeNameToConstructor, + ApiContext.MODULE); appendNativeRules(builtins, symbols.getNativeRules()); writeBuiltins(options.outputFile, builtins); diff --git a/src/main/java/com/google/devtools/build/docgen/BUILD b/src/main/java/com/google/devtools/build/docgen/BUILD index 183350d3e5f3c8..5987e037a73ec2 100644 --- a/src/main/java/com/google/devtools/build/docgen/BUILD +++ b/src/main/java/com/google/devtools/build/docgen/BUILD @@ -77,6 +77,7 @@ java_binary( srcs = ["ApiExporter.java"], main_class = "com.google.devtools.build.docgen.ApiExporter", runtime_deps = [ + "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:resolution", "//src/main/java/com/google/devtools/build/lib/bazel/repository", "//src/main/java/net/starlark/java/syntax", ], diff --git a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java index 96b0911b3dec5b..92f350e7a9fc09 100644 --- a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java +++ b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java @@ -39,6 +39,7 @@ public class SymbolFamilies { // Mappings between Starlark names and Starlark entities generated from the fakebuildapi. private final ImmutableMap globals; private final ImmutableMap bzlGlobals; + private final ImmutableMap moduleFileGlobals; public SymbolFamilies( StarlarkDocExpander expander, @@ -53,7 +54,8 @@ public SymbolFamilies( IllegalAccessException, BuildEncyclopediaDocException, ClassNotFoundException, - IOException { + IOException, + InstantiationException { ConfiguredRuleClassProvider configuredRuleClassProvider = createRuleClassProvider(provider); this.nativeRules = ImmutableList.copyOf( @@ -66,6 +68,7 @@ public SymbolFamilies( denyList)); this.globals = Starlark.UNIVERSE; this.bzlGlobals = collectBzlGlobals(configuredRuleClassProvider); + this.moduleFileGlobals = collectModuleFileGlobals(); this.allDocPages = StarlarkDocumentationCollector.getAllDocPages(expander); } @@ -92,6 +95,14 @@ public Map getBzlGlobals() { return bzlGlobals; } + /* + * Returns a mapping between Starlark names and Starlark entities that are available only in MODULE.bazel + * files. + */ + public Map getModuleFileGlobals() { + return moduleFileGlobals; + } + // Returns a mapping between type names and module/type documentation. public ImmutableMap> getAllDocPages() { return allDocPages; @@ -132,10 +143,25 @@ private List collectNativeRules( } private ConfiguredRuleClassProvider createRuleClassProvider(String classProvider) - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, + throws NoSuchMethodException, + InvocationTargetException, + IllegalAccessException, ClassNotFoundException { Class providerClass = Class.forName(classProvider); Method createMethod = providerClass.getMethod("create"); return (ConfiguredRuleClassProvider) createMethod.invoke(null); } + + private ImmutableMap collectModuleFileGlobals() + throws ClassNotFoundException, + NoSuchMethodException, + InvocationTargetException, + InstantiationException, + IllegalAccessException { + Class moduleFileGlobals = + Class.forName("com.google.devtools.build.lib.bazel.bzlmod.ModuleFileGlobals"); + ImmutableMap.Builder moduleFileEnv = ImmutableMap.builder(); + Starlark.addMethods(moduleFileEnv, moduleFileGlobals.getConstructor().newInstance()); + return moduleFileEnv.buildOrThrow(); + } } diff --git a/src/main/protobuf/builtin.proto b/src/main/protobuf/builtin.proto index 9e9fe1977aec55..af44fd3af0cdf1 100644 --- a/src/main/protobuf/builtin.proto +++ b/src/main/protobuf/builtin.proto @@ -57,6 +57,7 @@ enum ApiContext { ALL = 0; BZL = 1; BUILD = 2; + MODULE = 3; } // Generic representation for a Starlark object. If the object is callable diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index 67b96dc878316e..cfd4d6933c9068 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD @@ -149,3 +149,15 @@ test_suite( name = "others", tags = ["-" + n for n in TEST_SUITES], ) + +java_test( + name = "BuiltinProtoSmokeTest", + srcs = ["BuiltinProtoSmokeTest.java"], + data = ["//src/main/java/com/google/devtools/build/lib:gen_api_proto"], + env = {"BUILTIN_PROTO": "$(rlocationpath //src/main/java/com/google/devtools/build/lib:gen_api_proto)"}, + deps = [ + "//src/main/protobuf:builtin_java_proto", + "//third_party:truth", + "@bazel_tools//tools/java/runfiles", + ], +) diff --git a/src/test/java/com/google/devtools/build/lib/BuiltinProtoSmokeTest.java b/src/test/java/com/google/devtools/build/lib/BuiltinProtoSmokeTest.java new file mode 100644 index 00000000000000..a1463a2d92c2ce --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/BuiltinProtoSmokeTest.java @@ -0,0 +1,45 @@ +package com.google.devtools.build.lib; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.stream.Collectors.toMap; + +import com.google.devtools.build.docgen.builtin.BuiltinProtos; +import com.google.devtools.build.runfiles.Runfiles; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class BuiltinProtoSmokeTest { + static BuiltinProtos.Builtins builtins; + + @BeforeClass + public static void loadProto() throws IOException { + Path protoPath = + Path.of(Runfiles.preload().unmapped().rlocation(System.getenv("BUILTIN_PROTO"))); + try (InputStream inputStream = Files.newInputStream(protoPath); + BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) { + builtins = BuiltinProtos.Builtins.parseFrom(bufferedInputStream); + } + } + + @Test + public void hasGlobalCallableFromEachApiContext() { + assertThat( + builtins.getGlobalList().stream() + .filter(BuiltinProtos.Value::hasCallable) + .filter(global -> !global.getCallable().getParamList().isEmpty()) + .collect(toMap(BuiltinProtos.Value::getName, BuiltinProtos.Value::getApiContext))) + .containsAtLeast( + "range", BuiltinProtos.ApiContext.ALL, + "glob", BuiltinProtos.ApiContext.BUILD, + "DefaultInfo", BuiltinProtos.ApiContext.BZL, + "bazel_dep", BuiltinProtos.ApiContext.MODULE); + } +}