diff options
author | 2018-04-23 12:04:09 -0700 | |
---|---|---|
committer | 2018-04-23 12:05:19 -0700 | |
commit | 981f65bf0a53239c8d5d55a1469c17721a12b2f4 (patch) | |
tree | 097d8c6faea51729bac0e9aee95b2d38eacbcd07 /src/main/java/com/google/devtools/build | |
parent | a4852b5fbf09c40bfebfec6ed231ebeb11950194 (diff) |
Start refactoring elements of the Skylark Build API into their own package.
RELNOTES: None.
PiperOrigin-RevId: 193962460
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/BUILD | 2 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/skylark/BazelBuildApiGlobals.java | 47 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java | 4 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkModules.java | 2 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD | 28 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skylarkbuildapi/LateBoundDefaultApi.java | 24 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkBuildApiGlobals.java (renamed from src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkBuildApiGlobals.java) | 24 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java | 40 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/syntax/Runtime.java | 12 |
9 files changed, 145 insertions, 38 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index faa54bcb36..895ec859d2 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -56,6 +56,7 @@ filegroup( "//src/main/java/com/google/devtools/build/lib/shell:srcs", "//src/main/java/com/google/devtools/build/lib/skyframe/packages:srcs", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization:srcs", + "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi:srcs", "//src/main/java/com/google/devtools/build/lib/skylarkdebug/proto:srcs", "//src/main/java/com/google/devtools/build/lib/skylarkinterface/processor:srcs", "//src/main/java/com/google/devtools/build/lib/ssd:srcs", @@ -552,6 +553,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/profiler/memory:current_rule_tracker", "//src/main/java/com/google/devtools/build/lib/shell", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec", + "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi", "//src/main/java/com/google/devtools/build/lib/vfs", "//src/main/java/com/google/devtools/build/skyframe", "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/BazelBuildApiGlobals.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/BazelBuildApiGlobals.java new file mode 100644 index 0000000000..efd87e7c10 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/BazelBuildApiGlobals.java @@ -0,0 +1,47 @@ +// Copyright 2018 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.analysis.skylark; + +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.skylarkbuildapi.SkylarkBuildApiGlobals; +import com.google.devtools.build.lib.syntax.Environment; +import com.google.devtools.build.lib.syntax.EvalException; +import com.google.devtools.build.lib.syntax.SkylarkUtils; + +/** + * Bazel implementation of {@link SkylarkBuildApiGlobals}: a collection of global skylark build + * API functions that belong in the global namespace. + */ +public class BazelBuildApiGlobals implements SkylarkBuildApiGlobals { + + @Override + public SkylarkLateBoundDefault<?> configurationField( + String fragment, String name, Location loc, Environment env) + throws EvalException { + Class<?> fragmentClass = SkylarkUtils.getFragmentMap(env).get(fragment); + + if (fragmentClass == null) { + throw new EvalException( + loc, + String.format("invalid configuration fragment name '%s'", fragment)); + } + try { + return SkylarkLateBoundDefault.forConfigurationField( + fragmentClass, name, SkylarkUtils.getToolsRepository(env)); + } catch (SkylarkLateBoundDefault.InvalidConfigurationFieldException exception) { + throw new EvalException(loc, exception); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java index 93fe96e32e..bf91cafbab 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkLateBoundDefault.java @@ -27,9 +27,9 @@ import com.google.devtools.build.lib.packages.Attribute.LateBoundDefault; import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; +import com.google.devtools.build.lib.skylarkbuildapi.LateBoundDefaultApi; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; -import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; @@ -50,7 +50,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @AutoCodec public class SkylarkLateBoundDefault<FragmentT> extends AbstractLabelLateBoundDefault<FragmentT> - implements SkylarkValue { + implements LateBoundDefaultApi { private final Method method; private final String fragmentName; 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 17129ee6f4..a85893197e 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 @@ -38,8 +38,8 @@ public final class SkylarkModules { */ public static final ImmutableList<Class<?>> MODULES = ImmutableList.of( + BazelBuildApiGlobals.class, SkylarkAttr.class, - SkylarkBuildApiGlobals.class, SkylarkCommandLine.class, SkylarkNativeModule.class, SkylarkRuleClassFunctions.class); diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD new file mode 100644 index 0000000000..492daee57e --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/BUILD @@ -0,0 +1,28 @@ +# Description: +# This package contains interfaces representing the skylark "build API" +# (but not the implementation of that API). Ultimately, this package +# may be broken out of the Bazel package hierarchy to be standalone. +# Thus, this package should not depend on Bazel-specific packages (only +# those which contain pure-Skylark concepts, such as the interpretter or +# annotation interfaces). + +package(default_visibility = ["//src/main/java/com/google/devtools/build/lib:__pkg__"]) + +licenses(["notice"]) # Apache 2.0 + +filegroup( + name = "srcs", + srcs = glob(["**"]), +) + +java_library( + name = "skylarkbuildapi", + srcs = glob(["*.java"]), + deps = [ + "//src/main/java/com/google/devtools/build/lib:events", + "//src/main/java/com/google/devtools/build/lib:skylarkinterface", + "//src/main/java/com/google/devtools/build/lib:syntax", + "//third_party:guava", + "//third_party:jsr305", + ], +) diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/LateBoundDefaultApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/LateBoundDefaultApi.java new file mode 100644 index 0000000000..080a16f1e3 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/LateBoundDefaultApi.java @@ -0,0 +1,24 @@ +// Copyright 2018 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.skylarkbuildapi; + +import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; + +/** + * The interface for late bound defaults in Skylark. + */ +public interface LateBoundDefaultApi extends SkylarkValue { + // TODO(cparsons): Migrate this API from the Bazel-specific implementation. +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkBuildApiGlobals.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkBuildApiGlobals.java index a8851c92c4..fd24b7ff1e 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkBuildApiGlobals.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkBuildApiGlobals.java @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.devtools.build.lib.analysis.skylark; - +package com.google.devtools.build.lib.skylarkbuildapi; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skylarkinterface.Param; @@ -21,13 +20,12 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.EvalException; -import com.google.devtools.build.lib.syntax.SkylarkUtils; /** * A collection of global skylark build API functions that belong in the global namespace. */ @SkylarkGlobalLibrary -public class SkylarkBuildApiGlobals { +public interface SkylarkBuildApiGlobals { @SkylarkCallable( name = "configuration_field", @@ -52,21 +50,7 @@ public class SkylarkBuildApiGlobals { useLocation = true, useEnvironment = true ) - public SkylarkLateBoundDefault<?> configurationField( + public LateBoundDefaultApi configurationField( String fragment, String name, Location loc, Environment env) - throws EvalException { - Class<?> fragmentClass = SkylarkUtils.getFragmentMap(env).get(fragment); - - if (fragmentClass == null) { - throw new EvalException( - loc, - String.format("invalid configuration fragment name '%s'", fragment)); - } - try { - return SkylarkLateBoundDefault.forConfigurationField( - fragmentClass, name, SkylarkUtils.getToolsRepository(env)); - } catch (SkylarkLateBoundDefault.InvalidConfigurationFieldException exception) { - throw new EvalException(loc, exception); - } - } + throws EvalException; } diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java index 2c269a74d9..3ee297993a 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/SkylarkInterfaceUtils.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.skylarkinterface; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import javax.annotation.Nullable; @@ -22,30 +23,32 @@ import javax.annotation.Nullable; */ public class SkylarkInterfaceUtils { - private static final class ClassAndSkylarkModule { + private static final class ClassWithAnnotation<T extends Annotation> { final Class<?> klass; - final SkylarkModule skylarkModule; + final T annotation; - ClassAndSkylarkModule(Class<?> klass, SkylarkModule skylarkModule) { + ClassWithAnnotation(Class<?> klass, T annotation) { this.klass = klass; - this.skylarkModule = skylarkModule; + this.annotation = annotation; } } @Nullable - private static ClassAndSkylarkModule searchForSkylarkModule(Class<?> classObj) { - if (classObj.isAnnotationPresent(SkylarkModule.class)) { - return new ClassAndSkylarkModule(classObj, classObj.getAnnotation(SkylarkModule.class)); + private static <T extends Annotation> ClassWithAnnotation<T> searchForClassAnnotation( + Class<?> classObj, + Class<T> annotationClass) { + if (classObj.isAnnotationPresent(annotationClass)) { + return new ClassWithAnnotation<T>(classObj, classObj.getAnnotation(annotationClass)); } Class<?> superclass = classObj.getSuperclass(); if (superclass != null) { - ClassAndSkylarkModule result = searchForSkylarkModule(superclass); + ClassWithAnnotation<T> result = searchForClassAnnotation(superclass, annotationClass); if (result != null) { return result; } } for (Class<?> interfaceObj : classObj.getInterfaces()) { - ClassAndSkylarkModule result = searchForSkylarkModule(interfaceObj); + ClassWithAnnotation<T> result = searchForClassAnnotation(interfaceObj, annotationClass); if (result != null) { return result; } @@ -60,8 +63,9 @@ public class SkylarkInterfaceUtils { */ @Nullable public static SkylarkModule getSkylarkModule(Class<?> classObj) { - ClassAndSkylarkModule result = searchForSkylarkModule(classObj); - return result == null ? null : result.skylarkModule; + ClassWithAnnotation<SkylarkModule> result = + searchForClassAnnotation(classObj, SkylarkModule.class); + return result == null ? null : result.annotation; } /** @@ -71,11 +75,23 @@ public class SkylarkInterfaceUtils { */ @Nullable public static Class<?> getParentWithSkylarkModule(Class<?> classObj) { - ClassAndSkylarkModule result = searchForSkylarkModule(classObj); + ClassWithAnnotation<SkylarkModule> result = + searchForClassAnnotation(classObj, SkylarkModule.class); return result == null ? null : result.klass; } /** + * Searches {@code classObj}'s class hierarchy and for a superclass or interface that + * is annotated with {@link SkylarkGlobalLibrary} (including possibly {@code classObj} itself), + * and returns true if one is found. + */ + public static boolean hasSkylarkGlobalLibrary(Class<?> classObj) { + ClassWithAnnotation<SkylarkGlobalLibrary> result = + searchForClassAnnotation(classObj, SkylarkGlobalLibrary.class); + return result != null; + } + + /** * Returns the {@link SkylarkCallable} annotation for the given method, if it exists, and * null otherwise. The first annotation of an overridden version of the method that is found * will be returned, starting with {@code classObj} and following its base classes and 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 c037db2781..86f95b38b7 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 @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary; +import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature; @@ -337,14 +338,19 @@ public final class Runtime { * 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 env the Environment into which to register fields. * @param moduleClass the Class object containing globals. */ public static void setupModuleGlobals(Environment env, Class<?> moduleClass) { try { - if (moduleClass.isAnnotationPresent(SkylarkModule.class)) { + SkylarkModule skylarkModule = SkylarkInterfaceUtils.getSkylarkModule(moduleClass); + if (skylarkModule != null) { env.setup( - moduleClass.getAnnotation(SkylarkModule.class).name(), + skylarkModule.name(), moduleClass.getConstructor().newInstance()); } for (Field field : moduleClass.getDeclaredFields()) { @@ -362,7 +368,7 @@ public final class Runtime { } } } - if (moduleClass.isAnnotationPresent(SkylarkGlobalLibrary.class)) { + if (SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(moduleClass)) { Object moduleInstance = moduleClass.getConstructor().newInstance(); for (String methodName : FuncallExpression.getMethodNames(moduleClass)) { env.setup(methodName, FuncallExpression.getBuiltinCallable(moduleInstance, methodName)); |