mirror of
				https://github.com/go-task/task.git
				synced 2025-10-30 23:58:01 +02:00 
			
		
		
		
	fix(watcher): fix some v3.43.x regressions (#2271)
This commit is contained in:
		
							
								
								
									
										128
									
								
								watch.go
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								watch.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user