Skip to content

Commit 68ce864

Browse files
committed
Create v3 compiler which respects declaration order of variables
Also, fix "<no value>" been printed when a non-existing variable is printed.
1 parent 4913b6a commit 68ce864

File tree

31 files changed

+225
-35
lines changed

31 files changed

+225
-35
lines changed
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/templater/templater.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package templater
22

33
import (
44
"bytes"
5+
"strings"
56
"text/template"
67

78
"github.com/go-task/task/v2/internal/taskfile"
@@ -12,7 +13,8 @@ import (
1213
// happen will be assigned to r.err, and consecutive calls to funcs will just
1314
// return the zero value.
1415
type Templater struct {
15-
Vars *taskfile.Vars
16+
Vars *taskfile.Vars
17+
RemoveNoValue bool
1618

1719
cacheMap map[string]interface{}
1820
err error
@@ -42,6 +44,9 @@ func (r *Templater) Replace(str string) string {
4244
r.err = err
4345
return ""
4446
}
47+
if r.RemoveNoValue {
48+
return strings.ReplaceAll(b.String(), "<no value>", "")
49+
}
4550
return b.String()
4651
}
4752

task.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/go-task/task/v2/internal/compiler"
1414
compilerv2 "github.com/go-task/task/v2/internal/compiler/v2"
15+
compilerv3 "github.com/go-task/task/v2/internal/compiler/v3"
1516
"github.com/go-task/task/v2/internal/execext"
1617
"github.com/go-task/task/v2/internal/logger"
1718
"github.com/go-task/task/v2/internal/output"
@@ -131,9 +132,9 @@ func (e *Executor) Setup() error {
131132
Color: e.Color,
132133
}
133134

134-
v, err := strconv.ParseFloat(e.Taskfile.Version, 64)
135+
v, err := e.parsedVersion()
135136
if err != nil {
136-
return fmt.Errorf(`task: Could not parse taskfile version "%s": %v`, e.Taskfile.Version, err)
137+
137138
}
138139

139140
if v < 2 {
@@ -154,12 +155,20 @@ func (e *Executor) Setup() error {
154155
e.Logger.Color = false
155156
}
156157

157-
e.Compiler = &compilerv2.CompilerV2{
158-
Dir: e.Dir,
159-
Taskvars: e.taskvars,
160-
TaskfileVars: e.Taskfile.Vars,
161-
Expansions: e.Taskfile.Expansions,
162-
Logger: e.Logger,
158+
if v < 3 {
159+
e.Compiler = &compilerv2.CompilerV2{
160+
Dir: e.Dir,
161+
Taskvars: e.taskvars,
162+
TaskfileVars: e.Taskfile.Vars,
163+
Expansions: e.Taskfile.Expansions,
164+
Logger: e.Logger,
165+
}
166+
} else {
167+
e.Compiler = &compilerv3.CompilerV3{
168+
Dir: e.Dir,
169+
TaskfileVars: e.Taskfile.Vars,
170+
Logger: e.Logger,
171+
}
163172
}
164173

165174
if v < 2.1 && e.Taskfile.Output != "" {
@@ -231,6 +240,14 @@ func (e *Executor) Setup() error {
231240
return nil
232241
}
233242

243+
func (e *Executor) parsedVersion() (float64, error) {
244+
v, err := strconv.ParseFloat(e.Taskfile.Version, 64)
245+
if err != nil {
246+
return 0, fmt.Errorf(`task: Could not parse taskfile version "%s": %v`, e.Taskfile.Version, err)
247+
}
248+
return v, nil
249+
}
250+
234251
// RunTask runs a task by its name
235252
func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
236253
t, err := e.CompiledTask(call)

task_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ func TestVarsV2(t *testing.T) {
107107
tt.Run(t)
108108
}
109109

110+
func TestVarsV3(t *testing.T) {
111+
tt := fileContentTest{
112+
Dir: "testdata/vars/v3",
113+
Target: "default",
114+
Files: map[string]string{
115+
"missing-var.txt": "\n",
116+
"var-order.txt": "ABCDEF\n",
117+
"dependent-sh.txt": "123456\n",
118+
"with-call.txt": "Hi, ABC123!\n",
119+
},
120+
}
121+
tt.Run(t)
122+
}
123+
110124
func TestMultilineVars(t *testing.T) {
111125
for _, dir := range []string{"testdata/vars/v2/multiline"} {
112126
tt := fileContentTest{

testdata/checksum/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
build:

testdata/cyclic/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
task-1:

testdata/deps/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
default:

testdata/dir/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
whereami:

testdata/dir/explicit_doesnt_exist/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
whereami:

testdata/dir/explicit_exists/Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2'
1+
version: '3'
22

33
tasks:
44
whereami:

0 commit comments

Comments
 (0)