1
0
mirror of https://github.com/go-task/task.git synced 2024-12-14 10:52:43 +02:00
task/watch.go
Andrey Nering 87a200e42c Extract some functionality to its own packages
Like variable and template handling, and logging
2018-02-17 16:12:41 -02:00

152 lines
3.0 KiB
Go

package task
import (
"context"
"strings"
"time"
"github.com/go-task/task/internal/taskfile"
"github.com/mattn/go-zglob"
"github.com/radovskyb/watcher"
)
var watchIgnoredDirs = []string{
".git",
"node_modules",
}
// watchTasks start watching the given tasks
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
tasks := make([]string, len(calls))
for i, c := range calls {
tasks[i] = c.Task
}
e.Logger.Errf("task: Started watching for tasks: %s", strings.Join(tasks, ", "))
ctx, cancel := context.WithCancel(context.Background())
for _, c := range calls {
c := c
go func() {
if err := e.RunTask(ctx, c); err != nil && !isContextError(err) {
e.Logger.Errf("%v", err)
}
}()
}
w := watcher.New()
defer w.Close()
w.SetMaxEvents(1)
if err := w.Ignore(watchIgnoredDirs...); err != nil {
return err
}
go func() {
for {
select {
case event := <-w.Event:
e.Logger.VerboseErrf("task: received watch event: %v", event)
cancel()
ctx, cancel = context.WithCancel(context.Background())
for _, c := range calls {
c := c
go func() {
if err := e.RunTask(ctx, c); err != nil && !isContextError(err) {
e.Logger.Errf("%v", err)
}
}()
}
case err := <-w.Error:
switch err {
case watcher.ErrWatchedFileDeleted:
go func() {
w.TriggerEvent(watcher.Remove, nil)
}()
default:
e.Logger.Errf("%v", err)
}
case <-w.Closed:
return
}
}
}()
go func() {
// re-register each second because we can have new files
for {
if err := e.registerWatchedFiles(w, calls...); err != nil {
e.Logger.Errf("%v", err)
}
time.Sleep(time.Second)
}
}()
return w.Start(time.Second)
}
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Call) error {
oldWatchedFiles := make(map[string]struct{})
for f := range w.WatchedFiles() {
oldWatchedFiles[f] = struct{}{}
}
for f := range oldWatchedFiles {
if err := w.Remove(f); err != nil {
return err
}
}
var registerTaskFiles func(taskfile.Call) error
registerTaskFiles = func(c taskfile.Call) error {
task, err := e.CompiledTask(c)
if err != nil {
return err
}
for _, d := range task.Deps {
if err := registerTaskFiles(taskfile.Call{Task: d.Task, Vars: d.Vars}); err != nil {
return err
}
}
for _, c := range task.Cmds {
if c.Task != "" {
if err := registerTaskFiles(taskfile.Call{Task: c.Task, Vars: c.Vars}); err != nil {
return err
}
}
}
for _, s := range task.Sources {
files, err := zglob.Glob(s)
if err != nil {
return err
}
for _, f := range files {
if _, ok := oldWatchedFiles[f]; ok {
continue
}
if err := w.Add(f); err != nil {
return err
}
}
}
return nil
}
for _, c := range calls {
if err := registerTaskFiles(c); err != nil {
return err
}
}
return nil
}
func isContextError(err error) bool {
switch err {
case context.Canceled, context.DeadlineExceeded:
return true
default:
return false
}
}