diff options
author | cparsons <cparsons@google.com> | 2018-06-21 12:04:59 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-06-21 12:06:20 -0700 |
commit | 474d4a1bd59a1c41d6c23b1ee7fce08df903afc7 (patch) | |
tree | 6609c315bee8cd3639ab6dc9533ec7f66abe1f8f /src | |
parent | f24479d495df540bae634b5ff2dde3177585c2a3 (diff) |
Create a method for initializing build API libraries using object instances instead of object classes.
This allows the caller to, for example, initialize the global library before adding it to a global frame. The skylark interpreter will no longer require that global libraries have a zero-arg constructor.
RELNOTES: None.
PiperOrigin-RevId: 201563608
Diffstat (limited to 'src')
7 files changed, 83 insertions, 41 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java index a71bdab7ad..67a18683e3 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java @@ -34,16 +34,15 @@ public final class SkylarkModules { /** A bootstrap for non-rules-specific globals of the build API. */ private static TopLevelBootstrap topLevelBootstrap = new TopLevelBootstrap( - BazelBuildApiGlobals.class, - SkylarkAttr.class, - SkylarkCommandLine.class, - SkylarkNativeModule.class, - SkylarkRuleClassFunctions.class, + new BazelBuildApiGlobals(), + new SkylarkAttr(), + new SkylarkCommandLine(), + new SkylarkNativeModule(), + new SkylarkRuleClassFunctions(), StructProvider.STRUCT, OutputGroupInfo.SKYLARK_CONSTRUCTOR, ActionsProvider.INSTANCE, DefaultInfo.PROVIDER); - /** * Adds bindings for skylark built-ins and non-rules-specific globals of the build API to * the given environment map builder. 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 e336b3adc9..4f2708e17e 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 @@ -220,7 +220,7 @@ public class BazelRepositoryModule extends BlazeModule { } builder.addRuleDefinition(ruleDefinition); } - builder.addSkylarkBootstrap(new RepositoryBootstrap(SkylarkRepositoryModule.class)); + builder.addSkylarkBootstrap(new RepositoryBootstrap(new SkylarkRepositoryModule())); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/TopLevelBootstrap.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/TopLevelBootstrap.java index 002dc41e4c..27060a2a50 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/TopLevelBootstrap.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/TopLevelBootstrap.java @@ -23,22 +23,22 @@ import com.google.devtools.build.lib.syntax.Runtime; * A {@link Bootstrap} for top-level libraries of the build API. */ public class TopLevelBootstrap implements Bootstrap { - private final Class<? extends SkylarkBuildApiGlobals> skylarkBuildApiGlobals; - private final Class<? extends SkylarkAttrApi> skylarkAttrApi; - private final Class<? extends SkylarkCommandLineApi> skylarkCommandLineApi; - private final Class<? extends SkylarkNativeModuleApi> skylarkNativeModuleApi; - private final Class<? extends SkylarkRuleFunctionsApi<?>> skylarkRuleFunctionsApi; + private final SkylarkBuildApiGlobals skylarkBuildApiGlobals; + private final SkylarkAttrApi skylarkAttrApi; + private final SkylarkCommandLineApi skylarkCommandLineApi; + private final SkylarkNativeModuleApi skylarkNativeModuleApi; + private final SkylarkRuleFunctionsApi<?> skylarkRuleFunctionsApi; private final StructApi.StructProviderApi structProvider; private final OutputGroupInfoApiProvider outputGroupInfoProvider; private final ActionsInfoProviderApi actionsInfoProviderApi; private final DefaultInfoApiProvider<?, ?> defaultInfoProvider; public TopLevelBootstrap( - Class<? extends SkylarkBuildApiGlobals> skylarkBuildApiGlobals, - Class<? extends SkylarkAttrApi> skylarkAttrApi, - Class<? extends SkylarkCommandLineApi> skylarkCommandLineApi, - Class<? extends SkylarkNativeModuleApi> skylarkNativeModuleApi, - Class<? extends SkylarkRuleFunctionsApi<?>> skylarkRuleFunctionsApi, + SkylarkBuildApiGlobals skylarkBuildApiGlobals, + SkylarkAttrApi skylarkAttrApi, + SkylarkCommandLineApi skylarkCommandLineApi, + SkylarkNativeModuleApi skylarkNativeModuleApi, + SkylarkRuleFunctionsApi<?> skylarkRuleFunctionsApi, StructApi.StructProviderApi structProvider, OutputGroupInfoApiProvider outputGroupInfoProvider, ActionsInfoProviderApi actionsInfoProviderApi, @@ -56,11 +56,11 @@ public class TopLevelBootstrap implements Bootstrap { @Override public void addBindingsToBuilder(ImmutableMap.Builder<String, Object> builder) { - Runtime.setupModuleGlobals(builder, skylarkAttrApi); - Runtime.setupModuleGlobals(builder, skylarkBuildApiGlobals); - Runtime.setupModuleGlobals(builder, skylarkCommandLineApi); - Runtime.setupModuleGlobals(builder, skylarkNativeModuleApi); - Runtime.setupModuleGlobals(builder, skylarkRuleFunctionsApi); + Runtime.setupSkylarkLibrary(builder, skylarkAttrApi); + Runtime.setupSkylarkLibrary(builder, skylarkBuildApiGlobals); + Runtime.setupSkylarkLibrary(builder, skylarkCommandLineApi); + Runtime.setupSkylarkLibrary(builder, skylarkNativeModuleApi); + Runtime.setupSkylarkLibrary(builder, skylarkRuleFunctionsApi); builder.put("struct", structProvider); builder.put("OutputGroupInfo", outputGroupInfoProvider); builder.put("Actions", actionsInfoProviderApi); diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/RepositoryBootstrap.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/RepositoryBootstrap.java index 0df43175a6..e982bf9222 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/RepositoryBootstrap.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/RepositoryBootstrap.java @@ -23,14 +23,14 @@ import com.google.devtools.build.lib.syntax.Runtime; */ public class RepositoryBootstrap implements Bootstrap { - private final Class<? extends RepositoryModuleApi> repositoryModuleApiClass; + private final RepositoryModuleApi repositoryModuleApi; - public RepositoryBootstrap(Class<? extends RepositoryModuleApi> repositoryModuleApiClass) { - this.repositoryModuleApiClass = repositoryModuleApiClass; + public RepositoryBootstrap(RepositoryModuleApi repositoryModuleApi) { + this.repositoryModuleApi = repositoryModuleApi; } @Override public void addBindingsToBuilder(Builder<String, Object> builder) { - Runtime.setupModuleGlobals(builder, repositoryModuleApiClass); + Runtime.setupSkylarkLibrary(builder, repositoryModuleApi); } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java index 48129f4955..08c9a2a1cf 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Runtime.java @@ -330,9 +330,12 @@ public final class Runtime { * Convenience overload of {@link #setupModuleGlobals(ImmutableMap.Builder, Class)} to add * bindings directly to an {@link Environment}. * - * @param env the Environment into which to register fields. - * @param moduleClass the Class object containing globals. + * @param env the Environment into which to register fields + * @param moduleClass the Class object containing globals + * @deprecated use {@link #setupSkylarkLibrary} instead (and {@link SkylarkCallable} instead of + * {@link SkylarkSignature}) */ + @Deprecated public static void setupModuleGlobals(Environment env, Class<?> moduleClass) { ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder(); @@ -365,15 +368,16 @@ public final class Runtime { * @param builder the builder for the "bindings" map, which maps from symbol names to objects, * and which will be built into a global frame * @param moduleClass the Class object containing globals + * @deprecated use {@link #setupSkylarkLibrary} instead (and {@link SkylarkCallable} instead of + * {@link SkylarkSignature}) */ + @Deprecated public static void setupModuleGlobals(ImmutableMap.Builder<String, Object> builder, Class<?> moduleClass) { try { - SkylarkModule skylarkModule = SkylarkInterfaceUtils.getSkylarkModule(moduleClass); - if (skylarkModule != null) { - builder.put( - skylarkModule.name(), - moduleClass.getConstructor().newInstance()); + if (SkylarkInterfaceUtils.getSkylarkModule(moduleClass) != null + || SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass)) { + setupSkylarkLibrary(builder, moduleClass.getConstructor().newInstance()); } for (Field field : moduleClass.getDeclaredFields()) { if (field.isAnnotationPresent(SkylarkSignature.class)) { @@ -390,14 +394,53 @@ public final class Runtime { } } } - if (SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass)) { - Object moduleInstance = moduleClass.getConstructor().newInstance(); - for (String methodName : FuncallExpression.getMethodNames(moduleClass)) { - builder.put(methodName, FuncallExpression.getBuiltinCallable(moduleInstance, methodName)); - } - } } catch (ReflectiveOperationException e) { throw new AssertionError(e); } } + + /** + * Adds global (top-level) symbols, provided by the given object, to the given bindings + * builder. + * + * <p>Global symbols may be provided by the given object in the following ways: + * <ul> + * <li>If its class is annotated with {@link SkylarkModule}, an instance of that object is + * a global object with the module's name.</li> + * <li>If its class is annotated with {@link SkylarkGlobalLibrary}, then all of its methods + * which are annotated with + * {@link com.google.devtools.build.lib.skylarkinterface.SkylarkCallable} are global + * callables.</li> + * </ul> + * + * <p>On collisions, this method throws an {@link AssertionError}. Collisions may occur if + * multiple global libraries have functions of the same name, two modules of the same name + * are given, or if two subclasses of the same module are given. + * + * @param builder the builder for the "bindings" map, which maps from symbol names to objects, + * and which will be built into a global frame + * @param moduleInstance the object containing globals + * @throws AssertionError if there are name collisions + * @throws IllegalArgumentException if {@code moduleInstance} is not annotated with + * {@link SkylarkGlobalLibrary} nor {@link SkylarkModule} + */ + public static void setupSkylarkLibrary(ImmutableMap.Builder<String, Object> builder, + Object moduleInstance) { + Class<?> moduleClass = moduleInstance.getClass(); + SkylarkModule skylarkModule = SkylarkInterfaceUtils.getSkylarkModule(moduleClass); + boolean hasSkylarkGlobalLibrary = SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass); + + Preconditions.checkArgument(hasSkylarkGlobalLibrary || skylarkModule != null, + "%s must be annotated with @SkylarkGlobalLibrary or @SkylarkModule", + moduleClass); + + if (skylarkModule != null) { + builder.put(skylarkModule.name(), moduleInstance); + } + if (hasSkylarkGlobalLibrary) { + for (String methodName : FuncallExpression.getMethodNames(moduleClass)) { + builder.put(methodName, FuncallExpression.getBuiltinCallable(moduleInstance, methodName)); + } + } + } } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java index 3bf9f35f86..bf9ad93f04 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java @@ -107,7 +107,7 @@ public class SkylarkRepositoryIntegrationTest extends BuildViewTestCase { if (ruleProvider == null) { ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder(); TestRuleClassProvider.addStandardRules(builder); - builder.addSkylarkBootstrap(new RepositoryBootstrap(SkylarkRepositoryModule.class)); + builder.addSkylarkBootstrap(new RepositoryBootstrap(new SkylarkRepositoryModule())); ruleProvider = builder.build(); } return ruleProvider; diff --git a/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java b/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java index 21ef3d98bf..6d5c1dae35 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java @@ -58,7 +58,7 @@ public abstract class SkylarkTestCase extends BuildViewTestCase { ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder(); SkylarkModules.addSkylarkGlobalsToBuilder(envBuilder); - Runtime.setupModuleGlobals(envBuilder, PlatformCommon.class); + Runtime.setupSkylarkLibrary(envBuilder, new PlatformCommon()); return GlobalFrame.createForBuiltins(envBuilder.build()); } |