Skip to content

Commit

Permalink
feat: support only updating existing BUILD files
Browse files Browse the repository at this point in the history
  • Loading branch information
jbedard committed Sep 16, 2024
1 parent bf2bb89 commit 642cb3f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 12 deletions.
23 changes: 19 additions & 4 deletions walk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,27 @@ import (
gzflag "github.com/bazelbuild/bazel-gazelle/flag"
)

// GenerationModeType represents one of the generation modes.
type GenerationModeType string

// Generation modes
const (
// Update: update and maintain existing BUILD files
GenerationModeUpdate GenerationModeType = "update"

// Create: create new and update existing BUILD files
GenerationModeCreate GenerationModeType = "create"
)

// TODO(#472): store location information to validate each exclude. They
// may be set in one directory and used in another. Excludes work on
// declared generated files, so we can't just stat.

type walkConfig struct {
excludes []string
ignore bool
follow []string
updateOnly bool
excludes []string
ignore bool
follow []string
}

const walkName = "_walk"
Expand Down Expand Up @@ -70,7 +83,7 @@ func (*Configurer) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config)
func (*Configurer) CheckFlags(fs *flag.FlagSet, c *config.Config) error { return nil }

func (*Configurer) KnownDirectives() []string {
return []string{"exclude", "follow", "ignore"}
return []string{"generation_mode", "exclude", "follow", "ignore"}
}

func (cr *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
Expand All @@ -82,6 +95,8 @@ func (cr *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
if f != nil {
for _, d := range f.Directives {
switch d.Key {
case "generation_mode":
wcCopy.updateOnly = GenerationModeType(strings.TrimSpace(d.Value)) == GenerationModeUpdate
case "exclude":
if err := checkPathMatchPattern(path.Join(rel, d.Value)); err != nil {
log.Printf("the exclusion pattern is not valid %q: %s", path.Join(rel, d.Value), err)
Expand Down
44 changes: 36 additions & 8 deletions walk/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,12 @@ func Walk(c *config.Config, cexts []config.Configurer, dirs []string, mode Mode,
visit(c, cexts, knownDirectives, updateRels, trie, wf, c.RepoRoot, "", false)
}

func visit(c *config.Config, cexts []config.Configurer, knownDirectives map[string]bool, updateRels *UpdateFilter, trie *pathTrie, wf WalkFunc, dir, rel string, updateParent bool) {
// Read and traverse the 'rel' directory, calling the WalkFunc for each directory
// while respecting the `isBazelIgnored` and exclusion directives.
//
// If the given directory is not configured to produce a BUILD the collected files
// will be returned and the WalkFunc will not be called.
func visit(c *config.Config, cexts []config.Configurer, knownDirectives map[string]bool, updateRels *UpdateFilter, trie *pathTrie, wf WalkFunc, dir, rel string, updateParent bool) ([]string, bool) {
haveError := false

ents := make([]fs.DirEntry, 0, len(trie.children))
Expand All @@ -155,14 +160,22 @@ func visit(c *config.Config, cexts []config.Configurer, knownDirectives map[stri
haveError = true
}

c = configure(cexts, knownDirectives, c, rel, f)
wc := getWalkConfig(c)
collectionOnly := f == nil && wc.updateOnly

// Configure the current directory if not only collecting files
if !collectionOnly {
c = configure(cexts, knownDirectives, c, rel, f)
wc = getWalkConfig(c)

if wc.isExcluded(rel, ".") {
return
// If the config of this directory has excluded itself
if wc.isExcluded(rel, ".") {
return nil, false
}
}

var subdirs, regularFiles []string
// Divide the directory entries while filtering out ignored/excluded.
var dirs, regularFiles []string
for _, ent := range ents {
base := ent.Name()
if wc.isExcluded(rel, base) {
Expand All @@ -173,24 +186,39 @@ func visit(c *config.Config, cexts []config.Configurer, knownDirectives map[stri
case ent == nil:
continue
case ent.IsDir():
subdirs = append(subdirs, base)
dirs = append(dirs, base)
default:
regularFiles = append(regularFiles, base)
}
}

var subdirs []string

// Visit subdirectories dividing them into `regularFiles` and `subdirs``
shouldUpdate := updateRels.shouldUpdate(rel, updateParent)
for _, sub := range subdirs {
for _, sub := range dirs {
if subRel := path.Join(rel, sub); updateRels.shouldVisit(subRel, shouldUpdate) {
visit(c, cexts, knownDirectives, updateRels, trie.children[sub], wf, path.Join(dir, sub), subRel, shouldUpdate)
subFiles, shouldMerge := visit(c, cexts, knownDirectives, updateRels, trie.children[sub], wf, path.Join(dir, sub), subRel, shouldUpdate)
if shouldMerge {
for _, f := range subFiles {
regularFiles = append(regularFiles, path.Join(sub, f))
}
} else {
subdirs = append(subdirs, sub)
}
}
}

if collectionOnly {
return regularFiles, true
}

update := !haveError && !wc.ignore && shouldUpdate
if updateRels.shouldCall(rel, updateParent) {
genFiles := findGenFiles(wc, f)
wf(dir, rel, c, update, f, subdirs, regularFiles, genFiles)
}
return nil, false
}

// An UpdateFilter tracks which directories need to be updated
Expand Down

0 comments on commit 642cb3f

Please sign in to comment.