diff options
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java | 38 | ||||
-rwxr-xr-x | src/test/shell/bazel/workspace_resolved_test.sh | 47 |
2 files changed, 83 insertions, 2 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java index 9e8e84c172..1a4ec433d3 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java @@ -22,6 +22,7 @@ import static com.google.devtools.build.lib.syntax.Type.STRING_LIST; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.skylark.SkylarkAttr.Descriptor; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.packages.AttributeValueSource; import com.google.devtools.build.lib.packages.Package.NameConflictException; @@ -30,8 +31,10 @@ import com.google.devtools.build.lib.packages.PackageFactory.PackageContext; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException; +import com.google.devtools.build.lib.packages.SkylarkExportable; import com.google.devtools.build.lib.packages.WorkspaceFactoryHelper; import com.google.devtools.build.lib.skylarkbuildapi.repository.RepositoryModuleApi; +import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter; import com.google.devtools.build.lib.syntax.BaseFunction; import com.google.devtools.build.lib.syntax.DotExpression; import com.google.devtools.build.lib.syntax.EvalException; @@ -85,8 +88,11 @@ public class SkylarkRepositoryModule implements RepositoryModuleApi { return new RepositoryRuleFunction(builder); } - private static final class RepositoryRuleFunction extends BaseFunction { + private static final class RepositoryRuleFunction extends BaseFunction + implements SkylarkExportable { private final RuleClass.Builder builder; + private Label extensionLabel; + private String exportedName; public RepositoryRuleFunction(RuleClass.Builder builder) { super("repository_rule", FunctionSignature.KWARGS); @@ -94,12 +100,40 @@ public class SkylarkRepositoryModule implements RepositoryModuleApi { } @Override + public void export(Label extensionLabel, String exportedName) { + this.extensionLabel = extensionLabel; + this.exportedName = exportedName; + } + + @Override + public boolean isExported() { + return extensionLabel != null; + } + + @Override + public void repr(SkylarkPrinter printer) { + if (exportedName == null) { + printer.append("<anonymous skylark repository rule>"); + } else { + printer.append("<skylark repository rule " + extensionLabel + "%" + exportedName + ">"); + } + } + + @Override public Object call( Object[] args, FuncallExpression ast, com.google.devtools.build.lib.syntax.Environment env) throws EvalException, InterruptedException { String ruleClassName = null; Expression function = ast.getFunction(); - if (function instanceof Identifier) { + // If the function ever got exported (the common case), we take the name + // it was exprted to. Only in the not intended case of calling an unexported + // repository function through an exported macro, we fall back, for lack of + // alternatives, to the name in the local context. + // TODO(b/111199163): we probably should disallow the use of non-exported + // repository rules anyway. + if (isExported()) { + ruleClassName = exportedName; + } else if (function instanceof Identifier) { ruleClassName = ((Identifier) function).getName(); } else if (function instanceof DotExpression) { ruleClassName = ((DotExpression) function).getField().getName(); diff --git a/src/test/shell/bazel/workspace_resolved_test.sh b/src/test/shell/bazel/workspace_resolved_test.sh index cc9d9ec6d8..b013c6dcaf 100755 --- a/src/test/shell/bazel/workspace_resolved_test.sh +++ b/src/test/shell/bazel/workspace_resolved_test.sh @@ -388,4 +388,51 @@ EOF expect_log "Failure-message" } +test_indirect_call() { + rm -rf fetchrepo + mkdir fetchrepo + cd fetchrepo + touch BUILD + cat > rule.bzl <<'EOF' +def _trivial_rule_impl(ctx): + ctx.file("BUILD","genrule(name='hello', outs=['hello.txt'], cmd=' echo hello world > $@')") + +trivial_rule = repository_rule( + implementation = _trivial_rule_impl, + attrs = {}, +) +EOF + cat > indirect.bzl <<'EOF' +def call(fn_name, **args): + fn_name(**args) +EOF + cat > WORKSPACE <<'EOF' +load("//:rule.bzl", "trivial_rule") +load("//:indirect.bzl", "call") + +call(trivial_rule, name="foo") +EOF + bazel sync --experimental_repository_resolved_file=../repo.bzl + bazel shutdown; sync; sleep 10 + + cd .. + echo; cat repo.bzl; echo + touch WORKSPACE + cat > BUILD <<'EOF' +load("//:repo.bzl", "resolved") + +ruleclass = "".join([entry["original_rule_class"] for entry in resolved if entry["original_attributes"]["name"]=="foo"]) + +genrule( + name = "ruleclass", + outs = ["ruleclass.txt"], + cmd = "echo %s > $@" % (ruleclass,) +) +EOF + bazel build //:ruleclass + cat `bazel info bazel-genfiles`/ruleclass.txt > ${TEST_log} + expect_log '//:rule.bzl%trivial_rule' + expect_not_log 'fn_name' +} + run_suite "workspace_resolved_test tests" |