Fix relative label parsing with Starlark toolchain APIs.
- Use a LabelConversionContext in rule.toolchains to improve parsing.
- Update StarlarkToolchainContext to properly resolve labels using LabelConversionContext.
- Also move label conversion into the LabelConversionContext so it can be shared more widely.
PiperOrigin-RevId: 368044826
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index 4932b10..4a3d8c1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -2244,6 +2244,7 @@
":resolved_toolchain_context",
"//src/main/java/com/google/devtools/build/lib/analysis/platform",
"//src/main/java/com/google/devtools/build/lib/cmdline",
+ "//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform",
"//src/main/java/net/starlark/java/eval",
"//third_party:auto_value",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
index a6e7bec..8bafe6c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
@@ -46,7 +46,6 @@
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.LabelValidator;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.Attribute;
@@ -57,6 +56,7 @@
import com.google.devtools.build.lib.packages.BazelStarlarkContext;
import com.google.devtools.build.lib.packages.BuildSetting;
import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext;
import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy;
import com.google.devtools.build.lib.packages.ExecGroup;
import com.google.devtools.build.lib.packages.FunctionSplitTransitionAllowlist;
@@ -477,19 +477,22 @@
* Parses a sequence of label strings with a repo mapping.
*
* @param inputs sequence of input strings
- * @param mapping repository mapping
+ * @param thread repository mapping
* @param adjective describes the purpose of the label; used for errors
* @throws EvalException if the label can't be parsed
*/
private static ImmutableList<Label> parseLabels(
- Iterable<String> inputs,
- ImmutableMap<RepositoryName, RepositoryName> mapping,
- String adjective)
- throws EvalException {
+ Iterable<String> inputs, StarlarkThread thread, String adjective) throws EvalException {
ImmutableList.Builder<Label> parsedLabels = new ImmutableList.Builder<>();
+ BazelStarlarkContext bazelStarlarkContext = BazelStarlarkContext.from(thread);
+ LabelConversionContext context =
+ new LabelConversionContext(
+ BazelModuleContext.of(Module.ofInnermostEnclosingStarlarkFunction(thread)).label(),
+ bazelStarlarkContext.getRepoMapping(),
+ bazelStarlarkContext.getConvertedLabelsInPackage());
for (String input : inputs) {
try {
- Label label = Label.parseAbsolute(input, mapping);
+ Label label = context.convert(input);
parsedLabels.add(label);
} catch (LabelSyntaxException e) {
throw Starlark.errorf(
@@ -501,18 +504,13 @@
private static ImmutableList<Label> parseToolchains(Sequence<?> inputs, StarlarkThread thread)
throws EvalException {
- return parseLabels(
- Sequence.cast(inputs, String.class, "toolchains"),
- BazelStarlarkContext.from(thread).getRepoMapping(),
- "toolchain");
+ return parseLabels(Sequence.cast(inputs, String.class, "toolchains"), thread, "toolchain");
}
private static ImmutableList<Label> parseExecCompatibleWith(
Sequence<?> inputs, StarlarkThread thread) throws EvalException {
return parseLabels(
- Sequence.cast(inputs, String.class, "exec_compatible_with"),
- BazelStarlarkContext.from(thread).getRepoMapping(),
- "constraint");
+ Sequence.cast(inputs, String.class, "exec_compatible_with"), thread, "constraint");
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java
index d195acc..a75e6f3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java
@@ -21,9 +21,13 @@
import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.packages.BazelModuleContext;
+import com.google.devtools.build.lib.packages.BazelStarlarkContext;
+import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext;
import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainContextApi;
import javax.annotation.Nullable;
import net.starlark.java.eval.EvalException;
+import net.starlark.java.eval.Module;
import net.starlark.java.eval.Printer;
import net.starlark.java.eval.Starlark;
import net.starlark.java.eval.StarlarkSemantics;
@@ -84,9 +88,15 @@
return ((ToolchainTypeInfo) key).typeLabel();
} else if (key instanceof String) {
try {
- // TODO(jcater): Use LabelConversionContext and StarlarkThread to convert this instead.
- // Also remove repoMapping from ResolvedToolchainContext.
- return Label.parseAbsolute((String) key, toolchainContext().repoMapping());
+ BazelStarlarkContext bazelStarlarkContext = BazelStarlarkContext.from(starlarkThread);
+ LabelConversionContext context =
+ new LabelConversionContext(
+ BazelModuleContext.of(Module.ofInnermostEnclosingStarlarkFunction(starlarkThread))
+ .label(),
+ bazelStarlarkContext.getRepoMapping(),
+ bazelStarlarkContext.getConvertedLabelsInPackage());
+
+ return context.convert((String) key);
} catch (LabelSyntaxException e) {
throw Starlark.errorf("Unable to parse toolchain label '%s': %s", key, e.getMessage());
}
diff --git a/src/test/shell/bazel/toolchain_test.sh b/src/test/shell/bazel/toolchain_test.sh
index d7ef1e3..2a21543 100755
--- a/src/test/shell/bazel/toolchain_test.sh
+++ b/src/test/shell/bazel/toolchain_test.sh
@@ -2135,6 +2135,104 @@
expect_log 'Inner toolchain //inner:impl'
}
+# Test that toolchain type labels are correctly resolved relative to the
+# enclosing file, regardless of the repository name.
+# See http://b/183060658 for details.
+function test_repository_relative_toolchain_type() {
+ # Create a repository that defines a toolchain type and simple rule.
+ # The toolchain type used in the repository is relative to the repository.
+ mkdir -p external/rules_foo
+ touch external/rules_foo/WORKSPACE
+ mkdir -p external/rules_foo/rule
+ touch external/rules_foo/rule/BUILD
+ cat > external/rules_foo/rule/rule.bzl <<EOF
+def _foo_impl(ctx):
+ print(ctx.toolchains["//toolchain:foo_toolchain_type"])
+ return []
+
+foo_rule = rule(
+ implementation = _foo_impl,
+ toolchains = ["//toolchain:foo_toolchain_type"],
+)
+EOF
+ mkdir -p external/rules_foo/toolchain/
+ cat > external/rules_foo/toolchain/BUILD <<EOF
+load(":toolchain.bzl", "foo_toolchain")
+
+toolchain_type(
+ name = "foo_toolchain_type",
+ visibility = ["//visibility:public"],
+)
+
+foo_toolchain(
+ name = "foo_toolchain",
+ visibility = ["//visibility:public"],
+)
+
+toolchain(
+ name = "foo_default_toolchain",
+ toolchain = ":foo_toolchain",
+ toolchain_type = ":foo_toolchain_type",
+)
+EOF
+ cat > external/rules_foo/toolchain/toolchain.bzl <<EOF
+_ATTRS = dict(
+ foo_tool = attr.label(
+ allow_files = True,
+ default = "//foo_tools:foo_tool",
+ ),
+)
+
+def _impl(ctx):
+ return [platform_common.ToolchainInfo(
+ **{name: getattr(ctx.attr, name) for name in _ATTRS.keys()}
+ )]
+
+foo_toolchain = rule(
+ implementation = _impl,
+ attrs = _ATTRS,
+)
+EOF
+ mkdir -p external/rules_foo/foo_tools
+ cat > external/rules_foo/foo_tools/BUILD <<EOF
+sh_binary(
+ name = "foo_tool",
+ srcs = ["foo_tool.sh"],
+ visibility = ["//visibility:public"],
+)
+EOF
+ cat > external/rules_foo/foo_tools/foo_tool.sh <<EOF
+echo creating \$1
+touch \$1
+EOF
+ chmod +x external/rules_foo/foo_tools/foo_tool.sh
+
+ # Create a target that uses the rule.
+ mkdir -p demo
+ cat > demo/BUILD <<EOF
+load("@rules_foo//rule:rule.bzl", "foo_rule")
+
+foo_rule(name = "demo")
+EOF
+
+ # Set up the WORKSPACE.
+ cat >> WORKSPACE <<EOF
+local_repository(
+ name = "rules_foo",
+ path = "external/rules_foo",
+)
+
+register_toolchains(
+ "@rules_foo//toolchain:foo_default_toolchain",
+)
+EOF
+
+ # Test the build.
+ bazel build \
+ //demo:demo &> $TEST_log || fail "Build failed"
+ expect_log "foo_tool = <target @rules_foo//foo_tools:foo_tool>"
+}
+
# TODO(katre): Test using toolchain-provided make variables from a genrule.
run_suite "toolchain tests"