-
Notifications
You must be signed in to change notification settings - Fork 444
Description
I'm not sure if this is an actual bug or we are doing something weird, but I've found that if we have a BUILD file with a target which is a macro that returns a value (such as a struct, with the names of a few internally instantiated targets), then a command like buildozer 'print label srcs' //foo
will print an error that the rule cannot be found, even if buildozer 'print label srcs' //foo:*
shows that the rule exists.
I created a repo which reproduces the issue: https://github.com/mattnworb/buildozer-macro-return-issue
For instance, in //hello-world/BUILD.bazel
, there is a target that creates a java_binary
via a macro:
macro_java_binary(
name = "hello-world",
srcs = ["src/main/java/com/mattnworb/example/Main.java"],
main_class = "com.mattnworb.example.Main",
)
❯ buildozer 'print label srcs' //hello-world
//hello-world [src/main/java/com/mattnworb/example/Main.java]
but if the macro is made to return something, and that value is assigned to a variable in the BUILD.bazel file, then buildozer can no longer find the rule/target:
foo = macro_java_binary(
name = "hello-world",
srcs = ["src/main/java/com/mattnworb/example/Main.java"],
main_class = "com.mattnworb.example.Main",
)
❯ buildozer 'print label srcs' //hello-world
/Users/mattbrown/code/buildozer-issue-repro/hello-world/BUILD.bazel: error while executing commands [{[print label srcs]}] on target //hello-world: rule 'hello-world' not found
even though buildozer can execute the command against the target in question, when expanding wildcards:
❯ buildozer 'print label srcs' //hello-world:*
//hello-world [src/main/java/com/mattnworb/example/Main.java]
I think a part of the issue is that
Lines 295 to 325 in be1c24c
func IndexOfRuleByName(f *build.File, name string) (int, *build.Rule) { | |
linenum := -1 | |
if strings.HasPrefix(name, "%") { | |
// "%<LINENUM>" will match the rule which begins at LINENUM. | |
// This is for convenience, "%" is not a valid character in bazel targets. | |
if result, err := strconv.Atoi(name[1:]); err == nil { | |
linenum = result | |
} | |
} | |
for i, stmt := range f.Stmt { | |
call, ok := stmt.(*build.CallExpr) | |
if !ok { | |
continue | |
} | |
r := f.Rule(call) | |
start, _ := call.X.Span() | |
if r.Name() == name || start.Line == linenum { | |
return i, r | |
} | |
// Allow for precisely targeting the package declaration. This | |
// helps adding new load() and license() rules | |
if name == "__pkg__" { | |
if rule, ok := ExprToRule(stmt, "package"); ok { | |
return i, rule | |
} | |
} | |
} | |
return -1, nil | |
} |
CallExpr
, and assigning the return value of a macro (which I can't tell is an unorthodox thing to do?) changes that node to an AssignExpr
.