Skip to content

Commit 4b02772

Browse files
authored
Merge pull request #311 from go-task/vars-refactor-for-v3
v3: Variables refactoring
2 parents aee0ab0 + 68ce864 commit 4b02772

File tree

49 files changed

+420
-152
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+420
-152
lines changed

cmd/task/task.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ func main() {
148148
}
149149

150150
calls, globals := args.Parse(pflag.Args()...)
151-
for name, value := range globals {
152-
e.Taskfile.Vars[name] = value
153-
}
151+
e.Taskfile.Vars.Merge(globals)
154152

155153
ctx := context.Background()
156154
if !watch {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/spf13/pflag v1.0.3
1010
github.com/stretchr/testify v1.5.1
1111
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
12-
gopkg.in/yaml.v2 v2.2.2
12+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
1313
mvdan.cc/sh/v3 v3.1.0
1414
)
1515

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
5959
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
6060
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
6161
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
62+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
63+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6264
mvdan.cc/editorconfig v0.1.1-0.20200121172147-e40951bde157/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
6365
mvdan.cc/sh/v3 v3.1.0 h1:bFxsEzIubuABloc8G1Ko78rbZZ0JspNN9e9+R/w3z5k=
6466
mvdan.cc/sh/v3 v3.1.0/go.mod h1:F+Vm4ZxPJxDKExMLhvjuI50oPnedVXpfjNSrusiTOno=

internal/args/args.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import (
77
)
88

99
// Parse parses command line argument: tasks and vars of each task
10-
func Parse(args ...string) ([]taskfile.Call, taskfile.Vars) {
10+
func Parse(args ...string) ([]taskfile.Call, *taskfile.Vars) {
1111
var calls []taskfile.Call
12-
var globals taskfile.Vars
12+
var globals *taskfile.Vars
1313

1414
for _, arg := range args {
1515
if !strings.Contains(arg, "=") {
@@ -19,18 +19,16 @@ func Parse(args ...string) ([]taskfile.Call, taskfile.Vars) {
1919

2020
if len(calls) < 1 {
2121
if globals == nil {
22-
globals = taskfile.Vars{}
22+
globals = &taskfile.Vars{}
2323
}
24-
2524
name, value := splitVar(arg)
26-
globals[name] = taskfile.Var{Static: value}
25+
globals.Set(name, taskfile.Var{Static: value})
2726
} else {
2827
if calls[len(calls)-1].Vars == nil {
29-
calls[len(calls)-1].Vars = make(taskfile.Vars)
28+
calls[len(calls)-1].Vars = &taskfile.Vars{}
3029
}
31-
32-
name, value := splitVar((arg))
33-
calls[len(calls)-1].Vars[name] = taskfile.Var{Static: value}
30+
name, value := splitVar(arg)
31+
calls[len(calls)-1].Vars.Set(name, taskfile.Var{Static: value})
3432
}
3533
}
3634

internal/args/args_test.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestArgs(t *testing.T) {
1414
tests := []struct {
1515
Args []string
1616
ExpectedCalls []taskfile.Call
17-
ExpectedGlobals taskfile.Vars
17+
ExpectedGlobals *taskfile.Vars
1818
}{
1919
{
2020
Args: []string{"task-a", "task-b", "task-c"},
@@ -29,16 +29,22 @@ func TestArgs(t *testing.T) {
2929
ExpectedCalls: []taskfile.Call{
3030
{
3131
Task: "task-a",
32-
Vars: taskfile.Vars{
33-
"FOO": taskfile.Var{Static: "bar"},
32+
Vars: &taskfile.Vars{
33+
Keys: []string{"FOO"},
34+
Mapping: map[string]taskfile.Var{
35+
"FOO": taskfile.Var{Static: "bar"},
36+
},
3437
},
3538
},
3639
{Task: "task-b"},
3740
{
3841
Task: "task-c",
39-
Vars: taskfile.Vars{
40-
"BAR": taskfile.Var{Static: "baz"},
41-
"BAZ": taskfile.Var{Static: "foo"},
42+
Vars: &taskfile.Vars{
43+
Keys: []string{"BAR", "BAZ"},
44+
Mapping: map[string]taskfile.Var{
45+
"BAR": taskfile.Var{Static: "baz"},
46+
"BAZ": taskfile.Var{Static: "foo"},
47+
},
4248
},
4349
},
4450
},
@@ -48,8 +54,11 @@ func TestArgs(t *testing.T) {
4854
ExpectedCalls: []taskfile.Call{
4955
{
5056
Task: "task-a",
51-
Vars: taskfile.Vars{
52-
"CONTENT": taskfile.Var{Static: "with some spaces"},
57+
Vars: &taskfile.Vars{
58+
Keys: []string{"CONTENT"},
59+
Mapping: map[string]taskfile.Var{
60+
"CONTENT": taskfile.Var{Static: "with some spaces"},
61+
},
5362
},
5463
},
5564
},
@@ -60,8 +69,11 @@ func TestArgs(t *testing.T) {
6069
{Task: "task-a"},
6170
{Task: "task-b"},
6271
},
63-
ExpectedGlobals: taskfile.Vars{
64-
"FOO": {Static: "bar"},
72+
ExpectedGlobals: &taskfile.Vars{
73+
Keys: []string{"FOO"},
74+
Mapping: map[string]taskfile.Var{
75+
"FOO": {Static: "bar"},
76+
},
6577
},
6678
},
6779
{
@@ -81,9 +93,12 @@ func TestArgs(t *testing.T) {
8193
ExpectedCalls: []taskfile.Call{
8294
{Task: "default"},
8395
},
84-
ExpectedGlobals: taskfile.Vars{
85-
"FOO": {Static: "bar"},
86-
"BAR": {Static: "baz"},
96+
ExpectedGlobals: &taskfile.Vars{
97+
Keys: []string{"FOO", "BAR"},
98+
Mapping: map[string]taskfile.Var{
99+
"FOO": {Static: "bar"},
100+
"BAR": {Static: "baz"},
101+
},
87102
},
88103
},
89104
}

internal/compiler/compiler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ import (
77
// Compiler handles compilation of a task before its execution.
88
// E.g. variable merger, template processing, etc.
99
type Compiler interface {
10-
GetVariables(t *taskfile.Task, call taskfile.Call) (taskfile.Vars, error)
10+
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
1111
HandleDynamicVar(v taskfile.Var) (string, error)
1212
}

internal/compiler/env.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,12 @@ import (
99

1010
// GetEnviron the all return all environment variables encapsulated on a
1111
// taskfile.Vars
12-
func GetEnviron() taskfile.Vars {
13-
var (
14-
env = os.Environ()
15-
m = make(taskfile.Vars, len(env))
16-
)
17-
18-
for _, e := range env {
12+
func GetEnviron() *taskfile.Vars {
13+
m := &taskfile.Vars{}
14+
for _, e := range os.Environ() {
1915
keyVal := strings.SplitN(e, "=", 2)
2016
key, val := keyVal[0], keyVal[1]
21-
m[key] = taskfile.Var{Static: val}
17+
m.Set(key, taskfile.Var{Static: val})
2218
}
2319
return m
2420
}

internal/compiler/v2/compiler_v2.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ var _ compiler.Compiler = &CompilerV2{}
1919
type CompilerV2 struct {
2020
Dir string
2121

22-
Taskvars taskfile.Vars
23-
TaskfileVars taskfile.Vars
22+
Taskvars *taskfile.Vars
23+
TaskfileVars *taskfile.Vars
2424

2525
Expansions int
2626

@@ -36,10 +36,10 @@ type CompilerV2 struct {
3636
// 3. Taskfile variables
3737
// 4. Taskvars file variables
3838
// 5. Environment variables
39-
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (taskfile.Vars, error) {
39+
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
4040
vr := varResolver{c: c, vars: compiler.GetEnviron()}
41-
vr.vars["TASK"] = taskfile.Var{Static: t.Task}
42-
for _, vars := range []taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
41+
vr.vars.Set("TASK", taskfile.Var{Static: t.Task})
42+
for _, vars := range []*taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
4343
for i := 0; i < c.Expansions; i++ {
4444
vr.merge(vars)
4545
}
@@ -49,27 +49,28 @@ func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (taskfil
4949

5050
type varResolver struct {
5151
c *CompilerV2
52-
vars taskfile.Vars
52+
vars *taskfile.Vars
5353
err error
5454
}
5555

56-
func (vr *varResolver) merge(vars taskfile.Vars) {
56+
func (vr *varResolver) merge(vars *taskfile.Vars) {
5757
if vr.err != nil {
5858
return
5959
}
6060
tr := templater.Templater{Vars: vr.vars}
61-
for k, v := range vars {
61+
vars.Range(func(k string, v taskfile.Var) error {
6262
v = taskfile.Var{
6363
Static: tr.Replace(v.Static),
6464
Sh: tr.Replace(v.Sh),
6565
}
6666
static, err := vr.c.HandleDynamicVar(v)
6767
if err != nil {
6868
vr.err = err
69-
return
69+
return err
7070
}
71-
vr.vars[k] = taskfile.Var{Static: static}
72-
}
71+
vr.vars.Set(k, taskfile.Var{Static: static})
72+
return nil
73+
})
7374
vr.err = tr.Err()
7475
}
7576

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package v3
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"strings"
8+
"sync"
9+
10+
"github.com/go-task/task/v2/internal/compiler"
11+
"github.com/go-task/task/v2/internal/execext"
12+
"github.com/go-task/task/v2/internal/logger"
13+
"github.com/go-task/task/v2/internal/taskfile"
14+
"github.com/go-task/task/v2/internal/templater"
15+
)
16+
17+
var _ compiler.Compiler = &CompilerV3{}
18+
19+
type CompilerV3 struct {
20+
Dir string
21+
22+
TaskfileVars *taskfile.Vars
23+
24+
Logger *logger.Logger
25+
26+
dynamicCache map[string]string
27+
muDynamicCache sync.Mutex
28+
}
29+
30+
func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
31+
result := compiler.GetEnviron()
32+
result.Set("TASK", taskfile.Var{Static: t.Task})
33+
34+
rangeFunc := func(k string, v taskfile.Var) error {
35+
tr := templater.Templater{Vars: result, RemoveNoValue: true}
36+
v = taskfile.Var{
37+
Static: tr.Replace(v.Static),
38+
Sh: tr.Replace(v.Sh),
39+
}
40+
if err := tr.Err(); err != nil {
41+
return err
42+
}
43+
static, err := c.HandleDynamicVar(v)
44+
if err != nil {
45+
return err
46+
}
47+
result.Set(k, taskfile.Var{Static: static})
48+
return nil
49+
}
50+
51+
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
52+
return nil, err
53+
}
54+
if err := call.Vars.Range(rangeFunc); err != nil {
55+
return nil, err
56+
}
57+
if err := t.Vars.Range(rangeFunc); err != nil {
58+
return nil, err
59+
}
60+
61+
return result, nil
62+
}
63+
64+
func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) {
65+
if v.Static != "" || v.Sh == "" {
66+
return v.Static, nil
67+
}
68+
69+
c.muDynamicCache.Lock()
70+
defer c.muDynamicCache.Unlock()
71+
72+
if c.dynamicCache == nil {
73+
c.dynamicCache = make(map[string]string, 30)
74+
}
75+
if result, ok := c.dynamicCache[v.Sh]; ok {
76+
return result, nil
77+
}
78+
79+
var stdout bytes.Buffer
80+
opts := &execext.RunCommandOptions{
81+
Command: v.Sh,
82+
Dir: c.Dir,
83+
Stdout: &stdout,
84+
Stderr: c.Logger.Stderr,
85+
}
86+
if err := execext.RunCommand(context.Background(), opts); err != nil {
87+
return "", fmt.Errorf(`task: Command "%s" in taskvars file failed: %s`, opts.Command, err)
88+
}
89+
90+
// Trim a single trailing newline from the result to make most command
91+
// output easier to use in shell commands.
92+
result := strings.TrimSuffix(stdout.String(), "\n")
93+
94+
c.dynamicCache[v.Sh] = result
95+
c.Logger.VerboseErrf(logger.Magenta, `task: dynamic variable: '%s' result: '%s'`, v.Sh, result)
96+
97+
return result, nil
98+
}

internal/taskfile/call.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ package taskfile
33
// Call is the parameters to a task call
44
type Call struct {
55
Task string
6-
Vars Vars
6+
Vars *Vars
77
}

0 commit comments

Comments
 (0)