Skip to content

Commit a60c2ec

Browse files
authored
fix: sources brace expansion (#2075)
1 parent f789c57 commit a60c2ec

File tree

10 files changed

+63
-32
lines changed

10 files changed

+63
-32
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ require (
1717
github.com/go-task/slim-sprig/v3 v3.0.0
1818
github.com/go-task/template v0.1.0
1919
github.com/joho/godotenv v1.5.1
20-
github.com/mattn/go-zglob v0.0.6
2120
github.com/mitchellh/hashstructure/v2 v2.0.2
2221
github.com/otiai10/copy v1.14.1
2322
github.com/puzpuzpuz/xsync/v3 v3.5.1

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
9898
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
9999
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
100100
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
101-
github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A=
102-
github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY=
103101
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
104102
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
105103
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=

internal/execext/exec.go

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import (
1111

1212
"mvdan.cc/sh/v3/expand"
1313
"mvdan.cc/sh/v3/interp"
14-
"mvdan.cc/sh/v3/shell"
1514
"mvdan.cc/sh/v3/syntax"
1615

1716
"github.com/go-task/task/v3/errors"
1817
)
1918

20-
// RunCommandOptions is the options for the RunCommand func
19+
// ErrNilOptions is returned when a nil options is given
20+
var ErrNilOptions = errors.New("execext: nil options given")
21+
22+
// RunCommandOptions is the options for the [RunCommand] func.
2123
type RunCommandOptions struct {
2224
Command string
2325
Dir string
@@ -29,9 +31,6 @@ type RunCommandOptions struct {
2931
Stderr io.Writer
3032
}
3133

32-
// ErrNilOptions is returned when a nil options is given
33-
var ErrNilOptions = errors.New("execext: nil options given")
34-
3534
// RunCommand runs a shell command
3635
func RunCommand(ctx context.Context, opts *RunCommandOptions) error {
3736
if opts == nil {
@@ -91,22 +90,64 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error {
9190
return r.Run(ctx, p)
9291
}
9392

94-
// Expand is a helper to mvdan.cc/shell.Fields that returns the first field
95-
// if available.
96-
func Expand(s string) (string, error) {
93+
func escape(s string) string {
9794
s = filepath.ToSlash(s)
9895
s = strings.ReplaceAll(s, " ", `\ `)
9996
s = strings.ReplaceAll(s, "&", `\&`)
10097
s = strings.ReplaceAll(s, "(", `\(`)
10198
s = strings.ReplaceAll(s, ")", `\)`)
102-
fields, err := shell.Fields(s, nil)
99+
return s
100+
}
101+
102+
// ExpandLiteral is a wrapper around [expand.Literal]. It will escape the input
103+
// string, expand any shell symbols (such as '~') and resolve any environment
104+
// variables.
105+
func ExpandLiteral(s string) (string, error) {
106+
if s == "" {
107+
return "", nil
108+
}
109+
s = escape(s)
110+
p := syntax.NewParser()
111+
var words []*syntax.Word
112+
err := p.Words(strings.NewReader(s), func(w *syntax.Word) bool {
113+
words = append(words, w)
114+
return true
115+
})
103116
if err != nil {
104117
return "", err
105118
}
106-
if len(fields) > 0 {
107-
return fields[0], nil
119+
if len(words) == 0 {
120+
return "", nil
121+
}
122+
cfg := &expand.Config{
123+
Env: expand.FuncEnviron(os.Getenv),
124+
ReadDir2: os.ReadDir,
125+
GlobStar: true,
126+
}
127+
return expand.Literal(cfg, words[0])
128+
}
129+
130+
// ExpandFields is a wrapper around [expand.Fields]. It will escape the input
131+
// string, expand any shell symbols (such as '~') and resolve any environment
132+
// variables. It also expands brace expressions ({a.b}) and globs (*/**) and
133+
// returns the results as a list of strings.
134+
func ExpandFields(s string) ([]string, error) {
135+
s = escape(s)
136+
p := syntax.NewParser()
137+
var words []*syntax.Word
138+
err := p.Words(strings.NewReader(s), func(w *syntax.Word) bool {
139+
words = append(words, w)
140+
return true
141+
})
142+
if err != nil {
143+
return nil, err
144+
}
145+
cfg := &expand.Config{
146+
Env: expand.FuncEnviron(os.Getenv),
147+
ReadDir2: os.ReadDir,
148+
GlobStar: true,
108149
}
109-
return "", nil
150+
return expand.Fields(cfg, words...)
110151
}
111152

112153
func execHandler(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {

internal/fingerprint/glob.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"os"
55
"sort"
66

7-
"github.com/mattn/go-zglob"
8-
97
"github.com/go-task/task/v3/internal/execext"
108
"github.com/go-task/task/v3/internal/filepathext"
119
"github.com/go-task/task/v3/taskfile/ast"
@@ -28,12 +26,7 @@ func Globs(dir string, globs []*ast.Glob) ([]string, error) {
2826
func glob(dir string, g string) ([]string, error) {
2927
g = filepathext.SmartJoin(dir, g)
3028

31-
g, err := execext.Expand(g)
32-
if err != nil {
33-
return nil, err
34-
}
35-
36-
fs, err := zglob.GlobFollowSymlinks(g)
29+
fs, err := execext.ExpandFields(g)
3730
if err != nil {
3831
return nil, err
3932
}

setup.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func (e *Executor) setupTempDir() error {
120120
Fingerprint: filepathext.SmartJoin(e.Dir, ".task"),
121121
}
122122
} else if filepath.IsAbs(tempDir) || strings.HasPrefix(tempDir, "~") {
123-
tempDir, err := execext.Expand(tempDir)
123+
tempDir, err := execext.ExpandLiteral(tempDir)
124124
if err != nil {
125125
return err
126126
}
@@ -141,7 +141,7 @@ func (e *Executor) setupTempDir() error {
141141
remoteDir := env.GetTaskEnv("REMOTE_DIR")
142142
if remoteDir != "" {
143143
if filepath.IsAbs(remoteDir) || strings.HasPrefix(remoteDir, "~") {
144-
remoteTempDir, err := execext.Expand(remoteDir)
144+
remoteTempDir, err := execext.ExpandLiteral(remoteDir)
145145
if err != nil {
146146
return err
147147
}

taskfile/node_file.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
8484
return entrypoint, nil
8585
}
8686

87-
path, err := execext.Expand(entrypoint)
87+
path, err := execext.ExpandLiteral(entrypoint)
8888
if err != nil {
8989
return "", err
9090
}
@@ -100,7 +100,7 @@ func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
100100
}
101101

102102
func (node *FileNode) ResolveDir(dir string) (string, error) {
103-
path, err := execext.Expand(dir)
103+
path, err := execext.ExpandLiteral(dir)
104104
if err != nil {
105105
return "", err
106106
}

taskfile/node_git.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
106106
}
107107

108108
func (node *GitNode) ResolveDir(dir string) (string, error) {
109-
path, err := execext.Expand(dir)
109+
path, err := execext.ExpandLiteral(dir)
110110
if err != nil {
111111
return "", err
112112
}

taskfile/node_http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (node *HTTPNode) ResolveEntrypoint(entrypoint string) (string, error) {
9797
}
9898

9999
func (node *HTTPNode) ResolveDir(dir string) (string, error) {
100-
path, err := execext.Expand(dir)
100+
path, err := execext.ExpandLiteral(dir)
101101
if err != nil {
102102
return "", err
103103
}

taskfile/node_stdin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (node *StdinNode) ResolveEntrypoint(entrypoint string) (string, error) {
4848
return entrypoint, nil
4949
}
5050

51-
path, err := execext.Expand(entrypoint)
51+
path, err := execext.ExpandLiteral(entrypoint)
5252
if err != nil {
5353
return "", err
5454
}
@@ -61,7 +61,7 @@ func (node *StdinNode) ResolveEntrypoint(entrypoint string) (string, error) {
6161
}
6262

6363
func (node *StdinNode) ResolveDir(dir string) (string, error) {
64-
path, err := execext.Expand(dir)
64+
path, err := execext.ExpandLiteral(dir)
6565
if err != nil {
6666
return "", err
6767
}

variables.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
7777
Watch: origTask.Watch,
7878
Namespace: origTask.Namespace,
7979
}
80-
new.Dir, err = execext.Expand(new.Dir)
80+
new.Dir, err = execext.ExpandLiteral(new.Dir)
8181
if err != nil {
8282
return nil, err
8383
}

0 commit comments

Comments
 (0)