Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ BEGIN_UNRELEASED_TEMPLATE

{#v0-0-0-fixed}
### Fixed
* Nothing fixed.
* (gazelle) Remove {obj}`py_binary` targets with invalid `srcs`. This includes files
that are not generated or regular files.

{#v0-0-0-added}
### Added
Expand Down
45 changes: 44 additions & 1 deletion gazelle/python/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,14 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
}

collisionErrors := singlylinkedlist.New()
// Create a validFilesMap of mainModules to validate if python macros have valid srcs.
validFilesMap := make(map[string]struct{})

appendPyLibrary := func(srcs *treeset.Set, pyLibraryTargetName string) {
allDeps, mainModules, annotations, err := parser.parse(srcs)
for name := range mainModules {
validFilesMap[name] = struct{}{}
}
if err != nil {
log.Fatalf("ERROR: %v\n", err)
}
Expand Down Expand Up @@ -363,6 +368,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
setAnnotations(*annotations).
generateImportsAttribute()


pyBinary := pyBinaryTarget.build()

result.Gen = append(result.Gen, pyBinary)
Expand Down Expand Up @@ -490,7 +496,8 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
result.Gen = append(result.Gen, pyTest)
result.Imports = append(result.Imports, pyTest.PrivateAttr(config.GazelleImportsKey))
}

emptyRules := py.getRulesWithInvalidSrcs(args, validFilesMap)
result.Empty = append(result.Empty, emptyRules...)
if !collisionErrors.Empty() {
it := collisionErrors.Iterator()
for it.Next() {
Expand All @@ -502,6 +509,42 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
return result
}

// getRulesWithInvalidSrcs checks existing Python rules in the BUILD file and return the rules with invalid source files.
// Invalid source files are files that do not exist or not a target.
func (py *Python) getRulesWithInvalidSrcs(args language.GenerateArgs, validFilesMap map[string]struct{}) (invalidRules []*rule.Rule) {
if args.File == nil {
return
}
for _, file := range args.GenFiles {
validFilesMap[file] = struct{}{}
}

isTarget := func(src string) bool {
return strings.HasPrefix(src, "@") || strings.HasPrefix(src, "//") || strings.HasPrefix(src, ":")
}
for _, existingRule := range args.File.Rules {
actualPyBinaryKind := GetActualKindName(pyBinaryKind, args)
if existingRule.Kind() != actualPyBinaryKind {
continue
}
var hasValidSrcs bool
for _, src := range existingRule.AttrStrings("srcs") {
if isTarget(src) {
hasValidSrcs = true
break
}
if _, ok := validFilesMap[src]; ok {
hasValidSrcs = true
break
}
}
if !hasValidSrcs {
invalidRules = append(invalidRules, newTargetBuilder(pyBinaryKind, existingRule.Name(), "", "", nil, false).build())
}
}
return invalidRules
}

// isBazelPackage determines if the directory is a Bazel package by probing for
// the existence of a known BUILD file name.
func isBazelPackage(dir string) bool {
Expand Down
1 change: 1 addition & 0 deletions gazelle/python/kinds.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var pyKinds = map[string]rule.KindInfo{
SubstituteAttrs: map[string]bool{},
MergeableAttrs: map[string]bool{
"srcs": true,
"imports": true,
},
ResolveAttrs: map[string]bool{
"deps": true,
Expand Down
18 changes: 18 additions & 0 deletions gazelle/python/testdata/remove_invalid_binary/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

py_library(
name = "keep_library",
deps = ["//keep_binary:foo"],
)
py_binary(
name = "remove_invalid_binary",
srcs = ["__main__.py"],
data = ["testdata/test.txt"],
visibility = ["//:__subpackages__"],
)

py_binary(
name = "another_removed_binary",
srcs = ["foo.py"], # eg a now-deleted file that used to have `if __name__` block
imports = ["."],
)
6 changes: 6 additions & 0 deletions gazelle/python/testdata/remove_invalid_binary/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@rules_python//python:defs.bzl", "py_library")

py_library(
name = "keep_library",
deps = ["//keep_binary:foo"],
)
3 changes: 3 additions & 0 deletions gazelle/python/testdata/remove_invalid_binary/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Remove invalid binary

This test case asserts that `py_binary` should be deleted if invalid (no source files).
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

py_binary(
name = "foo",
srcs = ["foo.py"],
visibility = ["//:__subpackages__"],
)

py_library(
name = "keep_binary",
srcs = ["foo.py"],
visibility = ["//:__subpackages__"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library")

py_binary(
name = "foo",
srcs = ["foo.py"],
visibility = ["//:__subpackages__"],
)

py_library(
name = "keep_binary",
srcs = ["foo.py"],
visibility = ["//:__subpackages__"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if __name__ == "__main__":
print("foo")
Empty file.
6 changes: 6 additions & 0 deletions gazelle/python/testdata/respect_kind_mapping/BUILD.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
load("@rules_python//python:defs.bzl", "py_library")

# gazelle:map_kind py_test my_test :mytest.bzl
# gazelle:map_kind py_binary my_bin :mytest.bzl

py_library(
name = "respect_kind_mapping",
Expand All @@ -13,3 +14,8 @@ my_test(
main = "__test__.py",
deps = [":respect_kind_mapping"],
)

my_bin(
name = "my_bin_gets_removed",
srcs = ["__main__.py"],
)
1 change: 1 addition & 0 deletions gazelle/python/testdata/respect_kind_mapping/BUILD.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ load("@rules_python//python:defs.bzl", "py_library")
load(":mytest.bzl", "my_test")

# gazelle:map_kind py_test my_test :mytest.bzl
# gazelle:map_kind py_binary my_bin :mytest.bzl

py_library(
name = "respect_kind_mapping",
Expand Down