From 152fc0ad383987ab4b00030e49b77f204be65481 Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Sat, 17 Feb 2018 14:22:18 -0200 Subject: [PATCH] Move all structs related to Taskfile to its own package --- Taskvars.yml | 1 + help.go | 6 +- internal/args/args.go | 12 +-- internal/args/args_test.go | 24 ++--- internal/taskfile/call.go | 7 ++ command.go => internal/taskfile/cmd.go | 8 +- internal/taskfile/task.go | 20 ++++ internal/taskfile/taskfile.go | 26 +++++ .../taskfile/taskfile_test.go | 28 ++--- internal/taskfile/var.go | 58 ++++++++++ status.go | 21 ++-- task.go | 46 +++----- task_test.go | 21 ++-- taskfile.go | 33 +----- variables.go | 102 +++++------------- watch.go | 13 +-- 16 files changed, 223 insertions(+), 203 deletions(-) create mode 100644 internal/taskfile/call.go rename command.go => internal/taskfile/cmd.go (94%) create mode 100644 internal/taskfile/task.go create mode 100644 internal/taskfile/taskfile.go rename command_test.go => internal/taskfile/taskfile_test.go (54%) create mode 100644 internal/taskfile/var.go diff --git a/Taskvars.yml b/Taskvars.yml index 14911472..cc67ecde 100644 --- a/Taskvars.yml +++ b/Taskvars.yml @@ -7,3 +7,4 @@ GO_PACKAGES: ./internal/args ./internal/execext ./internal/status + ./internal/taskfile diff --git a/help.go b/help.go index 381897ee..07eb906f 100644 --- a/help.go +++ b/help.go @@ -4,6 +4,8 @@ import ( "fmt" "sort" "text/tabwriter" + + "github.com/go-task/task/internal/taskfile" ) // PrintTasksHelp prints help os tasks that have a description @@ -23,8 +25,8 @@ func (e *Executor) PrintTasksHelp() { w.Flush() } -func (e *Executor) tasksWithDesc() (tasks []*Task) { - tasks = make([]*Task, 0, len(e.Taskfile.Tasks)) +func (e *Executor) tasksWithDesc() (tasks []*taskfile.Task) { + tasks = make([]*taskfile.Task, 0, len(e.Taskfile.Tasks)) for _, task := range e.Taskfile.Tasks { if task.Desc != "" { tasks = append(tasks, task) diff --git a/internal/args/args.go b/internal/args/args.go index 3aba9159..2e1a8cd7 100644 --- a/internal/args/args.go +++ b/internal/args/args.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/go-task/task" + "github.com/go-task/task/internal/taskfile" ) var ( @@ -13,12 +13,12 @@ var ( ) // Parse parses command line argument: tasks and vars of each task -func Parse(args ...string) ([]task.Call, error) { - var calls []task.Call +func Parse(args ...string) ([]taskfile.Call, error) { + var calls []taskfile.Call for _, arg := range args { if !strings.Contains(arg, "=") { - calls = append(calls, task.Call{Task: arg}) + calls = append(calls, taskfile.Call{Task: arg}) continue } if len(calls) < 1 { @@ -26,11 +26,11 @@ func Parse(args ...string) ([]task.Call, error) { } if calls[len(calls)-1].Vars == nil { - calls[len(calls)-1].Vars = make(task.Vars) + calls[len(calls)-1].Vars = make(taskfile.Vars) } pair := strings.SplitN(arg, "=", 2) - calls[len(calls)-1].Vars[pair[0]] = task.Var{Static: pair[1]} + calls[len(calls)-1].Vars[pair[0]] = taskfile.Var{Static: pair[1]} } return calls, nil } diff --git a/internal/args/args_test.go b/internal/args/args_test.go index 99b0f04a..f6d42d97 100644 --- a/internal/args/args_test.go +++ b/internal/args/args_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/go-task/task" "github.com/go-task/task/internal/args" + "github.com/go-task/task/internal/taskfile" "github.com/stretchr/testify/assert" ) @@ -13,12 +13,12 @@ import ( func TestArgs(t *testing.T) { tests := []struct { Args []string - Expected []task.Call + Expected []taskfile.Call Err error }{ { Args: []string{"task-a", "task-b", "task-c"}, - Expected: []task.Call{ + Expected: []taskfile.Call{ {Task: "task-a"}, {Task: "task-b"}, {Task: "task-c"}, @@ -26,30 +26,30 @@ func TestArgs(t *testing.T) { }, { Args: []string{"task-a", "FOO=bar", "task-b", "task-c", "BAR=baz", "BAZ=foo"}, - Expected: []task.Call{ + Expected: []taskfile.Call{ { Task: "task-a", - Vars: task.Vars{ - "FOO": task.Var{Static: "bar"}, + Vars: taskfile.Vars{ + "FOO": taskfile.Var{Static: "bar"}, }, }, {Task: "task-b"}, { Task: "task-c", - Vars: task.Vars{ - "BAR": task.Var{Static: "baz"}, - "BAZ": task.Var{Static: "foo"}, + Vars: taskfile.Vars{ + "BAR": taskfile.Var{Static: "baz"}, + "BAZ": taskfile.Var{Static: "foo"}, }, }, }, }, { Args: []string{"task-a", "CONTENT=with some spaces"}, - Expected: []task.Call{ + Expected: []taskfile.Call{ { Task: "task-a", - Vars: task.Vars{ - "CONTENT": task.Var{Static: "with some spaces"}, + Vars: taskfile.Vars{ + "CONTENT": taskfile.Var{Static: "with some spaces"}, }, }, }, diff --git a/internal/taskfile/call.go b/internal/taskfile/call.go new file mode 100644 index 00000000..eec41031 --- /dev/null +++ b/internal/taskfile/call.go @@ -0,0 +1,7 @@ +package taskfile + +// Call is the parameters to a task call +type Call struct { + Task string + Vars Vars +} diff --git a/command.go b/internal/taskfile/cmd.go similarity index 94% rename from command.go rename to internal/taskfile/cmd.go index c14c94ba..f2bae2fc 100644 --- a/command.go +++ b/internal/taskfile/cmd.go @@ -1,4 +1,4 @@ -package task +package taskfile import ( "errors" @@ -76,9 +76,3 @@ func (d *Dep) UnmarshalYAML(unmarshal func(interface{}) error) error { } return ErrCantUnmarshalDep } - -// Call is the parameters to a task call -type Call struct { - Task string - Vars Vars -} diff --git a/internal/taskfile/task.go b/internal/taskfile/task.go new file mode 100644 index 00000000..6a2b4708 --- /dev/null +++ b/internal/taskfile/task.go @@ -0,0 +1,20 @@ +package taskfile + +// Tasks representas a group of tasks +type Tasks map[string]*Task + +// Task represents a task +type Task struct { + Task string + Cmds []*Cmd + Deps []*Dep + Desc string + Sources []string + Generates []string + Status []string + Dir string + Vars Vars + Env Vars + Silent bool + Method string +} diff --git a/internal/taskfile/taskfile.go b/internal/taskfile/taskfile.go new file mode 100644 index 00000000..dd5317bc --- /dev/null +++ b/internal/taskfile/taskfile.go @@ -0,0 +1,26 @@ +package taskfile + +// Taskfile represents a Taskfile.yml +type Taskfile struct { + // TODO: version is still not used + Version int + Tasks Tasks +} + +// UnmarshalYAML implements yaml.Unmarshaler interface +func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { + if err := unmarshal(&tf.Tasks); err == nil { + return nil + } + + var taskfile struct { + Version int + Tasks Tasks + } + if err := unmarshal(&taskfile); err != nil { + return err + } + tf.Version = taskfile.Version + tf.Tasks = taskfile.Tasks + return nil +} diff --git a/command_test.go b/internal/taskfile/taskfile_test.go similarity index 54% rename from command_test.go rename to internal/taskfile/taskfile_test.go index ad0b610a..9c5e0150 100644 --- a/command_test.go +++ b/internal/taskfile/taskfile_test.go @@ -1,9 +1,9 @@ -package task_test +package taskfile_test import ( "testing" - "github.com/go-task/task" + "github.com/go-task/task/internal/taskfile" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v2" @@ -27,28 +27,28 @@ vars: }{ { yamlCmd, - &task.Cmd{}, - &task.Cmd{Cmd: `echo "a string command"`}, + &taskfile.Cmd{}, + &taskfile.Cmd{Cmd: `echo "a string command"`}, }, { yamlTaskCall, - &task.Cmd{}, - &task.Cmd{Task: "another-task", Vars: task.Vars{ - "PARAM1": task.Var{Static: "VALUE1"}, - "PARAM2": task.Var{Static: "VALUE2"}, + &taskfile.Cmd{}, + &taskfile.Cmd{Task: "another-task", Vars: taskfile.Vars{ + "PARAM1": taskfile.Var{Static: "VALUE1"}, + "PARAM2": taskfile.Var{Static: "VALUE2"}, }}, }, { yamlDep, - &task.Dep{}, - &task.Dep{Task: "task-name"}, + &taskfile.Dep{}, + &taskfile.Dep{Task: "task-name"}, }, { yamlTaskCall, - &task.Dep{}, - &task.Dep{Task: "another-task", Vars: task.Vars{ - "PARAM1": task.Var{Static: "VALUE1"}, - "PARAM2": task.Var{Static: "VALUE2"}, + &taskfile.Dep{}, + &taskfile.Dep{Task: "another-task", Vars: taskfile.Vars{ + "PARAM1": taskfile.Var{Static: "VALUE1"}, + "PARAM2": taskfile.Var{Static: "VALUE2"}, }}, }, } diff --git a/internal/taskfile/var.go b/internal/taskfile/var.go new file mode 100644 index 00000000..f52e0f8b --- /dev/null +++ b/internal/taskfile/var.go @@ -0,0 +1,58 @@ +package taskfile + +import ( + "errors" + "strings" +) + +var ( + // ErrCantUnmarshalVar is returned for invalid var YAML. + ErrCantUnmarshalVar = errors.New("task: can't unmarshal var value") +) + +// Vars is a string[string] variables map. +type Vars map[string]Var + +// ToStringMap converts Vars to a string map containing only the static +// variables +func (vs Vars) ToStringMap() (m map[string]string) { + m = make(map[string]string, len(vs)) + for k, v := range vs { + if v.Sh != "" { + // Dynamic variable is not yet resolved; trigger + // to be used in templates. + continue + } + m[k] = v.Static + } + return +} + +// Var represents either a static or dynamic variable. +type Var struct { + Static string + Sh string +} + +// UnmarshalYAML implements yaml.Unmarshaler interface. +func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error { + var str string + if err := unmarshal(&str); err == nil { + if strings.HasPrefix(str, "$") { + v.Sh = strings.TrimPrefix(str, "$") + } else { + v.Static = str + } + return nil + } + + var sh struct { + Sh string + } + if err := unmarshal(&sh); err == nil { + v.Sh = sh.Sh + return nil + } + + return ErrCantUnmarshalVar +} diff --git a/status.go b/status.go index d231fb3f..d2dabd37 100644 --- a/status.go +++ b/status.go @@ -6,16 +6,17 @@ import ( "github.com/go-task/task/internal/execext" "github.com/go-task/task/internal/status" + "github.com/go-task/task/internal/taskfile" ) // Status returns an error if any the of given tasks is not up-to-date -func (e *Executor) Status(calls ...Call) error { +func (e *Executor) Status(calls ...taskfile.Call) error { for _, call := range calls { t, ok := e.Taskfile.Tasks[call.Task] if !ok { return &taskNotFoundError{taskName: call.Task} } - isUpToDate, err := t.isUpToDate(e.Context) + isUpToDate, err := isTaskUpToDate(e.Context, t) if err != nil { return err } @@ -26,12 +27,12 @@ func (e *Executor) Status(calls ...Call) error { return nil } -func (t *Task) isUpToDate(ctx context.Context) (bool, error) { +func isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool, error) { if len(t.Status) > 0 { - return t.isUpToDateStatus(ctx) + return isTaskUpToDateStatus(ctx, t) } - checker, err := t.getStatusChecker() + checker, err := getStatusChecker(t) if err != nil { return false, err } @@ -39,15 +40,15 @@ func (t *Task) isUpToDate(ctx context.Context) (bool, error) { return checker.IsUpToDate() } -func (t *Task) statusOnError() error { - checker, err := t.getStatusChecker() +func statusOnError(t *taskfile.Task) error { + checker, err := getStatusChecker(t) if err != nil { return err } return checker.OnError() } -func (t *Task) getStatusChecker() (status.Checker, error) { +func getStatusChecker(t *taskfile.Task) (status.Checker, error) { switch t.Method { case "", "timestamp": return &status.Timestamp{ @@ -68,13 +69,13 @@ func (t *Task) getStatusChecker() (status.Checker, error) { } } -func (t *Task) isUpToDateStatus(ctx context.Context) (bool, error) { +func isTaskUpToDateStatus(ctx context.Context, t *taskfile.Task) (bool, error) { for _, s := range t.Status { err := execext.RunCommand(&execext.RunCommandOptions{ Context: ctx, Command: s, Dir: t.Dir, - Env: t.getEnviron(), + Env: getEnviron(t), }) if err != nil { return false, nil diff --git a/task.go b/task.go index c4abe999..3ed284d5 100644 --- a/task.go +++ b/task.go @@ -9,6 +9,7 @@ import ( "sync/atomic" "github.com/go-task/task/internal/execext" + "github.com/go-task/task/internal/taskfile" "golang.org/x/sync/errgroup" ) @@ -23,7 +24,7 @@ const ( // Executor executes a Taskfile type Executor struct { - Taskfile *Taskfile + Taskfile *taskfile.Taskfile Dir string Force bool Watch bool @@ -36,7 +37,7 @@ type Executor struct { Stdout io.Writer Stderr io.Writer - taskvars Vars + taskvars taskfile.Vars taskCallCount map[string]*int32 @@ -44,27 +45,8 @@ type Executor struct { muDynamicCache sync.Mutex } -// Tasks representas a group of tasks -type Tasks map[string]*Task - -// Task represents a task -type Task struct { - Task string - Cmds []*Cmd - Deps []*Dep - Desc string - Sources []string - Generates []string - Status []string - Dir string - Vars Vars - Env Vars - Silent bool - Method string -} - // Run runs Task -func (e *Executor) Run(calls ...Call) error { +func (e *Executor) Run(calls ...taskfile.Call) error { if e.Context == nil { e.Context = context.Background() } @@ -109,7 +91,7 @@ func (e *Executor) Run(calls ...Call) error { } // RunTask runs a task by its name -func (e *Executor) RunTask(ctx context.Context, call Call) error { +func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error { t, err := e.CompiledTask(call) if err != nil { return err @@ -123,7 +105,7 @@ func (e *Executor) RunTask(ctx context.Context, call Call) error { } if !e.Force { - upToDate, err := t.isUpToDate(ctx) + upToDate, err := isTaskUpToDate(ctx, t) if err != nil { return err } @@ -137,7 +119,7 @@ func (e *Executor) RunTask(ctx context.Context, call Call) error { for i := range t.Cmds { if err := e.runCommand(ctx, t, call, i); err != nil { - if err2 := t.statusOnError(); err2 != nil { + if err2 := statusOnError(t); err2 != nil { e.verboseErrf("task: error cleaning status on error: %v", err2) } return &taskRunError{t.Task, err} @@ -146,25 +128,25 @@ func (e *Executor) RunTask(ctx context.Context, call Call) error { return nil } -func (e *Executor) runDeps(ctx context.Context, t *Task) error { +func (e *Executor) runDeps(ctx context.Context, t *taskfile.Task) error { g, ctx := errgroup.WithContext(ctx) for _, d := range t.Deps { d := d g.Go(func() error { - return e.RunTask(ctx, Call{Task: d.Task, Vars: d.Vars}) + return e.RunTask(ctx, taskfile.Call{Task: d.Task, Vars: d.Vars}) }) } return g.Wait() } -func (e *Executor) runCommand(ctx context.Context, t *Task, call Call, i int) error { +func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfile.Call, i int) error { cmd := t.Cmds[i] if cmd.Cmd == "" { - return e.RunTask(ctx, Call{Task: cmd.Task, Vars: cmd.Vars}) + return e.RunTask(ctx, taskfile.Call{Task: cmd.Task, Vars: cmd.Vars}) } if e.Verbose || (!cmd.Silent && !t.Silent && !e.Silent) { @@ -175,20 +157,20 @@ func (e *Executor) runCommand(ctx context.Context, t *Task, call Call, i int) er Context: ctx, Command: cmd.Cmd, Dir: t.Dir, - Env: t.getEnviron(), + Env: getEnviron(t), Stdin: e.Stdin, Stdout: e.Stdout, Stderr: e.Stderr, }) } -func (t *Task) getEnviron() []string { +func getEnviron(t *taskfile.Task) []string { if t.Env == nil { return nil } envs := os.Environ() - for k, v := range t.Env.toStringMap() { + for k, v := range t.Env.ToStringMap() { envs = append(envs, fmt.Sprintf("%s=%s", k, v)) } return envs diff --git a/task_test.go b/task_test.go index b93de4db..f8216530 100644 --- a/task_test.go +++ b/task_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/go-task/task" + "github.com/go-task/task/internal/taskfile" "github.com/stretchr/testify/assert" ) @@ -38,7 +39,7 @@ func (fct fileContentTest) Run(t *testing.T) { Stderr: ioutil.Discard, } assert.NoError(t, e.ReadTaskfile(), "e.ReadTaskfile()") - assert.NoError(t, e.Run(task.Call{Task: fct.Target}), "e.Run(target)") + assert.NoError(t, e.Run(taskfile.Call{Task: fct.Target}), "e.Run(target)") for name, expectContent := range fct.Files { t.Run(fct.name(name), func(t *testing.T) { @@ -136,7 +137,7 @@ func TestVarsInvalidTmpl(t *testing.T) { Stderr: ioutil.Discard, } assert.NoError(t, e.ReadTaskfile(), "e.ReadTaskfile()") - assert.EqualError(t, e.Run(task.Call{Task: target}), expectError, "e.Run(target)") + assert.EqualError(t, e.Run(taskfile.Call{Task: target}), expectError, "e.Run(target)") } func TestParams(t *testing.T) { @@ -188,7 +189,7 @@ func TestDeps(t *testing.T) { Stderr: ioutil.Discard, } assert.NoError(t, e.ReadTaskfile()) - assert.NoError(t, e.Run(task.Call{Task: "default"})) + assert.NoError(t, e.Run(taskfile.Call{Task: "default"})) for _, f := range files { f = filepath.Join(dir, f) @@ -214,7 +215,7 @@ func TestStatus(t *testing.T) { Stderr: ioutil.Discard, } assert.NoError(t, e.ReadTaskfile()) - assert.NoError(t, e.Run(task.Call{Task: "gen-foo"})) + assert.NoError(t, e.Run(taskfile.Call{Task: "gen-foo"})) if _, err := os.Stat(file); err != nil { t.Errorf("File should exists: %v", err) @@ -222,7 +223,7 @@ func TestStatus(t *testing.T) { buff := bytes.NewBuffer(nil) e.Stdout, e.Stderr = buff, buff - assert.NoError(t, e.Run(task.Call{Task: "gen-foo"})) + assert.NoError(t, e.Run(taskfile.Call{Task: "gen-foo"})) if buff.String() != `task: Task "gen-foo" is up to date`+"\n" { t.Errorf("Wrong output message: %s", buff.String()) @@ -261,7 +262,7 @@ func TestGenerates(t *testing.T) { fmt.Sprintf("task: Task \"%s\" is up to date\n", theTask) // Run task for the first time. - assert.NoError(t, e.Run(task.Call{Task: theTask})) + assert.NoError(t, e.Run(taskfile.Call{Task: theTask})) if _, err := os.Stat(srcFile); err != nil { t.Errorf("File should exists: %v", err) @@ -276,7 +277,7 @@ func TestGenerates(t *testing.T) { buff.Reset() // Re-run task to ensure it's now found to be up-to-date. - assert.NoError(t, e.Run(task.Call{Task: theTask})) + assert.NoError(t, e.Run(taskfile.Call{Task: theTask})) if buff.String() != upToDate { t.Errorf("Wrong output message: %s", buff.String()) } @@ -307,14 +308,14 @@ func TestStatusChecksum(t *testing.T) { } assert.NoError(t, e.ReadTaskfile()) - assert.NoError(t, e.Run(task.Call{Task: "build"})) + assert.NoError(t, e.Run(taskfile.Call{Task: "build"})) for _, f := range files { _, err := os.Stat(filepath.Join(dir, f)) assert.NoError(t, err) } buff.Reset() - assert.NoError(t, e.Run(task.Call{Task: "build"})) + assert.NoError(t, e.Run(taskfile.Call{Task: "build"})) assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String()) } @@ -345,7 +346,7 @@ func TestCyclicDep(t *testing.T) { Stderr: ioutil.Discard, } assert.NoError(t, e.ReadTaskfile()) - assert.IsType(t, &task.MaximumTaskCallExceededError{}, e.Run(task.Call{Task: "task-1"})) + assert.IsType(t, &task.MaximumTaskCallExceededError{}, e.Run(taskfile.Call{Task: "task-1"})) } func TestTaskVersion(t *testing.T) { diff --git a/taskfile.go b/taskfile.go index 6b8fc3d1..d6ebf9d8 100644 --- a/taskfile.go +++ b/taskfile.go @@ -6,35 +6,12 @@ import ( "path/filepath" "runtime" + "github.com/go-task/task/internal/taskfile" + "github.com/imdario/mergo" "gopkg.in/yaml.v2" ) -// Taskfile represents a Taskfile.yml -type Taskfile struct { - // TODO: version is still not used - Version int - Tasks Tasks -} - -// UnmarshalYAML implements yaml.Unmarshaler interface -func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error { - if err := unmarshal(&tf.Tasks); err == nil { - return nil - } - - var taskfile struct { - Version int - Tasks Tasks - } - if err := unmarshal(&taskfile); err != nil { - return err - } - tf.Version = taskfile.Version - tf.Tasks = taskfile.Tasks - return nil -} - // ReadTaskfile parses Taskfile from the disk func (e *Executor) ReadTaskfile() error { path := filepath.Join(e.Dir, TaskFilePath) @@ -64,9 +41,9 @@ func (e *Executor) ReadTaskfile() error { return e.readTaskvars() } -func (e *Executor) readTaskfileData(path string) (*Taskfile, error) { +func (e *Executor) readTaskfileData(path string) (*taskfile.Taskfile, error) { if b, err := ioutil.ReadFile(path + ".yml"); err == nil { - var taskfile Taskfile + var taskfile taskfile.Taskfile return &taskfile, yaml.UnmarshalStrict(b, &taskfile) } return nil, taskFileNotFound{path} @@ -85,7 +62,7 @@ func (e *Executor) readTaskvars() error { } if b, err := ioutil.ReadFile(osSpecificFile + ".yml"); err == nil { - osTaskvars := make(Vars, 10) + osTaskvars := make(taskfile.Vars, 10) if err := yaml.UnmarshalStrict(b, &osTaskvars); err != nil { return err } diff --git a/variables.go b/variables.go index 526a2ed6..c25463bd 100644 --- a/variables.go +++ b/variables.go @@ -2,7 +2,6 @@ package task import ( "bytes" - "errors" "os" "path/filepath" "runtime" @@ -10,6 +9,7 @@ import ( "text/template" "github.com/go-task/task/internal/execext" + "github.com/go-task/task/internal/taskfile" "github.com/Masterminds/sprig" "github.com/mitchellh/go-homedir" @@ -20,70 +20,20 @@ var ( TaskvarsFilePath = "Taskvars" ) -var ( - // ErrCantUnmarshalVar is returned for invalid var YAML. - ErrCantUnmarshalVar = errors.New("task: can't unmarshal var value") -) - -// Vars is a string[string] variables map. -type Vars map[string]Var - -func getEnvironmentVariables() Vars { +func getEnvironmentVariables() taskfile.Vars { var ( env = os.Environ() - m = make(Vars, len(env)) + m = make(taskfile.Vars, len(env)) ) for _, e := range env { keyVal := strings.SplitN(e, "=", 2) key, val := keyVal[0], keyVal[1] - m[key] = Var{Static: val} + m[key] = taskfile.Var{Static: val} } return m } -func (vs Vars) toStringMap() (m map[string]string) { - m = make(map[string]string, len(vs)) - for k, v := range vs { - if v.Sh != "" { - // Dynamic variable is not yet resolved; trigger - // to be used in templates. - continue - } - m[k] = v.Static - } - return -} - -// Var represents either a static or dynamic variable. -type Var struct { - Static string - Sh string -} - -// UnmarshalYAML implements yaml.Unmarshaler interface. -func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error { - var str string - if err := unmarshal(&str); err == nil { - if strings.HasPrefix(str, "$") { - v.Sh = strings.TrimPrefix(str, "$") - } else { - v.Static = str - } - return nil - } - - var sh struct { - Sh string - } - if err := unmarshal(&sh); err == nil { - v.Sh = sh.Sh - return nil - } - - return ErrCantUnmarshalVar -} - // getVariables returns fully resolved variables following the priority order: // 1. Call variables (should already have been resolved) // 2. Environment (should not need to be resolved) @@ -91,20 +41,20 @@ func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error { // - call, taskvars and environment variables // 4. Taskvars variables, resolved with access to: // - environment variables -func (e *Executor) getVariables(call Call) (Vars, error) { +func (e *Executor) getVariables(call taskfile.Call) (taskfile.Vars, error) { t, ok := e.Taskfile.Tasks[call.Task] if !ok { return nil, &taskNotFoundError{call.Task} } - merge := func(dest Vars, srcs ...Vars) { + merge := func(dest taskfile.Vars, srcs ...taskfile.Vars) { for _, src := range srcs { for k, v := range src { dest[k] = v } } } - varsKeys := func(srcs ...Vars) []string { + varsKeys := func(srcs ...taskfile.Vars) []string { m := make(map[string]struct{}) for _, src := range srcs { for k := range src { @@ -117,29 +67,29 @@ func (e *Executor) getVariables(call Call) (Vars, error) { } return lst } - replaceVars := func(dest Vars, keys []string) error { + replaceVars := func(dest taskfile.Vars, keys []string) error { r := varReplacer{vars: dest} for _, k := range keys { v := dest[k] - dest[k] = Var{ + dest[k] = taskfile.Var{ Static: r.replace(v.Static), Sh: r.replace(v.Sh), } } return r.err } - resolveShell := func(dest Vars, keys []string) error { + resolveShell := func(dest taskfile.Vars, keys []string) error { for _, k := range keys { v := dest[k] static, err := e.handleShVar(v) if err != nil { return err } - dest[k] = Var{Static: static} + dest[k] = taskfile.Var{Static: static} } return nil } - update := func(dest Vars, srcs ...Vars) error { + update := func(dest taskfile.Vars, srcs ...taskfile.Vars) error { merge(dest, srcs...) // updatedKeys ensures template evaluation is run only once. updatedKeys := varsKeys(srcs...) @@ -151,7 +101,7 @@ func (e *Executor) getVariables(call Call) (Vars, error) { // Resolve taskvars variables to "result" with environment override variables. override := getEnvironmentVariables() - result := make(Vars, len(e.taskvars)+len(t.Vars)+len(override)) + result := make(taskfile.Vars, len(e.taskvars)+len(t.Vars)+len(override)) if err := update(result, e.taskvars, override); err != nil { return nil, err } @@ -163,7 +113,7 @@ func (e *Executor) getVariables(call Call) (Vars, error) { return result, nil } -func (e *Executor) handleShVar(v Var) (string, error) { +func (e *Executor) handleShVar(v taskfile.Var) (string, error) { if v.Static != "" || v.Sh == "" { return v.Static, nil } @@ -197,7 +147,7 @@ func (e *Executor) handleShVar(v Var) (string, error) { // CompiledTask returns a copy of a task, but replacing variables in almost all // properties using the Go template package. -func (e *Executor) CompiledTask(call Call) (*Task, error) { +func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { origTask, ok := e.Taskfile.Tasks[call.Task] if !ok { return nil, &taskNotFoundError{call.Task} @@ -209,7 +159,7 @@ func (e *Executor) CompiledTask(call Call) (*Task, error) { } r := varReplacer{vars: vars} - new := Task{ + new := taskfile.Task{ Task: origTask.Task, Desc: r.replace(origTask.Desc), Sources: r.replaceSlice(origTask.Sources), @@ -233,13 +183,13 @@ func (e *Executor) CompiledTask(call Call) (*Task, error) { if err != nil { return nil, err } - new.Env[k] = Var{Static: static} + new.Env[k] = taskfile.Var{Static: static} } if len(origTask.Cmds) > 0 { - new.Cmds = make([]*Cmd, len(origTask.Cmds)) + new.Cmds = make([]*taskfile.Cmd, len(origTask.Cmds)) for i, cmd := range origTask.Cmds { - new.Cmds[i] = &Cmd{ + new.Cmds[i] = &taskfile.Cmd{ Task: r.replace(cmd.Task), Silent: cmd.Silent, Cmd: r.replace(cmd.Cmd), @@ -249,9 +199,9 @@ func (e *Executor) CompiledTask(call Call) (*Task, error) { } } if len(origTask.Deps) > 0 { - new.Deps = make([]*Dep, len(origTask.Deps)) + new.Deps = make([]*taskfile.Dep, len(origTask.Deps)) for i, dep := range origTask.Deps { - new.Deps[i] = &Dep{ + new.Deps[i] = &taskfile.Dep{ Task: r.replace(dep.Task), Vars: r.replaceVars(dep.Vars), } @@ -266,7 +216,7 @@ func (e *Executor) CompiledTask(call Call) (*Task, error) { // happen will be assigned to r.err, and consecutive calls to funcs will just // return the zero value. type varReplacer struct { - vars Vars + vars taskfile.Vars strMap map[string]string err error } @@ -283,7 +233,7 @@ func (r *varReplacer) replace(str string) string { } if r.strMap == nil { - r.strMap = r.vars.toStringMap() + r.strMap = r.vars.ToStringMap() } var b bytes.Buffer @@ -306,14 +256,14 @@ func (r *varReplacer) replaceSlice(strs []string) []string { return new } -func (r *varReplacer) replaceVars(vars Vars) Vars { +func (r *varReplacer) replaceVars(vars taskfile.Vars) taskfile.Vars { if r.err != nil || len(vars) == 0 { return nil } - new := make(Vars, len(vars)) + new := make(taskfile.Vars, len(vars)) for k, v := range vars { - new[k] = Var{ + new[k] = taskfile.Var{ Static: r.replace(v.Static), Sh: r.replace(v.Sh), } diff --git a/watch.go b/watch.go index 33bacc84..64b18895 100644 --- a/watch.go +++ b/watch.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/go-task/task/internal/taskfile" "github.com/mattn/go-zglob" "github.com/radovskyb/watcher" ) @@ -15,7 +16,7 @@ var watchIgnoredDirs = []string{ } // watchTasks start watching the given tasks -func (e *Executor) watchTasks(calls ...Call) error { +func (e *Executor) watchTasks(calls ...taskfile.Call) error { tasks := make([]string, len(calls)) for i, c := range calls { tasks[i] = c.Task @@ -83,7 +84,7 @@ func (e *Executor) watchTasks(calls ...Call) error { return w.Start(time.Second) } -func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...Call) error { +func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Call) error { oldWatchedFiles := make(map[string]struct{}) for f := range w.WatchedFiles() { oldWatchedFiles[f] = struct{}{} @@ -95,21 +96,21 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...Call) error } } - var registerTaskFiles func(Call) error - registerTaskFiles = func(c Call) error { + 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(Call{Task: d.Task, Vars: d.Vars}); err != nil { + 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(Call{Task: c.Task, Vars: c.Vars}); err != nil { + if err := registerTaskFiles(taskfile.Call{Task: c.Task, Vars: c.Vars}); err != nil { return err } }