mirror of
https://github.com/go-task/task.git
synced 2025-08-10 22:42:19 +02:00
fix(watcher): fix some v3.43.x regressions (#2271)
This commit is contained in:
92
watch.go
92
watch.go
@@ -19,6 +19,8 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/fingerprint"
|
"github.com/go-task/task/v3/internal/fingerprint"
|
||||||
"github.com/go-task/task/v3/internal/fsnotifyext"
|
"github.com/go-task/task/v3/internal/fsnotifyext"
|
||||||
"github.com/go-task/task/v3/internal/logger"
|
"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
|
const defaultWaitTime = 100 * time.Millisecond
|
||||||
@@ -85,17 +87,22 @@ func (e *Executor) watchTasks(calls ...*Call) error {
|
|||||||
for _, c := range calls {
|
for _, c := range calls {
|
||||||
c := c
|
c := c
|
||||||
go func() {
|
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)
|
t, err := e.GetTask(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Logger.Errf(logger.Red, "%v\n", err)
|
e.Logger.Errf(logger.Red, "%v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
baseDir := filepathext.SmartJoin(e.Dir, t.Dir)
|
baseDir := filepathext.SmartJoin(e.Dir, t.Dir)
|
||||||
files, err := fingerprint.Globs(baseDir, t.Sources)
|
files, err := e.collectSources(calls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Logger.Errf(logger.Red, "%v\n", err)
|
e.Logger.Errf(logger.Red, "%v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !event.Has(fsnotify.Remove) && !slices.Contains(files, event.Name) {
|
if !event.Has(fsnotify.Remove) && !slices.Contains(files, event.Name) {
|
||||||
relPath, _ := filepath.Rel(baseDir, event.Name)
|
relPath, _ := filepath.Rel(baseDir, event.Name)
|
||||||
e.Logger.VerboseErrf(logger.Magenta, "task: skipped for file not in sources: %s\n", relPath)
|
e.Logger.VerboseErrf(logger.Magenta, "task: skipped for file not in sources: %s\n", relPath)
|
||||||
@@ -158,37 +165,16 @@ func closeOnInterrupt(w *fsnotify.Watcher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) error {
|
func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) error {
|
||||||
var registerTaskDirs func(*Call) error
|
files, err := e.collectSources(calls)
|
||||||
registerTaskDirs = func(c *Call) error {
|
|
||||||
task, err := e.CompiledTask(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
for _, f := range files {
|
||||||
d := filepath.Dir(f)
|
d := filepath.Dir(f)
|
||||||
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
|
if isSet, ok := e.watchedDirs.Load(d); ok && isSet {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ShouldIgnoreFile(d) {
|
if ShouldIgnore(d) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := w.Add(d); err != nil {
|
if err := w.Add(d); err != nil {
|
||||||
@@ -196,27 +182,19 @@ func (e *Executor) registerWatchedDirs(w *fsnotify.Watcher, calls ...*Call) erro
|
|||||||
}
|
}
|
||||||
e.watchedDirs.Store(d, true)
|
e.watchedDirs.Store(d, true)
|
||||||
relPath, _ := filepath.Rel(e.Dir, d)
|
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)
|
e.Logger.VerboseOutf(logger.Green, "task: watching new dir: %v\n", relPath)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range calls {
|
var ignorePaths = []string{
|
||||||
if err := registerTaskDirs(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShouldIgnoreFile(path string) bool {
|
|
||||||
ignorePaths := []string{
|
|
||||||
"/.task",
|
"/.task",
|
||||||
"/.git",
|
"/.git",
|
||||||
"/.hg",
|
"/.hg",
|
||||||
"/node_modules",
|
"/node_modules",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ShouldIgnore(path string) bool {
|
||||||
for _, p := range ignorePaths {
|
for _, p := range ignorePaths {
|
||||||
if strings.Contains(path, fmt.Sprintf("%s/", p)) || strings.HasSuffix(path, p) {
|
if strings.Contains(path, fmt.Sprintf("%s/", p)) || strings.HasSuffix(path, p) {
|
||||||
return true
|
return true
|
||||||
@@ -224,3 +202,47 @@ func ShouldIgnoreFile(path string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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
|
||||||
|
}
|
||||||
|
@@ -31,16 +31,17 @@ task: Started watching for tasks: default
|
|||||||
task: [default] echo "Task running!"
|
task: [default] echo "Task running!"
|
||||||
Task running!
|
Task running!
|
||||||
task: task "default" finished 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
|
task: task "default" finished running
|
||||||
`)
|
`)
|
||||||
|
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
e := task.NewExecutor(
|
e := task.NewExecutor(
|
||||||
task.ExecutorWithDir(dir),
|
task.WithDir(dir),
|
||||||
task.ExecutorWithStdout(&buff),
|
task.WithStdout(&buff),
|
||||||
task.ExecutorWithStderr(&buff),
|
task.WithStderr(&buff),
|
||||||
task.ExecutorWithWatch(true),
|
task.WithWatch(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
require.NoError(t, e.Setup())
|
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)
|
err = os.WriteFile(filePath, []byte("test updated"), 0o644)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
time.Sleep(150 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
cancel()
|
cancel()
|
||||||
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldIgnoreFile(t *testing.T) {
|
func TestShouldIgnore(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
@@ -95,7 +96,7 @@ func TestShouldIgnoreFile(t *testing.T) {
|
|||||||
ct := ct
|
ct := ct
|
||||||
t.Run(fmt.Sprintf("ignore - %d", k), func(t *testing.T) {
|
t.Run(fmt.Sprintf("ignore - %d", k), func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
require.Equal(t, task.ShouldIgnoreFile(ct.path), ct.expect)
|
require.Equal(t, task.ShouldIgnore(ct.path), ct.expect)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user