Skip to content

buildozer fails to find targets that are macros with a return value assigned to a variable #1306

@mattnworb

Description

@mattnworb

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

buildtools/edit/edit.go

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
}
only examines nodes in the BUILD file AST which are 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3We're not considering working on this, but happy to review a PR. (No assignee)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions