Skip to content

Commit

Permalink
Allow reading the name of the target in the initializer
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 600862478
Change-Id: Iadc38abea17f4b3ec33a8f76245c75ae3aca6d1d
  • Loading branch information
comius authored and copybara-github committed Jan 23, 2024
1 parent dc759e3 commit 723a3ac
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ public Object call(StarlarkThread thread, Tuple args, Dict<String, Object> kwarg
// The less magic the better. Do not give in those temptations!
Dict.Builder<String, Object> initializerKwargs = Dict.builder();
for (var attr : currentRuleClass.getAttributes()) {
if (attr.isPublic() && attr.starlarkDefined()) {
if ((attr.isPublic() && attr.starlarkDefined()) || attr.getName().equals("name")) {
if (kwargs.containsKey(attr.getName())) {
Object value = kwargs.get(attr.getName());
if (value == Starlark.NONE) {
Expand Down Expand Up @@ -1238,6 +1238,12 @@ public Object call(StarlarkThread thread, Tuple args, Dict<String, Object> kwarg
: Dict.cast(ret, String.class, Object.class, "rule's initializer return value");

for (var arg : newKwargs.keySet()) {
if (arg.equals("name")) {
if (!kwargs.get("name").equals(newKwargs.get("name"))) {
throw Starlark.errorf("Initializer can't change the name of the target");
}
continue;
}
checkAttributeName(arg);
if (arg.startsWith("_")) {
// allow setting private attributes from initializers in builtins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,8 @@ StarlarkCallable macro(StarlarkFunction implementation, StarlarkThread thread)
doc =
"Experimental: the Stalark function initializing the attributes of the rule. "
+ "<p>The function is called at load time for each instance of the rule. It's "
+ "called with values of public attributes defined by the rule (not with "
+ "generic attributes, for example <code>name</code> or <code>tags</code>). "
+ "called with <code>name</code> and the values of public attributes defined by"
+ "the rule (not with generic attributes, for example <code>tags</code>). "
+ "<p>It has to return a dictionary from the attribute names to the desired "
+ "values. The attributes that are not returned are unaffected. Returning "
+ "<code>None</code> as value results in using the default value specified in "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2966,7 +2966,7 @@ public void initializer_basic() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" return {'deps': deps + ['//:added']}",
"def impl(ctx): ",
" return [MyInfo(",
Expand Down Expand Up @@ -2994,6 +2994,49 @@ public void initializer_basic() throws Exception {
assertThat((List<String>) info.getValue("deps")).containsExactly("@@//:initial", "@@//:added");
}

@Test
public void initializer_nameUnchanged() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(name, **kwargs):",
" if name != 'my_target':",
" fail()",
" return {'name': name} | kwargs",
"MyInfo = provider()",
"def impl(ctx): ",
" pass",
"my_rule = rule(impl, initializer = initializer)");
scratch.file(
"initializer_testing/BUILD", //
"load(':b.bzl','my_rule')",
"my_rule(name = 'my_target')");

getConfiguredTarget("//initializer_testing:my_target");

assertNoEvents();
}

@Test
public void initializer_nameChanged() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(name, **kwargs):",
" return {'name': 'my_new_name'}",
"def impl(ctx): ",
" pass",
"my_rule = rule(impl, initializer = initializer)");
scratch.file(
"initializer_testing/BUILD", //
"load(':b.bzl','my_rule')",
"my_rule(name = 'my_target')");

reporter.removeHandler(failFastHandler);
reporter.addHandler(ev.getEventCollector());
getConfiguredTarget("//initializer_testing:my_target");

ev.assertContainsError("Error in my_rule: Initializer can't change the name of the target");
}

@Test
@SuppressWarnings("unchecked")
public void initializer_stringListDict() throws Exception {
Expand Down Expand Up @@ -3066,7 +3109,7 @@ public void initializer_legacyAnyType() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(tristate = -1):",
"def initializer(name, tristate = -1):",
" return {'tristate': int(tristate)}",
"def impl(ctx): ",
" return [MyInfo(tristate = ctx.attr.tristate)]",
Expand Down Expand Up @@ -3126,7 +3169,7 @@ public void initializer_withSelect() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(srcs = []):",
"def initializer(name, srcs = []):",
" return {'srcs': srcs + ['b.ml']}",
"def impl(ctx): ",
" return [MyInfo(",
Expand Down Expand Up @@ -3186,7 +3229,7 @@ public void initializer_overridesAttributeDefault() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(deps = ['//:initializer_default']):",
"def initializer(name, deps = ['//:initializer_default']):",
" return {'deps': deps}",
"def impl(ctx): ",
" return [MyInfo(",
Expand Down Expand Up @@ -3221,7 +3264,7 @@ public void initializer_returningNoneSetsDefault() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(deps = ['//:initializer_default']):",
"def initializer(name, deps = ['//:initializer_default']):",
" return {'deps': None}",
"def impl(ctx): ",
" return [MyInfo(",
Expand Down Expand Up @@ -3251,7 +3294,7 @@ public void initializer_omittedValueIsNotPassed() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(srcs):",
"def initializer(name, srcs):",
" return {'srcs': srcs}",
"def impl(ctx): ",
" pass",
Expand All @@ -3278,7 +3321,7 @@ public void initializer_noneValueIsNotPassed() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"MyInfo = provider()",
"def initializer(srcs):",
"def initializer(name, srcs):",
" return {'srcs': srcs}",
"def impl(ctx): ",
" pass",
Expand All @@ -3303,7 +3346,7 @@ public void initializer_noneValueIsNotPassed() throws Exception {
public void initializer_incorrectReturnType() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = []):",
"def initializer(name, srcs = []):",
" return [srcs]",
"def impl(ctx): ",
" pass",
Expand All @@ -3328,7 +3371,7 @@ public void initializer_incorrectReturnType() throws Exception {
public void initializer_incorrectReturnDicts() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = []):",
"def initializer(name, srcs = []):",
" return {True: srcs}",
"def impl(ctx): ",
" pass",
Expand All @@ -3354,7 +3397,7 @@ public void initializer_failsSettingBaseAttribute() throws Exception {
// 'args' is an attribute defined for all executable rules
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" return {'srcs': srcs, 'deps': deps, 'args': ['a']}",
"def impl(ctx): ",
" pass",
Expand All @@ -3381,7 +3424,7 @@ public void initializer_failsSettingBaseAttribute() throws Exception {
public void initializer_failsSettingPrivateAttribute_outsideBuiltins() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" return {'srcs': srcs, '_tool': ':my_tool'}",
"def impl(ctx): ",
" pass",
Expand Down Expand Up @@ -3412,7 +3455,7 @@ public void initializer_settingPrivateAttribute_insideBuiltins() throws Exceptio
scratch.file("initializer_testing/builtins/BUILD", "filegroup(name='my_tool')");
scratch.file(
"initializer_testing/builtins/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" return {'srcs': srcs, '_tool': ':my_tool'}",
"MyInfo = provider()",
"def impl(ctx): ",
Expand Down Expand Up @@ -3443,7 +3486,7 @@ public void initializer_settingPrivateAttribute_insideBuiltins() throws Exceptio
public void initializer_failsSettingUnknownAttr() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" return {'srcs': srcs, 'my_deps': deps}",
"def impl(ctx): ",
" pass",
Expand All @@ -3469,7 +3512,7 @@ public void initializer_failsSettingUnknownAttr() throws Exception {
public void initializer_failsCreatingAnotherRule() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" native.java_library(name = 'jl', srcs = ['a.java'])",
" return {'srcs': srcs, 'deps': deps}",
"def impl(ctx): ",
Expand Down Expand Up @@ -3497,7 +3540,7 @@ public void initializer_failsCreatingAnotherRule() throws Exception {
public void initializer_failsWithExistingRules() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" native.existing_rules()",
" return {'srcs': srcs, 'deps': deps}",
"def impl(ctx): ",
Expand All @@ -3524,7 +3567,7 @@ public void initializer_failsWithExistingRules() throws Exception {
public void initializer_withFails() throws Exception {
scratch.file(
"initializer_testing/b.bzl",
"def initializer(srcs = [], deps = []):",
"def initializer(name, srcs = [], deps = []):",
" fail('Fail called in initializer')",
" return {'srcs': srcs, 'deps': deps}",
"def impl(ctx): ",
Expand Down Expand Up @@ -3653,7 +3696,7 @@ public void extendRule_withInitializers() throws Exception {
scratch.file(
"extend_rule_testing/parent/parent.bzl",
"ParentInfo = provider()",
"def _parent_initializer(srcs, deps):", // only parents attributes
"def _parent_initializer(name, srcs, deps):", // only parents attributes
" return {'deps': deps + ['//extend_rule_testing:parent_dep']}",
"def _impl(ctx):",
" return [ParentInfo()]",
Expand All @@ -3670,7 +3713,7 @@ public void extendRule_withInitializers() throws Exception {
"extend_rule_testing/child.bzl",
"load('//extend_rule_testing/parent:parent.bzl', 'parent_library')",
"ChildInfo = provider()",
"def _child_initializer(srcs, deps, runtime_deps = []):",
"def _child_initializer(name, srcs, deps, runtime_deps = []):",
" return {'deps': deps + [':child_dep'], 'runtime_deps': runtime_deps + [':runtime_dep']}",
"def _impl(ctx):",
" return ctx.super() + [ChildInfo(",
Expand Down

0 comments on commit 723a3ac

Please sign in to comment.