aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
authorGravatar Kristina Chodorow <kchodorow@google.com>2016-03-21 16:20:06 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-03-21 18:39:21 +0000
commit6f15335deac0c04cfae11623efbe745f11e177ff (patch)
tree6782a0a789abcb2e97d45c9624bbb306a0e8106a /src/main/java/com
parenta15c426bc5dfe9aa16f22553657dee60ccf1b5f5 (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')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java39
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/Environment.java58
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) {