diff options
author | 2016-03-21 16:20:06 +0000 | |
---|---|---|
committer | 2016-03-21 18:39:21 +0000 | |
commit | 6f15335deac0c04cfae11623efbe745f11e177ff (patch) | |
tree | 6782a0a789abcb2e97d45c9624bbb306a0e8106a /src/main/java/com | |
parent | a15c426bc5dfe9aa16f22553657dee60ccf1b5f5 (diff) |
Make labels in .bzl files in remote repos resolve relative to their repo
For example, if you have a BUILD file that does:
load('@foo//bar:baz.bzl', 'my_rule')
my_rule(...)
If baz.bzl uses Label('//whatever'), this change makes //whatever resolve to
@foo//whatever. Previous to this change, it would be resolved to the repository
the BUILD file using my_rule was in.
RELNOTES[INC]: Labels in .bzl files in remote repositories will be resolved
relative to their repository (instead of the repository the Skylark rule is
used in).
--
MOS_MIGRATED_REVID=117720181
Diffstat (limited to 'src/main/java/com')
7 files changed, 93 insertions, 19 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 798b14db53..efe4573976 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 @@ -518,7 +518,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { EventHandler eventHandler, String astFileContentHashCode, Map<String, Extension> importMap) { - Environment env = Environment.builder(mutability) + return Environment.builder(mutability) .setSkylark() .setGlobals(globals) .setEventHandler(eventHandler) @@ -526,17 +526,17 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { .setImportedExtensions(importMap) .setLoadingPhase() .build(); - return env; } @Override public Environment createSkylarkRuleClassEnvironment( - Mutability mutability, + Label extensionLabel, Mutability mutability, EventHandler eventHandler, String astFileContentHashCode, Map<String, Extension> importMap) { return createSkylarkRuleClassEnvironment( - mutability, globals, eventHandler, astFileContentHashCode, importMap); + mutability, globals.setLabel(extensionLabel), + eventHandler, astFileContentHashCode, importMap); } diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java index f6529a6d82..2f0988f575 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java @@ -49,12 +49,15 @@ public interface RuleClassProvider { * Returns a new Skylark Environment instance for rule creation. * Implementations need to be thread safe. * Be sure to close() the mutability before you return the results of said evaluation. + * + * @param label the location of the rule. * @param mutability the Mutability for the current evaluation context * @param eventHandler the EventHandler for warnings, errors, etc. * @param astFileContentHashCode the hash code identifying this environment. * @return an Environment, in which to evaluate load time skylark forms. */ Environment createSkylarkRuleClassEnvironment( + Label label, Mutability mutability, EventHandler eventHandler, @Nullable String astFileContentHashCode, 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 8ca4b647b3..a6714960a4 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 @@ -42,6 +42,7 @@ import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.RunUnder; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; +import com.google.devtools.build.lib.cmdline.LabelValidator; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; @@ -163,7 +164,7 @@ public class SkylarkRuleClassFunctions { // rules to skylark extensions. Using the same instance would require a large refactoring. // If we don't want to support old built-in rules and Skylark simultaneously // (except for transition phase) it's probably OK. - private static LoadingCache<String, Label> labelCache = + private static final LoadingCache<String, Label> labelCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Label>() { @Override public Label load(String from) throws Exception { @@ -613,16 +614,36 @@ public class SkylarkRuleClassFunctions { + "Example: <br><pre class=language-python>Label(\"//tools:default\")</pre>", returnType = Label.class, mandatoryPositionals = {@Param(name = "label_string", type = String.class, - doc = "the label string")}, - useLocation = true) + doc = "the label string")}, + optionalNamedOnly = {@Param( + name = "relative_to_caller_repository", + type = Boolean.class, + defaultValue = "False", + doc = "whether the label should be resolved relative to the label of the file this " + + "function is called from.")}, + useLocation = true, + useEnvironment = true) private static final BuiltinFunction label = new BuiltinFunction("Label") { - public Label invoke(String labelString, - Location loc) throws EvalException, ConversionException { - try { - return labelCache.get(labelString); - } catch (ExecutionException e) { - throw new EvalException(loc, "Illegal absolute label syntax: " + labelString); + @SuppressWarnings({"unchecked", "unused"}) + public Label invoke( + String labelString, Boolean relativeToCallerRepository, Location loc, Environment env) + throws EvalException { + Label parentLabel = null; + if (relativeToCallerRepository) { + parentLabel = env.getCallerLabel(); + } else { + parentLabel = env.getGlobals().label(); + } + try { + if (parentLabel != null) { + LabelValidator.parseAbsoluteLabel(labelString); + labelString = parentLabel.getRelative(labelString) + .getUnambiguousCanonicalForm(); } + return labelCache.get(labelString); + } catch (LabelValidator.BadLabelException | LabelSyntaxException | ExecutionException e) { + throw new EvalException(loc, "Illegal absolute label syntax: " + labelString); + } } }; diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java index a264278fee..db0f9709f6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java @@ -69,6 +69,7 @@ public final class SkylarkRuleConfiguredTargetBuilder { SkylarkRuleContext skylarkRuleContext = new SkylarkRuleContext(ruleContext, Kind.RULE); Environment env = Environment.builder(mutability) .setSkylark() + .setCallerLabel(ruleContext.getLabel()) .setGlobals( ruleContext.getRule().getRuleClassObject().getRuleDefinitionEnvironment().getGlobals()) .setEventHandler(ruleContext.getAnalysisEnvironment().getEventHandler()) diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java index c030cccb15..e0bafdfd46 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java @@ -105,6 +105,7 @@ public class ASTFileLookupFunction implements SkyFunction { ast = BuildFileAST.parseSkylarkFile(path, astFileSize, env.getListener(), new ValidationEnvironment( ruleClassProvider.createSkylarkRuleClassEnvironment( + fileLabel, mutability, env.getListener(), // the two below don't matter for extracting the ValidationEnvironment: diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java index 47ee3efcac..c4889fa7d8 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java @@ -360,7 +360,7 @@ public class SkylarkImportLookupFunction implements SkyFunction { com.google.devtools.build.lib.syntax.Environment extensionEnv = ruleClassProvider .createSkylarkRuleClassEnvironment( - mutability, eventHandler, ast.getContentHashCode(), importMap) + extensionLabel, mutability, eventHandler, ast.getContentHashCode(), importMap) .setupOverride("native", packageFactory.getNativeModule(inWorkspace)); ast.exec(extensionEnv, eventHandler); try { 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 f25aed6aa2..2338b3183f 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 @@ -18,6 +18,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.EventKind; @@ -98,10 +99,14 @@ public final class Environment implements Freezable { private final Mutability mutability; final Frame parent; final Map<String, Object> bindings = new HashMap<>(); + // The label for the target this frame is defined in (e.g., //foo:bar.bzl). + @Nullable + private Label label; - Frame(Mutability mutability, Frame parent) { + private Frame(Mutability mutability, Frame parent) { this.mutability = mutability; this.parent = parent; + this.label = parent == null ? null : parent.label; } @Override @@ -110,6 +115,25 @@ public final class Environment implements Freezable { } /** + * Attaches a label to an existing frame. This is used to get the repository a Skylark + * extension is actually defined in. + * @param label the label to attach. + * @return a new Frame with the existing frame's properties plus the label. + */ + public Frame setLabel(Label label) { + this.label = label; + return this; + } + + /** + * Returns the label for this frame. + */ + @Nullable + public final Label label() { + return label; + } + + /** * Gets a binding from the current frame or if not found its parent. * @param varname the name of the variable to be bound * @return the value bound to variable @@ -325,6 +349,13 @@ public final class Environment implements Freezable { @Nullable private Continuation continuation; /** + * Gets the label of the BUILD file that is using this environment. For example, if a target + * //foo has a dependency on //bar which is a Skylark rule defined in //rules:my_rule.bzl being + * evaluated in this environment, then this would return //foo. + */ + @Nullable private final Label callerLabel; + + /** * 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 @@ -394,7 +425,7 @@ public final class Environment implements Freezable { /** * @return the current Frame, in which variable side-effects happen. */ - private Frame currentFrame() { + public Frame currentFrame() { return isGlobal() ? globalFrame : lexicalFrame; } @@ -450,6 +481,7 @@ public final class Environment implements Freezable { * @param isSkylark true if in Skylark context * @param fileContentHashCode a hash for the source file being evaluated, if any * @param isLoadingPhase true if in loading phase + * @param callerLabel the label this environment came from */ private Environment( Frame globalFrame, @@ -458,7 +490,8 @@ public final class Environment implements Freezable { Map<String, Extension> importedExtensions, boolean isSkylark, @Nullable String fileContentHashCode, - boolean isLoadingPhase) { + boolean isLoadingPhase, + @Nullable Label callerLabel) { this.globalFrame = Preconditions.checkNotNull(globalFrame); this.dynamicFrame = Preconditions.checkNotNull(dynamicFrame); Preconditions.checkArgument(globalFrame.mutability().isMutable()); @@ -468,6 +501,7 @@ public final class Environment implements Freezable { this.isSkylark = isSkylark; this.fileContentHashCode = fileContentHashCode; this.isLoadingPhase = isLoadingPhase; + this.callerLabel = callerLabel; } /** @@ -481,6 +515,7 @@ public final class Environment implements Freezable { @Nullable private EventHandler eventHandler; @Nullable private Map<String, Extension> importedExtensions; @Nullable private String fileContentHashCode; + private Label label; Builder(Mutability mutability) { this.mutability = mutability; @@ -545,7 +580,13 @@ public final class Environment implements Freezable { importedExtensions, isSkylark, fileContentHashCode, - isLoadingPhase); + isLoadingPhase, + label); + } + + public Builder setCallerLabel(Label label) { + this.label = label; + return this; } } @@ -554,6 +595,13 @@ public final class Environment implements Freezable { } /** + * Returns the caller's label. + */ + public Label getCallerLabel() { + return callerLabel; + } + + /** * Sets a binding for a special dynamic variable in this Environment. * This is not for end-users, and will throw an AssertionError in case of conflict. * @param varname the name of the dynamic variable to be bound @@ -856,7 +904,7 @@ public final class Environment implements Freezable { /** * Parses some String input without a supporting file, returning statements and comments. - * @param input a list of lines of code + * @param inputLines a list of lines of code */ @VisibleForTesting Parser.ParseResult parseFileWithComments(String... inputLines) { |