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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions