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
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 f25aed6..2338b31 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.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 @@
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 @@
}
/**
+ * 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 @@
@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 @@
/**
* @return the current Frame, in which variable side-effects happen.
*/
- private Frame currentFrame() {
+ public Frame currentFrame() {
return isGlobal() ? globalFrame : lexicalFrame;
}
@@ -450,6 +481,7 @@
* @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 @@
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 @@
this.isSkylark = isSkylark;
this.fileContentHashCode = fileContentHashCode;
this.isLoadingPhase = isLoadingPhase;
+ this.callerLabel = callerLabel;
}
/**
@@ -481,6 +515,7 @@
@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 @@
importedExtensions,
isSkylark,
fileContentHashCode,
- isLoadingPhase);
+ isLoadingPhase,
+ label);
+ }
+
+ public Builder setCallerLabel(Label label) {
+ this.label = label;
+ return this;
}
}
@@ -554,6 +595,13 @@
}
/**
+ * 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 @@
/**
* 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) {