mirror of
https://github.com/go-task/task.git
synced 2025-06-17 00:17:51 +02:00
Issue 813. Made watch interval configurable through global setting in Taskfile and through CLI arg.
Separated Taskfile param and Arg flag
This commit is contained in:
@ -73,6 +73,7 @@ func main() {
|
|||||||
entrypoint string
|
entrypoint string
|
||||||
output taskfile.Output
|
output taskfile.Output
|
||||||
color bool
|
color bool
|
||||||
|
interval string
|
||||||
)
|
)
|
||||||
|
|
||||||
pflag.BoolVar(&versionFlag, "version", false, "show Task version")
|
pflag.BoolVar(&versionFlag, "version", false, "show Task version")
|
||||||
@ -96,6 +97,7 @@ func main() {
|
|||||||
pflag.StringVar(&output.Group.End, "output-group-end", "", "message template to print after a task's grouped output")
|
pflag.StringVar(&output.Group.End, "output-group-end", "", "message template to print after a task's grouped output")
|
||||||
pflag.BoolVarP(&color, "color", "c", true, "colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable")
|
pflag.BoolVarP(&color, "color", "c", true, "colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable")
|
||||||
pflag.IntVarP(&concurrency, "concurrency", "C", 0, "limit number tasks to run concurrently")
|
pflag.IntVarP(&concurrency, "concurrency", "C", 0, "limit number tasks to run concurrently")
|
||||||
|
pflag.StringVarP(&interval, "interval", "I", "5s", "interval to watch for changes")
|
||||||
pflag.Parse()
|
pflag.Parse()
|
||||||
|
|
||||||
if versionFlag {
|
if versionFlag {
|
||||||
@ -151,6 +153,7 @@ func main() {
|
|||||||
Parallel: parallel,
|
Parallel: parallel,
|
||||||
Color: color,
|
Color: color,
|
||||||
Concurrency: concurrency,
|
Concurrency: concurrency,
|
||||||
|
Interval: interval,
|
||||||
|
|
||||||
Stdin: os.Stdin,
|
Stdin: os.Stdin,
|
||||||
Stdout: os.Stdout,
|
Stdout: os.Stdout,
|
||||||
@ -206,6 +209,10 @@ func main() {
|
|||||||
e.InterceptInterruptSignals()
|
e.InterceptInterruptSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e.Interval == "" {
|
||||||
|
e.Interval = strings.TrimSpace(interval)
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if status {
|
if status {
|
||||||
|
1
task.go
1
task.go
@ -41,6 +41,7 @@ type Executor struct {
|
|||||||
Parallel bool
|
Parallel bool
|
||||||
Color bool
|
Color bool
|
||||||
Concurrency int
|
Concurrency int
|
||||||
|
Interval string
|
||||||
|
|
||||||
Stdin io.Reader
|
Stdin io.Reader
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
|
61
task_test.go
61
task_test.go
@ -10,6 +10,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@ -1400,3 +1401,63 @@ func TestEvaluateSymlinksInPaths(t *testing.T) {
|
|||||||
err = os.RemoveAll(dir + "/.task")
|
err = os.RemoveAll(dir + "/.task")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileWatcherInterval(t *testing.T) {
|
||||||
|
const dir = "testdata/watcher_interval"
|
||||||
|
expectedOutput := strings.TrimSpace(`
|
||||||
|
task: Started watching for tasks: default
|
||||||
|
task: [default] echo "Hello, World!"
|
||||||
|
Hello, World!
|
||||||
|
task: [default] echo "Hello, World!"
|
||||||
|
Hello, World!
|
||||||
|
`)
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := &task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
Watch: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
buff.Reset()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
err := os.MkdirAll(dir+"/src", 0755)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(dir+"/src/a", []byte("test"), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(ctx context.Context) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
err := e.Run(ctx, taskfile.Call{Task: "default"})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(ctx)
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
err = os.WriteFile(dir+"/src/a", []byte("test updated"), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(70 * time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = os.RemoveAll(dir + "/.task")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ type Taskfile struct {
|
|||||||
Silent bool
|
Silent bool
|
||||||
Dotenv []string
|
Dotenv []string
|
||||||
Run string
|
Run string
|
||||||
|
Interval string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||||
@ -34,10 +35,13 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
Silent bool
|
Silent bool
|
||||||
Dotenv []string
|
Dotenv []string
|
||||||
Run string
|
Run string
|
||||||
|
Interval string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := unmarshal(&taskfile); err != nil {
|
if err := unmarshal(&taskfile); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tf.Version = taskfile.Version
|
tf.Version = taskfile.Version
|
||||||
tf.Expansions = taskfile.Expansions
|
tf.Expansions = taskfile.Expansions
|
||||||
tf.Output = taskfile.Output
|
tf.Output = taskfile.Output
|
||||||
@ -49,6 +53,8 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
tf.Silent = taskfile.Silent
|
tf.Silent = taskfile.Silent
|
||||||
tf.Dotenv = taskfile.Dotenv
|
tf.Dotenv = taskfile.Dotenv
|
||||||
tf.Run = taskfile.Run
|
tf.Run = taskfile.Run
|
||||||
|
tf.Interval = taskfile.Interval
|
||||||
|
|
||||||
if tf.Expansions <= 0 {
|
if tf.Expansions <= 0 {
|
||||||
tf.Expansions = 2
|
tf.Expansions = 2
|
||||||
}
|
}
|
||||||
|
1
testdata/watcher_interval/.gitignore
vendored
Normal file
1
testdata/watcher_interval/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
src/*
|
16
testdata/watcher_interval/Taskfile.yaml
vendored
Normal file
16
testdata/watcher_interval/Taskfile.yaml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# https://taskfile.dev
|
||||||
|
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
GREETING: Hello, World!
|
||||||
|
|
||||||
|
interval: "50ms"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
sources:
|
||||||
|
- "src/*"
|
||||||
|
cmds:
|
||||||
|
- echo "{{.GREETING}}"
|
||||||
|
silent: false
|
31
watch.go
31
watch.go
@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/radovskyb/watcher"
|
"github.com/radovskyb/watcher"
|
||||||
)
|
)
|
||||||
|
|
||||||
const watchInterval = 5 * time.Second
|
const defaultWatchInterval = 5 * time.Second
|
||||||
|
|
||||||
// watchTasks start watching the given tasks
|
// watchTasks start watching the given tasks
|
||||||
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
||||||
@ -24,6 +24,7 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
for i, c := range calls {
|
for i, c := range calls {
|
||||||
tasks[i] = c.Task
|
tasks[i] = c.Task
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Logger.Errf(logger.Green, "task: Started watching for tasks: %s", strings.Join(tasks, ", "))
|
e.Logger.Errf(logger.Green, "task: Started watching for tasks: %s", strings.Join(tasks, ", "))
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@ -36,6 +37,26 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var watchIntervalString string
|
||||||
|
|
||||||
|
if e.Taskfile.Interval != "" {
|
||||||
|
watchIntervalString = e.Taskfile.Interval
|
||||||
|
} else if e.Interval != "" {
|
||||||
|
watchIntervalString = e.Interval
|
||||||
|
}
|
||||||
|
|
||||||
|
watchInterval := defaultWatchInterval
|
||||||
|
|
||||||
|
if watchIntervalString != "" {
|
||||||
|
var err error
|
||||||
|
watchInterval, err = parsedWatchInterval(watchIntervalString)
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Errf(logger.Red, "%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Logger.VerboseOutf(logger.Green, "task: Watching for changes every %v", watchInterval)
|
||||||
|
|
||||||
w := watcher.New()
|
w := watcher.New()
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
w.SetMaxEvents(1)
|
w.SetMaxEvents(1)
|
||||||
@ -163,3 +184,11 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
|
|||||||
func shouldIgnoreFile(path string) bool {
|
func shouldIgnoreFile(path string) bool {
|
||||||
return strings.Contains(path, "/.git") || strings.Contains(path, "/.task") || strings.Contains(path, "/node_modules")
|
return strings.Contains(path, "/.git") || strings.Contains(path, "/.task") || strings.Contains(path, "/node_modules")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parsedWatchInterval(watchInterval string) (time.Duration, error) {
|
||||||
|
v, err := time.ParseDuration(watchInterval)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf(`task: Could not parse watch interval "%s": %v`, watchInterval, err)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user