This commit is contained in:
Valentin Maerten
2026-04-04 10:29:45 +02:00
parent 714ffdb1b5
commit 78e057e9cb
11 changed files with 38 additions and 43 deletions

View File

@@ -14,13 +14,16 @@ type gitignoreRule struct {
matcher *ignore.GitIgnore matcher *ignore.GitIgnore
} }
// loadGitignoreRules reads .gitignore files walking up from dir to rootDir. // loadGitignoreRules walks up from dir collecting .gitignore files.
func loadGitignoreRules(rootDir, dir string) []gitignoreRule { // Stops at the first .git (file or directory) found.
rootDir, _ = filepath.Abs(rootDir) // Returns nil if no .git is found (not in a git repo).
func loadGitignoreRules(dir string) []gitignoreRule {
dir, _ = filepath.Abs(dir) dir, _ = filepath.Abs(dir)
var rules []gitignoreRule var rules []gitignoreRule
foundGit := false
current := dir current := dir
for { for {
lines := readGitignoreLines(filepath.Join(current, ".gitignore")) lines := readGitignoreLines(filepath.Join(current, ".gitignore"))
if len(lines) > 0 { if len(lines) > 0 {
@@ -29,7 +32,8 @@ func loadGitignoreRules(rootDir, dir string) []gitignoreRule {
matcher: ignore.CompileIgnoreLines(lines...), matcher: ignore.CompileIgnoreLines(lines...),
}) })
} }
if current == rootDir { if _, err := os.Stat(filepath.Join(current, ".git")); err == nil {
foundGit = true
break break
} }
parent := filepath.Dir(current) parent := filepath.Dir(current)
@@ -39,6 +43,10 @@ func loadGitignoreRules(rootDir, dir string) []gitignoreRule {
current = parent current = parent
} }
if !foundGit {
return nil
}
return rules return rules
} }
@@ -61,8 +69,8 @@ func readGitignoreLines(path string) []string {
} }
// filterGitignored removes entries from the file map that match gitignore rules. // filterGitignored removes entries from the file map that match gitignore rules.
func filterGitignored(files map[string]bool, rootDir, dir string) map[string]bool { func filterGitignored(files map[string]bool, dir string) map[string]bool {
rules := loadGitignoreRules(rootDir, dir) rules := loadGitignoreRules(dir)
if len(rules) == 0 { if len(rules) == 0 {
return files return files
} }

View File

@@ -34,10 +34,10 @@ func TestGlobsWithGitignore(t *testing.T) {
{Glob: "./*"}, {Glob: "./*"},
} }
filesWithout, err := Globs(dir, globs, false, dir) filesWithout, err := Globs(dir, globs, false)
require.NoError(t, err) require.NoError(t, err)
filesWith, err := Globs(dir, globs, true, dir) filesWith, err := Globs(dir, globs, true)
require.NoError(t, err) require.NoError(t, err)
hasLog := false hasLog := false
@@ -91,7 +91,7 @@ func TestGlobsWithGitignoreNested(t *testing.T) {
{Glob: "./*"}, {Glob: "./*"},
} }
files, err := Globs(subDir, globs, true, dir) files, err := Globs(subDir, globs, true)
require.NoError(t, err) require.NoError(t, err)
for _, f := range files { for _, f := range files {
@@ -112,7 +112,7 @@ func TestGlobsWithGitignoreNoRepo(t *testing.T) {
{Glob: "./*"}, {Glob: "./*"},
} }
files, err := Globs(dir, globs, true, dir) files, err := Globs(dir, globs, true)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, files, 1) assert.Len(t, files, 1)
} }

View File

@@ -10,7 +10,7 @@ import (
"github.com/go-task/task/v3/taskfile/ast" "github.com/go-task/task/v3/taskfile/ast"
) )
func Globs(dir string, globs []*ast.Glob, gitignore bool, rootDir string) ([]string, error) { func Globs(dir string, globs []*ast.Glob, gitignore bool) ([]string, error) {
resultMap := make(map[string]bool) resultMap := make(map[string]bool)
for _, g := range globs { for _, g := range globs {
matches, err := glob(dir, g.Glob) matches, err := glob(dir, g.Glob)
@@ -23,7 +23,7 @@ func Globs(dir string, globs []*ast.Glob, gitignore bool, rootDir string) ([]str
} }
if gitignore { if gitignore {
resultMap = filterGitignored(resultMap, rootDir, dir) resultMap = filterGitignored(resultMap, dir)
} }
return collectKeys(resultMap), nil return collectKeys(resultMap), nil

View File

@@ -2,12 +2,12 @@ package fingerprint
import "fmt" import "fmt"
func NewSourcesChecker(method, tempDir string, dry bool, rootDir string) (SourcesCheckable, error) { func NewSourcesChecker(method, tempDir string, dry bool) (SourcesCheckable, error) {
switch method { switch method {
case "timestamp": case "timestamp":
return NewTimestampChecker(tempDir, dry, rootDir), nil return NewTimestampChecker(tempDir, dry), nil
case "checksum": case "checksum":
return NewChecksumChecker(tempDir, dry, rootDir), nil return NewChecksumChecker(tempDir, dry), nil
case "none": case "none":
return NoneChecker{}, nil return NoneChecker{}, nil
default: default:

View File

@@ -19,14 +19,12 @@ import (
type ChecksumChecker struct { type ChecksumChecker struct {
tempDir string tempDir string
dry bool dry bool
rootDir string
} }
func NewChecksumChecker(tempDir string, dry bool, rootDir string) *ChecksumChecker { func NewChecksumChecker(tempDir string, dry bool) *ChecksumChecker {
return &ChecksumChecker{ return &ChecksumChecker{
tempDir: tempDir, tempDir: tempDir,
dry: dry, dry: dry,
rootDir: rootDir,
} }
} }
@@ -91,7 +89,7 @@ func (*ChecksumChecker) Kind() string {
} }
func (c *ChecksumChecker) checksum(t *ast.Task) (string, error) { func (c *ChecksumChecker) checksum(t *ast.Task) (string, error) {
sources, err := Globs(t.Dir, t.Sources, t.IsGitignore(), c.rootDir) sources, err := Globs(t.Dir, t.Sources, t.IsGitignore())
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@@ -13,14 +13,12 @@ import (
type TimestampChecker struct { type TimestampChecker struct {
tempDir string tempDir string
dry bool dry bool
rootDir string
} }
func NewTimestampChecker(tempDir string, dry bool, rootDir string) *TimestampChecker { func NewTimestampChecker(tempDir string, dry bool) *TimestampChecker {
return &TimestampChecker{ return &TimestampChecker{
tempDir: tempDir, tempDir: tempDir,
dry: dry, dry: dry,
rootDir: rootDir,
} }
} }
@@ -30,7 +28,7 @@ func (checker *TimestampChecker) IsUpToDate(t *ast.Task) (bool, error) {
return false, nil return false, nil
} }
sources, err := Globs(t.Dir, t.Sources, t.IsGitignore(), checker.rootDir) sources, err := Globs(t.Dir, t.Sources, t.IsGitignore())
if err != nil { if err != nil {
return false, nil return false, nil
} }
@@ -56,7 +54,7 @@ func (checker *TimestampChecker) IsUpToDate(t *ast.Task) (bool, error) {
} }
} }
generates, err := Globs(t.Dir, t.Generates, t.IsGitignore(), checker.rootDir) generates, err := Globs(t.Dir, t.Generates, t.IsGitignore())
if err != nil { if err != nil {
return false, nil return false, nil
} }
@@ -114,7 +112,7 @@ func (checker *TimestampChecker) Kind() string {
// Value implements the Checker Interface // Value implements the Checker Interface
func (checker *TimestampChecker) Value(t *ast.Task) (any, error) { func (checker *TimestampChecker) Value(t *ast.Task) (any, error) {
sources, err := Globs(t.Dir, t.Sources, t.IsGitignore(), checker.rootDir) sources, err := Globs(t.Dir, t.Sources, t.IsGitignore())
if err != nil { if err != nil {
return time.Now(), err return time.Now(), err
} }

View File

@@ -13,7 +13,6 @@ type (
method string method string
dry bool dry bool
tempDir string tempDir string
rootDir string
logger *logger.Logger logger *logger.Logger
statusChecker StatusCheckable statusChecker StatusCheckable
sourcesChecker SourcesCheckable sourcesChecker SourcesCheckable
@@ -38,12 +37,6 @@ func WithTempDir(tempDir string) CheckerOption {
} }
} }
func WithRootDir(rootDir string) CheckerOption {
return func(config *CheckerConfig) {
config.rootDir = rootDir
}
}
func WithLogger(logger *logger.Logger) CheckerOption { func WithLogger(logger *logger.Logger) CheckerOption {
return func(config *CheckerConfig) { return func(config *CheckerConfig) {
config.logger = logger config.logger = logger
@@ -93,7 +86,7 @@ func IsTaskUpToDate(
// If no sources checker was given, set up the default one // If no sources checker was given, set up the default one
if config.sourcesChecker == nil { if config.sourcesChecker == nil {
config.sourcesChecker, err = NewSourcesChecker(config.method, config.tempDir, config.dry, config.rootDir) config.sourcesChecker, err = NewSourcesChecker(config.method, config.tempDir, config.dry)
if err != nil { if err != nil {
return false, err return false, err
} }

View File

@@ -46,7 +46,7 @@ func (e *Executor) statusOnError(t *ast.Task) error {
if method == "" { if method == "" {
method = e.Taskfile.Method method = e.Taskfile.Method
} }
checker, err := fingerprint.NewSourcesChecker(method, e.TempDir.Fingerprint, e.Dry, e.Dir) checker, err := fingerprint.NewSourcesChecker(method, e.TempDir.Fingerprint, e.Dry)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -231,7 +231,6 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error {
fingerprint.WithTempDir(e.TempDir.Fingerprint), fingerprint.WithTempDir(e.TempDir.Fingerprint),
fingerprint.WithDry(e.Dry), fingerprint.WithDry(e.Dry),
fingerprint.WithLogger(e.Logger), fingerprint.WithLogger(e.Logger),
fingerprint.WithRootDir(e.Dir),
) )
if err != nil { if err != nil {
return err return err

View File

@@ -203,9 +203,9 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
var checker fingerprint.SourcesCheckable var checker fingerprint.SourcesCheckable
if origTask.Method == "timestamp" { if origTask.Method == "timestamp" {
checker = fingerprint.NewTimestampChecker(e.TempDir.Fingerprint, e.Dry, e.Dir) checker = fingerprint.NewTimestampChecker(e.TempDir.Fingerprint, e.Dry)
} else { } else {
checker = fingerprint.NewChecksumChecker(e.TempDir.Fingerprint, e.Dry, e.Dir) checker = fingerprint.NewChecksumChecker(e.TempDir.Fingerprint, e.Dry)
} }
value, err := checker.Value(&new) value, err := checker.Value(&new)
@@ -226,7 +226,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
continue continue
} }
if cmd.For != nil { if cmd.For != nil {
list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, new.Generates, gitignore, e.Dir, vars, origTask.Location, cache) list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, new.Generates, gitignore, vars, origTask.Location, cache)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -275,7 +275,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
continue continue
} }
if dep.For != nil { if dep.For != nil {
list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, new.Generates, gitignore, e.Dir, vars, origTask.Location, cache) list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, new.Generates, gitignore, vars, origTask.Location, cache)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -347,7 +347,6 @@ func itemsFromFor(
sources []*ast.Glob, sources []*ast.Glob,
generates []*ast.Glob, generates []*ast.Glob,
gitignore bool, gitignore bool,
rootDir string,
vars *ast.Vars, vars *ast.Vars,
location *ast.Location, location *ast.Location,
cache *templater.Cache, cache *templater.Cache,
@@ -370,7 +369,7 @@ func itemsFromFor(
} }
// Get the list from the task sources // Get the list from the task sources
if f.From == "sources" { if f.From == "sources" {
glist, err := fingerprint.Globs(dir, sources, gitignore, rootDir) glist, err := fingerprint.Globs(dir, sources, gitignore)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -384,7 +383,7 @@ func itemsFromFor(
} }
// Get the list from the task generates // Get the list from the task generates
if f.From == "generates" { if f.From == "generates" {
glist, err := fingerprint.Globs(dir, generates, gitignore, rootDir) glist, err := fingerprint.Globs(dir, generates, gitignore)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -205,7 +205,7 @@ func (e *Executor) collectSources(calls []*Call) ([]string, error) {
var sources []string var sources []string
err := e.traverse(calls, func(task *ast.Task) error { err := e.traverse(calls, func(task *ast.Task) error {
files, err := fingerprint.Globs(task.Dir, task.Sources, task.IsGitignore(), e.Dir) files, err := fingerprint.Globs(task.Dir, task.Sources, task.IsGitignore())
if err != nil { if err != nil {
return err return err
} }