Make Bazel handle visibility through //external: labels correctly: //external: targets can depend on anything and visibility is checked a the edges incoming to said labels.
Fixes #388.
--
MOS_MIGRATED_REVID=101363086
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 52e8508..7cb8012 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -118,6 +118,7 @@
import com.google.devtools.build.lib.rules.workspace.BindRule;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.util.ResourceFileLoader;
+import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
@@ -125,6 +126,7 @@
* A rule class provider implementing the rules Bazel knows.
*/
public class BazelRuleClassProvider {
+ private static final PathFragment EXTERNAL = new PathFragment("external");
/**
* Used by the build encyclopedia generator.
@@ -154,12 +156,17 @@
private void validateDirectPrerequisiteVisibility(
RuleContext.Builder context, ConfiguredTarget prerequisite, String attrName) {
Rule rule = context.getRule();
+ if (rule.getLabel().getPackageFragment().equals(EXTERNAL)) {
+ // //external: labels are special. They have access to everything and visibility is checked
+ // at the edge that points to the //external: label.
+ return;
+ }
Target prerequisiteTarget = prerequisite.getTarget();
Label prerequisiteLabel = prerequisiteTarget.getLabel();
// We don't check the visibility of late-bound attributes, because it would break some
// features.
- if (!context.getRule().getLabel().getPackageName().equals(
- prerequisite.getTarget().getLabel().getPackageName())
+ if (!context.getRule().getLabel().getPackageIdentifier().equals(
+ prerequisite.getTarget().getLabel().getPackageIdentifier())
&& !context.isVisible(prerequisite)) {
if (!context.getConfiguration().checkVisibility()) {
context.ruleWarning(String.format("Target '%s' violates visibility of target "
diff --git a/src/test/shell/bazel/local_repository_test.sh b/src/test/shell/bazel/local_repository_test.sh
index e3f1460..4629ae3 100755
--- a/src/test/shell/bazel/local_repository_test.sh
+++ b/src/test/shell/bazel/local_repository_test.sh
@@ -636,7 +636,12 @@
mkdir $r
touch $r/WORKSPACE
cat > $r/BUILD <<'EOF'
-genrule(name="r", srcs=[], outs=["r.out"], cmd="touch $@")
+genrule(
+ name="r",
+ srcs=[],
+ outs=["r.out"],
+ cmd="touch $@",
+ visibility=["//visibility:public"])
EOF
cat > WORKSPACE <<EOF
@@ -698,4 +703,64 @@
assert_contains "abcxyz" bazel-bin/x.sh
}
+function test_visibility_through_bind() {
+ local r=$TEST_TMPDIR/r
+ rm -fr $r
+ mkdir $r
+
+ cat > $r/BUILD <<EOF
+genrule(
+ name = "public",
+ srcs = ["//external:public"],
+ outs = ["public.out"],
+ cmd = "cp \$< \$@",
+)
+
+genrule(
+ name = "private",
+ srcs = ["//external:private"],
+ outs = ["private.out"],
+ cmd = "cp \$< \$@",
+)
+EOF
+
+ cat > WORKSPACE <<EOF
+local_repository(
+ name = "r",
+ path = "$r",
+)
+
+bind(
+ name = "public",
+ actual = "//:public",
+)
+
+bind(
+ name = "private",
+ actual = "//:private",
+)
+EOF
+
+ cat > BUILD <<EOF
+genrule(
+ name = "public",
+ srcs = [],
+ outs = ["public.out"],
+ cmd = "echo PUBLIC > \$@",
+ visibility = ["//visibility:public"],
+)
+
+genrule(
+ name = "private",
+ srcs = [],
+ outs = ["private.out"],
+ cmd = "echo PRIVATE > \$@",
+)
+EOF
+
+ bazel build @r//:public >& $TEST_log || fail "failed to build public target"
+ bazel build @r//:private >& $TEST_log && fail "could build private target"
+ expect_log "Target '//:private' is not visible from target '@r//:private'"
+}
+
run_suite "local repository tests"