1
0
mirror of https://github.com/go-task/task.git synced 2025-08-08 22:36:57 +02:00

fix(watcher): fix some v3.43.x regressions (#2271)

This commit is contained in:
Andrey Nering
2025-06-08 19:44:08 -03:00
committed by GitHub
parent 9cc2d65091
commit 7782bc92ae
2 changed files with 85 additions and 62 deletions

128
watch.go
View File

@ -19,6 +19,8 @@ import (
"github.com/go-task/task/v3/internal/fingerprint"
"github.com/go-task/task/v3/internal/fsnotifyext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/slicesext"
"github.com/go-task/task/v3/taskfile/ast"
)
const defaultWaitTime = 100 * time.Millisecond
@ -85,17 +87,22 @@ func (e *Executor) watchTasks(calls ...*Call) error {
for _, c := range calls {
c := c
go func() {
if ShouldIgnore(event.Name) {
e.Logger.VerboseErrf(logger.Magenta, "task: event skipped for being an ignored dir: %s\n", event.Name)
return
}
t, err := e.GetTask(c)
if err != nil {
e.Logger.Errf(logger.Red, "%v\n", err)
return
}
baseDir := filepathext.SmartJoin(e.Dir, t.Dir)
files, err := fingerprint.Globs(baseDir, t.Sources)
files, err := e.collectSources(calls)
if err != nil {
e.Logger.Errf(logger.Red, "%v\n", err)
return
}
if !event.Has(fsnotify.Remove) && !slices.Contains(files, event.Name) {
relPath, _ := filepath.Rel(baseDir, event.Name)
e.Logger.VerboseErrf(logger.Magenta, "task: skipped for file not in sources: %s\n", relPath)
@ -158,65 +165,36 @@ func closeOnInterrupt(w *fsnotify.Watcher) {
}
func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) error {
var registerTaskDirs func(*Call) error
registerTaskDirs = func(c *Call) error {
task, err := e.CompiledTask(c)
if err != nil {
return err
}
for _, d := range task.Deps {
if err := registerTaskDirs(&Call{Task: d.Task, Vars: d.Vars}); err != nil {
return err
}
}
for _, c := range task.Cmds {
if c.Task != "" {
if err := registerTaskDirs(&Call{Task: c.Task, Vars: c.Vars}); err != nil {
return err
}
}
}
files, err := fingerprint.Globs(task.Dir, task.Sources)
if err != nil {
return err
}
for _, f := range files {
d := filepath.Dir(f)
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
continue
}
if ShouldIgnoreFile(d) {
continue
}
if err := w.Add(d); err != nil {
return err
}
e.watchedDirs.Store(d, true)
relPath, _ := filepath.Rel(e.Dir, d)
w.Events <- fsnotify.Event{Name: f, Op: fsnotify.Create}
e.Logger.VerboseOutf(logger.Green, "task: watching new dir: %v\n", relPath)
}
return nil
files, err := e.collectSources(calls)
if err != nil {
return err
}
for _, c := range calls {
if err := registerTaskDirs(c); err != nil {
for _, f := range files {
d := filepath.Dir(f)
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
continue
}
if ShouldIgnore(d) {
continue
}
if err := w.Add(d); err != nil {
return err
}
e.watchedDirs.Store(d, true)
relPath, _ := filepath.Rel(e.Dir, d)
e.Logger.VerboseOutf(logger.Green, "task: watching new dir: %v\n", relPath)
}
return nil
}
func ShouldIgnoreFile(path string) bool {
ignorePaths := []string{
"/.task",
"/.git",
"/.hg",
"/node_modules",
}
var ignorePaths = []string{
"/.task",
"/.git",
"/.hg",
"/node_modules",
}
func ShouldIgnore(path string) bool {
for _, p := range ignorePaths {
if strings.Contains(path, fmt.Sprintf("%s/", p)) || strings.HasSuffix(path, p) {
return true
@ -224,3 +202,47 @@ func ShouldIgnoreFile(path string) bool {
}
return false
}
func (e *Executor) collectSources(calls []*Call) ([]string, error) {
var sources []string
err := e.traverse(calls, func(task *ast.Task) error {
files, err := fingerprint.Globs(task.Dir, task.Sources)
if err != nil {
return err
}
sources = append(sources, files...)
return nil
})
return slicesext.UniqueJoin(sources), err
}
type traverseFunc func(*ast.Task) error
func (e *Executor) traverse(calls []*Call, yield traverseFunc) error {
for _, c := range calls {
task, err := e.CompiledTask(c)
if err != nil {
return err
}
for _, dep := range task.Deps {
if dep.Task != "" {
if err := e.traverse([]*Call{{Task: dep.Task, Vars: dep.Vars}}, yield); err != nil {
return err
}
}
}
for _, cmd := range task.Cmds {
if cmd.Task != "" {
if err := e.traverse([]*Call{{Task: cmd.Task, Vars: cmd.Vars}}, yield); err != nil {
return err
}
}
}
if err := yield(task); err != nil {
return err
}
}
return nil
}

View File

@ -31,16 +31,17 @@ task: Started watching for tasks: default
task: [default] echo "Task running!"
Task running!
task: task "default" finished running
task: Task "default" is up to date
task: [default] echo "Task running!"
Task running!
task: task "default" finished running
`)
var buff bytes.Buffer
e := task.NewExecutor(
task.ExecutorWithDir(dir),
task.ExecutorWithStdout(&buff),
task.ExecutorWithStderr(&buff),
task.ExecutorWithWatch(true),
task.WithDir(dir),
task.WithStdout(&buff),
task.WithStderr(&buff),
task.WithWatch(true),
)
require.NoError(t, e.Setup())
@ -71,16 +72,16 @@ task: task "default" finished running
}
}()
time.Sleep(10 * time.Millisecond)
time.Sleep(200 * time.Millisecond)
err = os.WriteFile(filePath, []byte("test updated"), 0o644)
require.NoError(t, err)
time.Sleep(150 * time.Millisecond)
time.Sleep(200 * time.Millisecond)
cancel()
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
}
func TestShouldIgnoreFile(t *testing.T) {
func TestShouldIgnore(t *testing.T) {
t.Parallel()
tt := []struct {
@ -95,7 +96,7 @@ func TestShouldIgnoreFile(t *testing.T) {
ct := ct
t.Run(fmt.Sprintf("ignore - %d", k), func(t *testing.T) {
t.Parallel()
require.Equal(t, task.ShouldIgnoreFile(ct.path), ct.expect)
require.Equal(t, task.ShouldIgnore(ct.path), ct.expect)
})
}
}