2017-04-01 21:04:52 +02:00
|
|
|
package task
|
|
|
|
|
|
|
|
import (
|
2017-04-13 01:53:41 +02:00
|
|
|
"context"
|
2017-04-01 21:04:52 +02:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mattn/go-zglob"
|
2017-08-05 16:50:39 +02:00
|
|
|
"github.com/radovskyb/watcher"
|
2017-04-01 21:04:52 +02:00
|
|
|
)
|
|
|
|
|
2017-08-05 18:35:10 +02:00
|
|
|
var watchIgnoredDirs = []string{
|
|
|
|
".git",
|
|
|
|
"node_modules",
|
|
|
|
}
|
|
|
|
|
2017-06-04 21:02:04 +02:00
|
|
|
// watchTasks start watching the given tasks
|
|
|
|
func (e *Executor) watchTasks(args ...string) error {
|
2017-07-01 20:05:51 +02:00
|
|
|
e.printfln("task: Started watching for tasks: %s", strings.Join(args, ", "))
|
2017-04-01 21:04:52 +02:00
|
|
|
|
2017-08-04 17:48:15 +02:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
for _, a := range args {
|
|
|
|
a := a
|
|
|
|
go func() {
|
2017-08-05 19:04:31 +02:00
|
|
|
if err := e.RunTask(ctx, Call{Task: a}); err != nil && !isContextError(err) {
|
2017-08-04 17:48:15 +02:00
|
|
|
e.println(err)
|
|
|
|
}
|
|
|
|
}()
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
|
|
|
|
2017-08-05 16:50:39 +02:00
|
|
|
w := watcher.New()
|
|
|
|
defer w.Close()
|
|
|
|
w.SetMaxEvents(1)
|
2017-08-05 18:35:10 +02:00
|
|
|
if err := w.Ignore(watchIgnoredDirs...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-04-01 21:04:52 +02:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
2017-08-05 16:50:39 +02:00
|
|
|
select {
|
|
|
|
case event := <-w.Event:
|
|
|
|
e.verbosePrintfln("task: received watch event: %v", event)
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
ctx, cancel = context.WithCancel(context.Background())
|
|
|
|
for _, a := range args {
|
|
|
|
a := a
|
|
|
|
go func() {
|
2017-08-05 19:04:31 +02:00
|
|
|
if err := e.RunTask(ctx, Call{Task: a}); err != nil && !isContextError(err) {
|
2017-08-05 16:50:39 +02:00
|
|
|
e.println(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
case err := <-w.Error:
|
|
|
|
switch err {
|
|
|
|
case watcher.ErrWatchedFileDeleted:
|
|
|
|
go func() {
|
|
|
|
w.TriggerEvent(watcher.Remove, nil)
|
|
|
|
}()
|
|
|
|
default:
|
|
|
|
e.println(err)
|
|
|
|
}
|
|
|
|
case <-w.Closed:
|
|
|
|
return
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2017-08-05 16:50:39 +02:00
|
|
|
go func() {
|
|
|
|
// re-register each second because we can have new files
|
|
|
|
for {
|
|
|
|
if err := e.registerWatchedFiles(w, args); err != nil {
|
|
|
|
e.println(err)
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
2017-08-05 16:50:39 +02:00
|
|
|
time.Sleep(time.Second)
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
2017-08-05 16:50:39 +02:00
|
|
|
}()
|
|
|
|
|
|
|
|
return w.Start(time.Second)
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
|
|
|
|
2017-08-05 16:50:39 +02:00
|
|
|
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, args []string) error {
|
|
|
|
oldWatchedFiles := make(map[string]struct{})
|
|
|
|
for f := range w.WatchedFiles() {
|
|
|
|
oldWatchedFiles[f] = struct{}{}
|
|
|
|
}
|
2017-04-01 21:04:52 +02:00
|
|
|
|
2017-08-05 16:50:39 +02:00
|
|
|
for f := range oldWatchedFiles {
|
|
|
|
if err := w.Remove(f); err != nil {
|
2017-04-01 21:04:52 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-05 16:50:39 +02:00
|
|
|
var registerTaskFiles func(string) error
|
|
|
|
registerTaskFiles = func(t string) error {
|
|
|
|
task, ok := e.Tasks[t]
|
2017-04-01 21:04:52 +02:00
|
|
|
if !ok {
|
2017-08-05 16:50:39 +02:00
|
|
|
return &taskNotFoundError{t}
|
2017-07-02 20:30:50 +02:00
|
|
|
}
|
2017-08-05 16:50:39 +02:00
|
|
|
|
|
|
|
for _, d := range task.Deps {
|
|
|
|
if err := registerTaskFiles(d.Task); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
2017-08-05 16:50:39 +02:00
|
|
|
|
2017-04-01 21:04:52 +02:00
|
|
|
for _, s := range task.Sources {
|
|
|
|
files, err := zglob.Glob(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, f := range files {
|
2017-08-05 16:50:39 +02:00
|
|
|
if _, ok := oldWatchedFiles[f]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2017-04-01 21:04:52 +02:00
|
|
|
if err := w.Add(f); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-05 16:50:39 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range args {
|
|
|
|
if err := registerTaskFiles(a); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-04-01 21:04:52 +02:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2017-08-05 19:04:31 +02:00
|
|
|
|
|
|
|
func isContextError(err error) bool {
|
|
|
|
switch err {
|
|
|
|
case context.Canceled, context.DeadlineExceeded:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|