diff options
author | 2016-10-27 12:48:22 +0000 | |
---|---|---|
committer | 2016-10-27 17:11:20 +0000 | |
commit | a31bc4eb21c0f07a6558c22f3d17bff656a9648a (patch) | |
tree | e9a5e601287e7fa1ac6c248015f30a59c1bf6722 /src/main/java/com/google/devtools | |
parent | 238839cd79ac7bef427df7e6604992b02eff05b7 (diff) |
Move ToolsRepository out of Environment
Other fields will follow (is_skylark, phase, callerLabel).
The goal is to make Environment (and more generally Skylark) less dependent
on Bazel.
--
MOS_MIGRATED_REVID=137386248
Diffstat (limited to 'src/main/java/com/google/devtools')
5 files changed, 232 insertions, 153 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java index 27733485ab..076c5a8b7f 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java @@ -54,6 +54,7 @@ import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.Environment.Extension; import com.google.devtools.build.lib.syntax.Environment.Phase; import com.google.devtools.build.lib.syntax.Mutability; +import com.google.devtools.build.lib.syntax.SkylarkUtils; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.common.options.OptionsClassProvider; import java.lang.reflect.Constructor; @@ -709,15 +710,17 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { EventHandler eventHandler, String astFileContentHashCode, Map<String, Extension> importMap) { - return Environment.builder(mutability) - .setSkylark() - .setGlobals(globals) - .setEventHandler(eventHandler) - .setFileContentHashCode(astFileContentHashCode) - .setImportedExtensions(importMap) - .setToolsRepository(toolsRepository) - .setPhase(Phase.LOADING) - .build(); + Environment env = + Environment.builder(mutability) + .setSkylark() + .setGlobals(globals) + .setEventHandler(eventHandler) + .setFileContentHashCode(astFileContentHashCode) + .setImportedExtensions(importMap) + .setPhase(Phase.LOADING) + .build(); + SkylarkUtils.setToolsRepository(env, toolsRepository); + return env; } @Override diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java index 189cc1558f..4c2488d557 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java @@ -59,6 +59,7 @@ import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; +import com.google.devtools.build.lib.syntax.SkylarkUtils; import com.google.devtools.build.lib.syntax.Statement; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.ConversionException; @@ -1633,9 +1634,9 @@ public final class PackageFactory { .setGlobals(Environment.DEFAULT_GLOBALS) .setEventHandler(eventHandler) .setImportedExtensions(imports) - .setToolsRepository(ruleClassProvider.getToolsRepository()) .setPhase(Phase.LOADING) .build(); + SkylarkUtils.setToolsRepository(pkgEnv, ruleClassProvider.getToolsRepository()); pkgBuilder.setFilename(buildFilePath) .setMakeEnv(pkgMakeEnv) @@ -1709,9 +1710,9 @@ public final class PackageFactory { Environment.builder(mutability) .setGlobals(Environment.DEFAULT_GLOBALS) .setEventHandler(NullEventHandler.INSTANCE) - .setToolsRepository(ruleClassProvider.getToolsRepository()) .setPhase(Phase.LOADING) .build(); + SkylarkUtils.setToolsRepository(pkgEnv, ruleClassProvider.getToolsRepository()); Package.Builder pkgBuilder = new Package.Builder(packageBuilderHelper.createFreshPackage( packageId, ruleClassProvider.getRunfilesPrefix())); diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java index 975a954d63..0050178c4c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java @@ -85,6 +85,7 @@ import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkNestedSet; import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; +import com.google.devtools.build.lib.syntax.SkylarkUtils; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.ConversionException; import com.google.devtools.build.lib.util.Pair; @@ -232,129 +233,191 @@ public class SkylarkRuleClassFunctions { // TODO(bazel-team): implement attribute copy and other rule properties - @SkylarkSignature(name = "rule", doc = - "Creates a new rule. Store it in a global value, so that it can be loaded and called " - + "from BUILD files.", - returnType = BaseFunction.class, - parameters = { - @Param(name = "implementation", type = BaseFunction.class, - doc = "the function implementing this rule, must have exactly one parameter: " - + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis phase " - + "for each instance of the rule. It can access the attributes provided by the user. " - + "It must create actions to generate all the declared outputs."), - @Param(name = "test", type = Boolean.class, defaultValue = "False", - doc = "Whether this rule is a test rule. " - + "If True, the rule must end with <code>_test</code> (otherwise it must not), " - + "and there must be an action that generates <code>ctx.outputs.executable</code>."), - @Param(name = "attrs", type = SkylarkDict.class, noneable = true, defaultValue = "None", - doc = + @SkylarkSignature( + name = "rule", + doc = + "Creates a new rule. Store it in a global value, so that it can be loaded and called " + + "from BUILD files.", + returnType = BaseFunction.class, + parameters = { + @Param( + name = "implementation", + type = BaseFunction.class, + doc = + "the function implementing this rule, must have exactly one parameter: " + + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis phase " + + "for each instance of the rule. It can access the attributes provided by the " + + "user. It must create actions to generate all the declared outputs." + ), + @Param( + name = "test", + type = Boolean.class, + defaultValue = "False", + doc = + "Whether this rule is a test rule. " + + "If True, the rule must end with <code>_test</code> (otherwise it must not), " + + "and there must be an action that generates <code>ctx.outputs.executable</code>." + ), + @Param( + name = "attrs", + type = SkylarkDict.class, + noneable = true, + defaultValue = "None", + doc = "dictionary to declare all the attributes of the rule. It maps from an attribute name " - + "to an attribute object (see <a href=\"attr.html\">attr</a> module). " - + "Attributes starting with <code>_</code> are private, and can be used to add " - + "an implicit dependency on a label. The attribute <code>name</code> is implicitly " - + "added and must not be specified. Attributes <code>visibility</code>, " - + "<code>deprecation</code>, <code>tags</code>, <code>testonly</code>, and " - + "<code>features</code> are implicitly added and might be overriden."), - // TODO(bazel-team): need to give the types of these builtin attributes - @Param(name = "outputs", type = SkylarkDict.class, callbackEnabled = true, noneable = true, - defaultValue = "None", doc = "outputs of this rule. " - + "It is a dictionary mapping from string to a template name. " - + "For example: <code>{\"ext\": \"%{name}.ext\"}</code>. <br>" - + "The dictionary key becomes an attribute in <code>ctx.outputs</code>. " - + "Similar to computed dependency rule attributes, you can also specify the name of a " - + "function that returns the dictionary. This function can access all rule " - + "attributes that are listed as parameters in its function signature." - + "For example, <code>outputs = _my_func<code> with <code>def _my_func(srcs, deps):" - + "</code> has access to the attributes 'srcs' and 'deps' (if defined)."), - @Param(name = "executable", type = Boolean.class, defaultValue = "False", - doc = "whether this rule is marked as executable or not. If True, " - + "there must be an action that generates <code>ctx.outputs.executable</code>."), - @Param(name = "output_to_genfiles", type = Boolean.class, defaultValue = "False", - doc = "If true, the files will be generated in the genfiles directory instead of the " - + "bin directory. Unless you need it for compatibility with existing rules " - + "(e.g. when generating header files for C++), do not set this flag."), - @Param(name = "fragments", type = SkylarkList.class, generic1 = String.class, - defaultValue = "[]", - doc = "List of names of configuration fragments that the rule requires " - + "in target configuration."), - @Param(name = "host_fragments", type = SkylarkList.class, generic1 = String.class, - defaultValue = "[]", - doc = "List of names of configuration fragments that the rule requires " - + "in host configuration."), - @Param(name = "_skylark_testable", type = Boolean.class, defaultValue = "False", - doc = "<i>(Experimental)</i> " + + "to an attribute object (see <a href=\"attr.html\">attr</a> module). " + + "Attributes starting with <code>_</code> are private, and can be used to add " + + "an implicit dependency on a label. The attribute <code>name</code> is " + + "implicitly added and must not be specified. Attributes <code>visibility</code>, " + + "<code>deprecation</code>, <code>tags</code>, <code>testonly</code>, and " + + "<code>features</code> are implicitly added and might be overriden." + ), + // TODO(bazel-team): need to give the types of these builtin attributes + @Param( + name = "outputs", + type = SkylarkDict.class, + callbackEnabled = true, + noneable = true, + defaultValue = "None", + doc = + "outputs of this rule. " + + "It is a dictionary mapping from string to a template name. " + + "For example: <code>{\"ext\": \"%{name}.ext\"}</code>. <br>" + + "The dictionary key becomes an attribute in <code>ctx.outputs</code>. " + + "Similar to computed dependency rule attributes, you can also specify the name " + + "of a function that returns the dictionary. This function can access all rule " + + "attributes that are listed as parameters in its function signature." + + "For example, <code>outputs = _my_func<code> with <code>def _my_func(srcs, deps):" + + "</code> has access to the attributes 'srcs' and 'deps' (if defined)." + ), + @Param( + name = "executable", + type = Boolean.class, + defaultValue = "False", + doc = + "whether this rule is marked as executable or not. If True, " + + "there must be an action that generates <code>ctx.outputs.executable</code>." + ), + @Param( + name = "output_to_genfiles", + type = Boolean.class, + defaultValue = "False", + doc = + "If true, the files will be generated in the genfiles directory instead of the " + + "bin directory. Unless you need it for compatibility with existing rules " + + "(e.g. when generating header files for C++), do not set this flag." + ), + @Param( + name = "fragments", + type = SkylarkList.class, + generic1 = String.class, + defaultValue = "[]", + doc = + "List of names of configuration fragments that the rule requires " + + "in target configuration." + ), + @Param( + name = "host_fragments", + type = SkylarkList.class, + generic1 = String.class, + defaultValue = "[]", + doc = + "List of names of configuration fragments that the rule requires " + + "in host configuration." + ), + @Param( + name = "_skylark_testable", + type = Boolean.class, + defaultValue = "False", + doc = + "<i>(Experimental)</i> " + "If true, this rule will expose its actions for inspection by rules that depend " + "on it via an <a href=\"ActionsSkylarkApiProvider.html\">actions</a> provider." + "The provider is also available to the rule itself by calling " + "<code>ctx.created_actions()</code>." + "" + "<p>This should only be used for testing the analysis-time behavior of Skylark " - + "rules. This flag may be removed in the future.")}, - useAst = true, useEnvironment = true) - private static final BuiltinFunction rule = new BuiltinFunction("rule") { - @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces - // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK. - public BaseFunction invoke(BaseFunction implementation, Boolean test, Object attrs, - Object implicitOutputs, Boolean executable, Boolean outputToGenfiles, SkylarkList fragments, - SkylarkList hostFragments, Boolean skylarkTestable, FuncallExpression ast, - Environment funcallEnv) - throws EvalException, ConversionException { - funcallEnv.checkLoadingOrWorkspacePhase("rule", ast.getLocation()); - RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL; - RuleClass parent = test ? getTestBaseRule(funcallEnv.getToolsRepository()) - : (executable ? binaryBaseRule : baseRule); - - // We'll set the name later, pass the empty string for now. - RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent); - ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes = - attrObjectToAttributesList(attrs, ast); - - if (skylarkTestable) { - builder.setSkylarkTestable(); - } + + "rules. This flag may be removed in the future." + ) + }, + useAst = true, + useEnvironment = true + ) + private static final BuiltinFunction rule = + new BuiltinFunction("rule") { + @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces + // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK. + public BaseFunction invoke( + BaseFunction implementation, + Boolean test, + Object attrs, + Object implicitOutputs, + Boolean executable, + Boolean outputToGenfiles, + SkylarkList fragments, + SkylarkList hostFragments, + Boolean skylarkTestable, + FuncallExpression ast, + Environment funcallEnv) + throws EvalException, ConversionException { + funcallEnv.checkLoadingOrWorkspacePhase("rule", ast.getLocation()); + RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL; + RuleClass parent = + test + ? getTestBaseRule(SkylarkUtils.getToolsRepository(funcallEnv)) + : (executable ? binaryBaseRule : baseRule); + + // We'll set the name later, pass the empty string for now. + RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent); + ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes = + attrObjectToAttributesList(attrs, ast); - if (executable || test) { - addAttribute( - ast.getLocation(), - builder, - attr("$is_executable", BOOLEAN) - .value(true) - .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target") - .build()); - builder.setOutputsDefaultExecutable(); - } + if (skylarkTestable) { + builder.setSkylarkTestable(); + } - if (implicitOutputs != Runtime.NONE) { - if (implicitOutputs instanceof BaseFunction) { - BaseFunction func = (BaseFunction) implicitOutputs; - SkylarkCallbackFunction callback = new SkylarkCallbackFunction(func, ast, funcallEnv); - builder.setImplicitOutputsFunction( - new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation())); - } else { - builder.setImplicitOutputsFunction( - new SkylarkImplicitOutputsFunctionWithMap( - ImmutableMap.copyOf( - castMap( - implicitOutputs, - String.class, - String.class, - "implicit outputs of the rule class")))); - } - } + if (executable || test) { + addAttribute( + ast.getLocation(), + builder, + attr("$is_executable", BOOLEAN) + .value(true) + .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target") + .build()); + builder.setOutputsDefaultExecutable(); + } - if (outputToGenfiles) { - builder.setOutputToGenfiles(); - } + if (implicitOutputs != Runtime.NONE) { + if (implicitOutputs instanceof BaseFunction) { + BaseFunction func = (BaseFunction) implicitOutputs; + SkylarkCallbackFunction callback = new SkylarkCallbackFunction(func, ast, funcallEnv); + builder.setImplicitOutputsFunction( + new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation())); + } else { + builder.setImplicitOutputsFunction( + new SkylarkImplicitOutputsFunctionWithMap( + ImmutableMap.copyOf( + castMap( + implicitOutputs, + String.class, + String.class, + "implicit outputs of the rule class")))); + } + } - builder.requiresConfigurationFragmentsBySkylarkModuleName( - fragments.getContents(String.class, "fragments")); - builder.requiresHostConfigurationFragmentsBySkylarkModuleName( - hostFragments.getContents(String.class, "host_fragments")); - builder.setConfiguredTargetFunction(implementation); - builder.setRuleDefinitionEnvironment(funcallEnv); - return new RuleFunction(builder, type, attributes, ast.getLocation()); - } - }; + if (outputToGenfiles) { + builder.setOutputToGenfiles(); + } + + builder.requiresConfigurationFragmentsBySkylarkModuleName( + fragments.getContents(String.class, "fragments")); + builder.requiresHostConfigurationFragmentsBySkylarkModuleName( + hostFragments.getContents(String.class, "host_fragments")); + builder.setConfiguredTargetFunction(implementation); + builder.setRuleDefinitionEnvironment(funcallEnv); + return new RuleFunction(builder, type, attributes, ast.getLocation()); + } + }; protected static ImmutableList<Pair<String, Descriptor>> attrObjectToAttributesList( Object attrs, FuncallExpression ast) throws EvalException { diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java index aeb018ff8b..08614ace39 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java @@ -14,8 +14,6 @@ package com.google.devtools.build.lib.syntax; -import static com.google.common.base.Preconditions.checkState; - import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; @@ -353,12 +351,6 @@ public final class Environment implements Freezable { @Nullable private final Label callerLabel; /** - * The path to the tools repository. - * TODO(laurentlb): Remove from Environment - */ - private final String toolsRepository; - - /** * Enters a scope by saving state to a new Continuation * @param function the function whose scope to enter * @param caller the source AST node for the caller @@ -476,8 +468,8 @@ public final class Environment implements Freezable { } /** - * Constructs an Environment. - * This is the main, most basic constructor. + * Constructs an Environment. This is the main, most basic constructor. + * * @param globalFrame a frame for the global Environment * @param dynamicFrame a frame for the dynamic Environment * @param eventHandler an EventHandler for warnings, errors, etc @@ -495,8 +487,7 @@ public final class Environment implements Freezable { boolean isSkylark, @Nullable String fileContentHashCode, Phase phase, - @Nullable Label callerLabel, - String toolsRepository) { + @Nullable Label callerLabel) { this.globalFrame = Preconditions.checkNotNull(globalFrame); this.dynamicFrame = Preconditions.checkNotNull(dynamicFrame); Preconditions.checkArgument(globalFrame.mutability().isMutable()); @@ -506,7 +497,6 @@ public final class Environment implements Freezable { this.isSkylark = isSkylark; this.phase = phase; this.callerLabel = callerLabel; - this.toolsRepository = toolsRepository; this.transitiveHashCode = computeTransitiveContentHashCode(fileContentHashCode, importedExtensions); } @@ -523,7 +513,6 @@ public final class Environment implements Freezable { @Nullable private Map<String, Extension> importedExtensions; @Nullable private String fileContentHashCode; private Label label; - private String toolsRepository; Builder(Mutability mutability) { this.mutability = mutability; @@ -570,12 +559,6 @@ public final class Environment implements Freezable { return this; } - /** Sets the path to the tools repository */ - public Builder setToolsRepository(String toolsRepository) { - this.toolsRepository = toolsRepository; - return this; - } - /** Builds the Environment. */ public Environment build() { Preconditions.checkArgument(mutability.isMutable()); @@ -587,9 +570,6 @@ public final class Environment implements Freezable { if (importedExtensions == null) { importedExtensions = ImmutableMap.of(); } - if (phase == Phase.LOADING) { - Preconditions.checkState(this.toolsRepository != null); - } return new Environment( globalFrame, dynamicFrame, @@ -598,8 +578,7 @@ public final class Environment implements Freezable { isSkylark, fileContentHashCode, phase, - label, - toolsRepository); + label); } public Builder setCallerLabel(Label label) { @@ -929,9 +908,4 @@ public final class Environment implements Freezable { } return ast.eval(this); } - - public String getToolsRepository() { - checkState(toolsRepository != null); - return toolsRepository; - } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkUtils.java new file mode 100644 index 0000000000..875586f4f0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkUtils.java @@ -0,0 +1,38 @@ +// Copyright 2016 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.syntax; + +/** This class contains Bazel-specific functions to extend or interoperate with Skylark. */ +public final class SkylarkUtils { + + public static final String TOOLS_REPOSITORY = "$tools_repository"; + + /** Unsafe version of Environment#update */ + private static void updateEnv(Environment env, String key, Object value) { + try { + env.update(key, value); + } catch (EvalException e) { + throw new AssertionError(e); + } + } + + public static void setToolsRepository(Environment env, String toolsRepository) { + updateEnv(env, TOOLS_REPOSITORY, toolsRepository); + } + + public static String getToolsRepository(Environment env) { + return (String) env.lookup(TOOLS_REPOSITORY); + } +} |