-
Notifications
You must be signed in to change notification settings - Fork 447
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 foundeven 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.