mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-02 23:57:59 +00:00
feat(monorel): skip untracked directories during recursive walk
Add buildTrackedDirs which runs "git ls-files" once from the walk root and builds a set of directories containing at least one tracked file. findMainPackages uses this set to skip untracked directories (dist/, vendor/, node_modules/, build artifacts, etc.) without having to enumerate git-ignored paths explicitly. Falls back to walking everything when git is unavailable or the directory is not inside a repository.
This commit is contained in:
parent
a28fe8ed55
commit
69148f9edb
@ -498,15 +498,24 @@ func expandPaths(paths []string, recursive, all bool) ([]string, error) {
|
|||||||
// any directory listed in stopMarkers (e.g. .git directories), preventing
|
// any directory listed in stopMarkers (e.g. .git directories), preventing
|
||||||
// the walk from crossing into a parent repository.
|
// the walk from crossing into a parent repository.
|
||||||
//
|
//
|
||||||
// By default directories whose names begin with '.' or '_' are skipped (they
|
// Only directories that contain at least one git-tracked file are visited;
|
||||||
// are conventionally hidden or disabled). Pass all=true (the -A flag) to
|
// untracked directories (dist/, vendor/, node_modules/, build artifacts, etc.)
|
||||||
// include them; in that mode ReadDir failures are downgraded to warnings so
|
// are skipped automatically.
|
||||||
|
//
|
||||||
|
// By default directories whose names begin with '.' or '_' are also skipped
|
||||||
|
// (they are conventionally hidden or disabled). Pass all=true (the -A flag)
|
||||||
|
// to include them; in that mode ReadDir failures are downgraded to warnings so
|
||||||
// that a single unreadable directory doesn't abort the whole walk.
|
// that a single unreadable directory doesn't abort the whole walk.
|
||||||
func findMainPackages(root string, all bool) ([]string, error) {
|
func findMainPackages(root string, all bool) ([]string, error) {
|
||||||
abs, err := filepath.Abs(root)
|
abs, err := filepath.Abs(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolving %s: %w", root, err)
|
return nil, fmt.Errorf("resolving %s: %w", root, err)
|
||||||
}
|
}
|
||||||
|
// Build the set of directories that contain at least one tracked file.
|
||||||
|
// Nil means git is unavailable; in that case we fall back to walking
|
||||||
|
// everything (pre-existing behaviour).
|
||||||
|
trackedDirs := buildTrackedDirs(abs)
|
||||||
|
|
||||||
var paths []string
|
var paths []string
|
||||||
var walk func(dir string) error
|
var walk func(dir string) error
|
||||||
walk = func(dir string) error {
|
walk = func(dir string) error {
|
||||||
@ -544,7 +553,12 @@ func findMainPackages(root string, all bool) ([]string, error) {
|
|||||||
if !all && len(name) > 0 && (name[0] == '.' || name[0] == '_') {
|
if !all && len(name) > 0 && (name[0] == '.' || name[0] == '_') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := walk(filepath.Join(dir, name)); err != nil {
|
child := filepath.Join(dir, name)
|
||||||
|
// Skip directories that contain no git-tracked files.
|
||||||
|
if trackedDirs != nil && !trackedDirs[child] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := walk(child); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,6 +567,35 @@ func findMainPackages(root string, all bool) ([]string, error) {
|
|||||||
return paths, walk(abs)
|
return paths, walk(abs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildTrackedDirs runs "git ls-files" from dir and returns the set of all
|
||||||
|
// directories (absolute paths) that contain at least one tracked file.
|
||||||
|
// Returns nil if dir is not inside a git repository or git is unavailable,
|
||||||
|
// in which case the caller proceeds without git-tracking filtering.
|
||||||
|
func buildTrackedDirs(dir string) map[string]bool {
|
||||||
|
cmd := exec.Command("git", "ls-files")
|
||||||
|
cmd.Dir = dir
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dirs := make(map[string]bool)
|
||||||
|
for _, line := range strings.Split(string(out), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
abs := filepath.Join(dir, filepath.FromSlash(line))
|
||||||
|
// Mark every ancestor directory up to (but not including) dir.
|
||||||
|
for d := filepath.Dir(abs); d != dir; d = filepath.Dir(d) {
|
||||||
|
if dirs[d] {
|
||||||
|
break // already added this path and all its ancestors
|
||||||
|
}
|
||||||
|
dirs[d] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dirs
|
||||||
|
}
|
||||||
|
|
||||||
// findModuleRoot walks upward from absDir looking for a directory that
|
// findModuleRoot walks upward from absDir looking for a directory that
|
||||||
// contains go.mod. It stops (with an error) if it encounters a stopMarker
|
// contains go.mod. It stops (with an error) if it encounters a stopMarker
|
||||||
// (default: ".git") before finding go.mod, preventing searches from crossing
|
// (default: ".git") before finding go.mod, preventing searches from crossing
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user