mirror of
https://github.com/go-task/task.git
synced 2025-01-12 04:34:11 +02:00
commit
cb72c404f5
53
README.md
53
README.md
@ -39,9 +39,7 @@ your `PATH`. DEB and RPM packages are also available.
|
||||
## Usage
|
||||
|
||||
Create a file called `Taskfile.yml` in the root of the project.
|
||||
(`Taskfile.toml` and `Taskfile.json` are also supported, but YAML is used in
|
||||
the documentation). The `cmds` attribute should contains the commands of a
|
||||
task:
|
||||
The `cmds` attribute should contains the commands of a task:
|
||||
|
||||
```yml
|
||||
build:
|
||||
@ -167,22 +165,53 @@ The above will fail with the message: "cyclic dependency detected".
|
||||
|
||||
When a task has many dependencies, they are executed concurrently. This will
|
||||
often result in a faster build pipeline. But in some situations you may need
|
||||
to call other tasks serially. For this just prefix a command with `^`:
|
||||
to call other tasks serially. In this case, just use the following syntax:
|
||||
|
||||
```yml
|
||||
main-task:
|
||||
cmds:
|
||||
- task: task-to-be-called
|
||||
- task: another-task
|
||||
- echo "Both done"
|
||||
|
||||
task-to-be-called:
|
||||
cmds:
|
||||
- echo "Task to be called"
|
||||
|
||||
another-task:
|
||||
cmds:
|
||||
- echo "Another task"
|
||||
```
|
||||
|
||||
Overriding variables in the called task is as simple as informing `vars`
|
||||
attribute:
|
||||
|
||||
```yml
|
||||
main-task:
|
||||
cmds:
|
||||
- task: write-file
|
||||
vars: {FILE: "hello.txt", CONTENT: "Hello!"}
|
||||
- task: write-file
|
||||
vars: {FILE: "world.txt", CONTENT: "World!"}
|
||||
|
||||
write-file:
|
||||
cmds:
|
||||
- echo "{{.CONTENT}}" > {{.FILE}}
|
||||
```
|
||||
|
||||
The above syntax is also supported in `deps`.
|
||||
|
||||
> NOTE: It's also possible to call a task without any param prefixing it
|
||||
with `^`, but this syntax is deprecaded:
|
||||
|
||||
```yml
|
||||
a-task:
|
||||
cmds:
|
||||
- ^another-task
|
||||
- ^even-another-task
|
||||
- echo "Both done"
|
||||
|
||||
another-task:
|
||||
cmds:
|
||||
- ...
|
||||
|
||||
even-another-task:
|
||||
cmds:
|
||||
- ...
|
||||
- echo "Another task"
|
||||
```
|
||||
|
||||
### Prevent unnecessary work
|
||||
@ -256,7 +285,7 @@ setvar:
|
||||
The above sample saves the path into a new variable which is then again echoed.
|
||||
|
||||
You can use environment variables, task level variables and a file called
|
||||
`Taskvars.yml` (or `Taskvars.toml` or `Taskvars.json`) as source of variables.
|
||||
`Taskvars.yml` as source of variables.
|
||||
|
||||
They are evaluated in the following order:
|
||||
|
||||
|
68
command.go
Normal file
68
command.go
Normal file
@ -0,0 +1,68 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cmd is a task command
|
||||
type Cmd struct {
|
||||
Cmd string
|
||||
Task string
|
||||
Vars Vars
|
||||
}
|
||||
|
||||
// Dep is a task dependency
|
||||
type Dep struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrCantUnmarshalCmd is returned for invalid command YAML
|
||||
ErrCantUnmarshalCmd = errors.New("task: can't unmarshal cmd value")
|
||||
// ErrCantUnmarshalDep is returned for invalid dependency YAML
|
||||
ErrCantUnmarshalDep = errors.New("task: can't unmarshal dep value")
|
||||
)
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var cmd string
|
||||
if err := unmarshal(&cmd); err == nil {
|
||||
if strings.HasPrefix(cmd, "^") {
|
||||
c.Task = strings.TrimPrefix(cmd, "^")
|
||||
} else {
|
||||
c.Cmd = cmd
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err == nil {
|
||||
c.Task = taskCall.Task
|
||||
c.Vars = taskCall.Vars
|
||||
return nil
|
||||
}
|
||||
return ErrCantUnmarshalCmd
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (d *Dep) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var task string
|
||||
if err := unmarshal(&task); err == nil {
|
||||
d.Task = task
|
||||
return nil
|
||||
}
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err == nil {
|
||||
d.Task = taskCall.Task
|
||||
d.Vars = taskCall.Vars
|
||||
return nil
|
||||
}
|
||||
return ErrCantUnmarshalDep
|
||||
}
|
54
command_test.go
Normal file
54
command_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
package task_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestCmdParse(t *testing.T) {
|
||||
const (
|
||||
yamlCmd = `echo "a string command"`
|
||||
yamlDep = `"task-name"`
|
||||
yamlTaskCall = `
|
||||
task: another-task
|
||||
vars:
|
||||
PARAM1: VALUE1
|
||||
PARAM2: VALUE2
|
||||
`
|
||||
)
|
||||
tests := []struct {
|
||||
content string
|
||||
v interface{}
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
yamlCmd,
|
||||
&task.Cmd{},
|
||||
&task.Cmd{Cmd: `echo "a string command"`},
|
||||
},
|
||||
{
|
||||
yamlTaskCall,
|
||||
&task.Cmd{},
|
||||
&task.Cmd{Task: "another-task", Vars: task.Vars{"PARAM1": "VALUE1", "PARAM2": "VALUE2"}},
|
||||
},
|
||||
{
|
||||
yamlDep,
|
||||
&task.Dep{},
|
||||
&task.Dep{Task: "task-name"},
|
||||
},
|
||||
{
|
||||
yamlTaskCall,
|
||||
&task.Dep{},
|
||||
&task.Dep{Task: "another-task", Vars: task.Vars{"PARAM1": "VALUE1", "PARAM2": "VALUE2"}},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
err := yaml.Unmarshal([]byte(test.content), test.v)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.expected, test.v)
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ func (e *Executor) HasCyclicDep() bool {
|
||||
defer delete(visits, name)
|
||||
|
||||
for _, d := range t.Deps {
|
||||
if !checkCyclicDep(d, e.Tasks[d]) {
|
||||
if !checkCyclicDep(d.Task, e.Tasks[d.Task]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ func TestCyclicDepCheck(t *testing.T) {
|
||||
isCyclic := &task.Executor{
|
||||
Tasks: task.Tasks{
|
||||
"task-a": &task.Task{
|
||||
Deps: []string{"task-b"},
|
||||
Deps: []*task.Dep{&task.Dep{Task: "task-b"}},
|
||||
},
|
||||
"task-b": &task.Task{
|
||||
Deps: []string{"task-a"},
|
||||
Deps: []*task.Dep{&task.Dep{Task: "task-a"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -25,10 +25,10 @@ func TestCyclicDepCheck(t *testing.T) {
|
||||
isNotCyclic := &task.Executor{
|
||||
Tasks: task.Tasks{
|
||||
"task-a": &task.Task{
|
||||
Deps: []string{"task-c"},
|
||||
Deps: []*task.Dep{&task.Dep{Task: "task-c"}},
|
||||
},
|
||||
"task-b": &task.Task{
|
||||
Deps: []string{"task-c"},
|
||||
Deps: []*task.Dep{&task.Dep{Task: "task-c"}},
|
||||
},
|
||||
"task-c": &task.Task{},
|
||||
},
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"hello": {
|
||||
"cmds": [
|
||||
"echo \"I am going to write a file named 'output.txt' now.\"",
|
||||
"echo \"hello\" > output.txt"
|
||||
],
|
||||
"generates": [
|
||||
"output.txt"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
[hello]
|
||||
cmds = [
|
||||
"echo \"I am going to write a file named 'output.txt' now.\"",
|
||||
"echo \"hello\" > output.txt"
|
||||
]
|
||||
generates = ["output.txt"]
|
@ -1,13 +1,11 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/imdario/mergo"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
@ -26,7 +24,6 @@ func (e *Executor) ReadTaskfile() error {
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case taskFileNotFound:
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
@ -34,6 +31,9 @@ func (e *Executor) ReadTaskfile() error {
|
||||
if err := mergo.MapWithOverwrite(&e.Tasks, osTasks); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.readTaskvarsFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -41,11 +41,16 @@ func (e *Executor) readTaskfileData(path string) (tasks map[string]*Task, err er
|
||||
if b, err := ioutil.ReadFile(path + ".yml"); err == nil {
|
||||
return tasks, yaml.Unmarshal(b, &tasks)
|
||||
}
|
||||
if b, err := ioutil.ReadFile(path + ".json"); err == nil {
|
||||
return tasks, json.Unmarshal(b, &tasks)
|
||||
}
|
||||
if b, err := ioutil.ReadFile(path + ".toml"); err == nil {
|
||||
return tasks, toml.Unmarshal(b, &tasks)
|
||||
}
|
||||
return nil, taskFileNotFound{path}
|
||||
}
|
||||
|
||||
func (e *Executor) readTaskvarsFile() error {
|
||||
file := filepath.Join(e.Dir, TaskvarsFilePath)
|
||||
|
||||
if b, err := ioutil.ReadFile(file + ".yml"); err == nil {
|
||||
if err := yaml.Unmarshal(b, &e.taskvars); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
89
task.go
89
task.go
@ -30,24 +30,28 @@ type Executor struct {
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
|
||||
taskvars Vars
|
||||
watchingFiles map[string]struct{}
|
||||
}
|
||||
|
||||
// Vars is a string[string] variables map
|
||||
type Vars map[string]string
|
||||
|
||||
// Tasks representas a group of tasks
|
||||
type Tasks map[string]*Task
|
||||
|
||||
// Task represents a task
|
||||
type Task struct {
|
||||
Cmds []string
|
||||
Deps []string
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Desc string
|
||||
Sources []string
|
||||
Generates []string
|
||||
Status []string
|
||||
Dir string
|
||||
Vars map[string]string
|
||||
Vars Vars
|
||||
Set string
|
||||
Env map[string]string
|
||||
Env Vars
|
||||
}
|
||||
|
||||
// Run runs Task
|
||||
@ -83,7 +87,7 @@ func (e *Executor) Run(args ...string) error {
|
||||
}
|
||||
|
||||
for _, a := range args {
|
||||
if err := e.RunTask(context.Background(), a); err != nil {
|
||||
if err := e.RunTask(context.Background(), a, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -91,18 +95,18 @@ func (e *Executor) Run(args ...string) error {
|
||||
}
|
||||
|
||||
// RunTask runs a task by its name
|
||||
func (e *Executor) RunTask(ctx context.Context, name string) error {
|
||||
func (e *Executor) RunTask(ctx context.Context, name string, vars Vars) error {
|
||||
t, ok := e.Tasks[name]
|
||||
if !ok {
|
||||
return &taskNotFoundError{name}
|
||||
}
|
||||
|
||||
if err := e.runDeps(ctx, name); err != nil {
|
||||
if err := e.runDeps(ctx, name, vars); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !e.Force {
|
||||
upToDate, err := e.isTaskUpToDate(ctx, name)
|
||||
upToDate, err := e.isTaskUpToDate(ctx, name, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -113,27 +117,27 @@ func (e *Executor) RunTask(ctx context.Context, name string) error {
|
||||
}
|
||||
|
||||
for i := range t.Cmds {
|
||||
if err := e.runCommand(ctx, name, i); err != nil {
|
||||
if err := e.runCommand(ctx, name, i, vars); err != nil {
|
||||
return &taskRunError{name, err}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) runDeps(ctx context.Context, task string) error {
|
||||
func (e *Executor) runDeps(ctx context.Context, task string, vars Vars) error {
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
t := e.Tasks[task]
|
||||
|
||||
for _, d := range t.Deps {
|
||||
dep := d
|
||||
d := d
|
||||
|
||||
g.Go(func() error {
|
||||
dep, err := e.ReplaceVariables(task, dep)
|
||||
dep, err := e.ReplaceVariables(d.Task, task, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = e.RunTask(ctx, dep); err != nil {
|
||||
if err = e.RunTask(ctx, dep, d.Vars); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -146,28 +150,32 @@ func (e *Executor) runDeps(ctx context.Context, task string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) isTaskUpToDate(ctx context.Context, task string) (bool, error) {
|
||||
func (e *Executor) isTaskUpToDate(ctx context.Context, task string, vars Vars) (bool, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
if len(t.Status) > 0 {
|
||||
return e.isUpToDateStatus(ctx, task)
|
||||
return e.isUpToDateStatus(ctx, task, vars)
|
||||
}
|
||||
return e.isUpToDateTimestamp(ctx, task)
|
||||
return e.isUpToDateTimestamp(ctx, task, vars)
|
||||
}
|
||||
|
||||
func (e *Executor) isUpToDateStatus(ctx context.Context, task string) (bool, error) {
|
||||
func (e *Executor) isUpToDateStatus(ctx context.Context, task string, vars Vars) (bool, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
environ, err := e.getEnviron(task)
|
||||
environ, err := e.getEnviron(task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
dir, err := e.getTaskDir(task)
|
||||
dir, err := e.getTaskDir(task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
status, err := e.ReplaceSliceVariables(t.Status, task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, s := range t.Status {
|
||||
for _, s := range status {
|
||||
err = execext.RunCommand(&execext.RunCommandOptions{
|
||||
Context: ctx,
|
||||
Command: s,
|
||||
@ -181,23 +189,23 @@ func (e *Executor) isUpToDateStatus(ctx context.Context, task string) (bool, err
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (e *Executor) isUpToDateTimestamp(ctx context.Context, task string) (bool, error) {
|
||||
func (e *Executor) isUpToDateTimestamp(ctx context.Context, task string, vars Vars) (bool, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
if len(t.Sources) == 0 || len(t.Generates) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
dir, err := e.getTaskDir(task)
|
||||
dir, err := e.getTaskDir(task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
sources, err := e.ReplaceSliceVariables(task, t.Sources)
|
||||
sources, err := e.ReplaceSliceVariables(t.Sources, task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
generates, err := e.ReplaceSliceVariables(task, t.Generates)
|
||||
generates, err := e.ReplaceSliceVariables(t.Generates, task, vars)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -215,28 +223,25 @@ func (e *Executor) isUpToDateTimestamp(ctx context.Context, task string) (bool,
|
||||
return generatesMinTime.After(sourcesMaxTime), nil
|
||||
}
|
||||
|
||||
func (e *Executor) runCommand(ctx context.Context, task string, i int) error {
|
||||
func (e *Executor) runCommand(ctx context.Context, task string, i int, vars Vars) error {
|
||||
t := e.Tasks[task]
|
||||
cmd := t.Cmds[i]
|
||||
|
||||
c, err := e.ReplaceVariables(task, t.Cmds[i])
|
||||
if cmd.Cmd == "" {
|
||||
return e.RunTask(ctx, cmd.Task, cmd.Vars)
|
||||
}
|
||||
|
||||
c, err := e.ReplaceVariables(cmd.Cmd, task, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.HasPrefix(c, "^") {
|
||||
c = strings.TrimPrefix(c, "^")
|
||||
if err = e.RunTask(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
dir, err := e.getTaskDir(task)
|
||||
dir, err := e.getTaskDir(task, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
envs, err := e.getEnviron(task)
|
||||
envs, err := e.getEnviron(task, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -266,14 +271,14 @@ func (e *Executor) runCommand(ctx context.Context, task string, i int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) getTaskDir(name string) (string, error) {
|
||||
t := e.Tasks[name]
|
||||
func (e *Executor) getTaskDir(task string, vars Vars) (string, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
exeDir, err := e.ReplaceVariables(name, e.Dir)
|
||||
exeDir, err := e.ReplaceVariables(e.Dir, task, vars)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
taskDir, err := e.ReplaceVariables(name, t.Dir)
|
||||
taskDir, err := e.ReplaceVariables(t.Dir, task, vars)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -281,7 +286,7 @@ func (e *Executor) getTaskDir(name string) (string, error) {
|
||||
return filepath.Join(exeDir, taskDir), nil
|
||||
}
|
||||
|
||||
func (e *Executor) getEnviron(task string) ([]string, error) {
|
||||
func (e *Executor) getEnviron(task string, vars Vars) ([]string, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
if t.Env == nil {
|
||||
@ -291,7 +296,7 @@ func (e *Executor) getEnviron(task string) ([]string, error) {
|
||||
envs := os.Environ()
|
||||
|
||||
for k, v := range t.Env {
|
||||
env, err := e.ReplaceVariables(task, fmt.Sprintf("%s=%s", k, v))
|
||||
env, err := e.ReplaceVariables(fmt.Sprintf("%s=%s", k, v), task, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
32
task_test.go
32
task_test.go
@ -166,3 +166,35 @@ func TestInit(t *testing.T) {
|
||||
t.Errorf("Taskfile.yml should exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParams(t *testing.T) {
|
||||
const dir = "testdata/params"
|
||||
var files = []struct {
|
||||
file string
|
||||
content string
|
||||
}{
|
||||
{"hello.txt", "Hello\n"},
|
||||
{"world.txt", "World\n"},
|
||||
{"exclamation.txt", "!\n"},
|
||||
{"dep1.txt", "Dependence1\n"},
|
||||
{"dep2.txt", "Dependence2\n"},
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
_ = os.Remove(filepath.Join(dir, f.file))
|
||||
}
|
||||
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: ioutil.Discard,
|
||||
Stderr: ioutil.Discard,
|
||||
}
|
||||
assert.NoError(t, e.ReadTaskfile())
|
||||
assert.NoError(t, e.Run("default"))
|
||||
|
||||
for _, f := range files {
|
||||
content, err := ioutil.ReadFile(filepath.Join(dir, f.file))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, f.content, string(content))
|
||||
}
|
||||
}
|
||||
|
1
testdata/params/.gitignore
vendored
Normal file
1
testdata/params/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.txt
|
17
testdata/params/Taskfile.yml
vendored
Normal file
17
testdata/params/Taskfile.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
default:
|
||||
deps:
|
||||
- task: write-file
|
||||
vars: {CONTENT: Dependence1, FILE: dep1.txt}
|
||||
- task: write-file
|
||||
vars: {CONTENT: Dependence2, FILE: dep2.txt}
|
||||
cmds:
|
||||
- task: write-file
|
||||
vars: {CONTENT: Hello, FILE: hello.txt}
|
||||
- task: write-file
|
||||
vars: {CONTENT: "$echo 'World'", FILE: world.txt}
|
||||
- task: write-file
|
||||
vars: {CONTENT: "!", FILE: exclamation.txt}
|
||||
|
||||
write-file:
|
||||
cmds:
|
||||
- echo {{.CONTENT}} > {{.FILE}}
|
@ -2,9 +2,7 @@ package task
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -13,9 +11,7 @@ import (
|
||||
|
||||
"github.com/go-task/task/execext"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/Masterminds/sprig"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -52,7 +48,7 @@ func (e *Executor) handleDynamicVariableContent(value string) (string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *Executor) getVariables(task string) (map[string]string, error) {
|
||||
func (e *Executor) getVariables(task string, vars Vars) (map[string]string, error) {
|
||||
t := e.Tasks[task]
|
||||
|
||||
localVariables := make(map[string]string)
|
||||
@ -63,20 +59,27 @@ func (e *Executor) getVariables(task string) (map[string]string, error) {
|
||||
}
|
||||
localVariables[key] = val
|
||||
}
|
||||
if fileVariables, err := e.readTaskvarsFile(); err == nil {
|
||||
for key, value := range fileVariables {
|
||||
if e.taskvars != nil {
|
||||
for key, value := range e.taskvars {
|
||||
val, err := e.handleDynamicVariableContent(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localVariables[key] = val
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range getEnvironmentVariables() {
|
||||
localVariables[key] = value
|
||||
}
|
||||
if vars != nil {
|
||||
for k, v := range vars {
|
||||
val, err := e.handleDynamicVariableContent(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localVariables[k] = val
|
||||
}
|
||||
}
|
||||
return localVariables, nil
|
||||
}
|
||||
|
||||
@ -109,11 +112,11 @@ func init() {
|
||||
}
|
||||
|
||||
// ReplaceSliceVariables writes vars into initial string slice
|
||||
func (e *Executor) ReplaceSliceVariables(task string, initials []string) ([]string, error) {
|
||||
func (e *Executor) ReplaceSliceVariables(initials []string, task string, vars Vars) ([]string, error) {
|
||||
result := make([]string, len(initials))
|
||||
for i, s := range initials {
|
||||
var err error
|
||||
result[i], err = e.ReplaceVariables(task, s)
|
||||
result[i], err = e.ReplaceVariables(s, task, vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -122,8 +125,8 @@ func (e *Executor) ReplaceSliceVariables(task string, initials []string) ([]stri
|
||||
}
|
||||
|
||||
// ReplaceVariables writes vars into initial string
|
||||
func (e *Executor) ReplaceVariables(task, initial string) (string, error) {
|
||||
vars, err := e.getVariables(task)
|
||||
func (e *Executor) ReplaceVariables(initial, task string, vars Vars) (string, error) {
|
||||
vars, err := e.getVariables(task, vars)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -154,28 +157,3 @@ func getEnvironmentVariables() map[string]string {
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (e *Executor) readTaskvarsFile() (map[string]string, error) {
|
||||
file := filepath.Join(e.Dir, TaskvarsFilePath)
|
||||
|
||||
var variables map[string]string
|
||||
if b, err := ioutil.ReadFile(file + ".yml"); err == nil {
|
||||
if err := yaml.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
if b, err := ioutil.ReadFile(file + ".json"); err == nil {
|
||||
if err := json.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
if b, err := ioutil.ReadFile(file + ".toml"); err == nil {
|
||||
if err := toml.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
|
10
watch.go
10
watch.go
@ -15,7 +15,7 @@ func (e *Executor) watchTasks(args ...string) error {
|
||||
|
||||
// run tasks on init
|
||||
for _, a := range args {
|
||||
if err := e.RunTask(context.Background(), a); err != nil {
|
||||
if err := e.RunTask(context.Background(), a, nil); err != nil {
|
||||
e.println(err)
|
||||
break
|
||||
}
|
||||
@ -41,7 +41,7 @@ loop:
|
||||
select {
|
||||
case <-watcher.Events:
|
||||
for _, a := range args {
|
||||
if err := e.RunTask(context.Background(), a); err != nil {
|
||||
if err := e.RunTask(context.Background(), a, nil); err != nil {
|
||||
e.println(err)
|
||||
continue loop
|
||||
}
|
||||
@ -68,7 +68,11 @@ func (e *Executor) registerWatchedFiles(w *fsnotify.Watcher, args []string) erro
|
||||
if !ok {
|
||||
return &taskNotFoundError{a}
|
||||
}
|
||||
if err := e.registerWatchedFiles(w, task.Deps); err != nil {
|
||||
deps := make([]string, len(task.Deps))
|
||||
for i, d := range task.Deps {
|
||||
deps[i] = d.Task
|
||||
}
|
||||
if err := e.registerWatchedFiles(w, deps); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range task.Sources {
|
||||
|
Loading…
Reference in New Issue
Block a user