mirror of
https://github.com/go-task/task.git
synced 2025-08-10 22:42:19 +02:00
feat: support for loops with generates (#2151)
This commit is contained in:
@@ -759,6 +759,8 @@ func TestForCmds(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{name: "loop-sources"},
|
{name: "loop-sources"},
|
||||||
{name: "loop-sources-glob"},
|
{name: "loop-sources-glob"},
|
||||||
|
{name: "loop-generates"},
|
||||||
|
{name: "loop-generates-glob"},
|
||||||
{name: "loop-vars"},
|
{name: "loop-vars"},
|
||||||
{name: "loop-vars-sh"},
|
{name: "loop-vars-sh"},
|
||||||
{name: "loop-task"},
|
{name: "loop-task"},
|
||||||
@@ -800,6 +802,8 @@ func TestForDeps(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{name: "loop-sources"},
|
{name: "loop-sources"},
|
||||||
{name: "loop-sources-glob"},
|
{name: "loop-sources-glob"},
|
||||||
|
{name: "loop-generates"},
|
||||||
|
{name: "loop-generates-glob"},
|
||||||
{name: "loop-vars"},
|
{name: "loop-vars"},
|
||||||
{name: "loop-vars-sh"},
|
{name: "loop-vars-sh"},
|
||||||
{name: "loop-task"},
|
{name: "loop-task"},
|
||||||
|
17
testdata/for/cmds/Taskfile.yml
vendored
17
testdata/for/cmds/Taskfile.yml
vendored
@@ -57,6 +57,23 @@ tasks:
|
|||||||
- for: sources
|
- for: sources
|
||||||
cmd: cat "{{.ITEM}}"
|
cmd: cat "{{.ITEM}}"
|
||||||
|
|
||||||
|
# Loop over the task's generates
|
||||||
|
loop-generates:
|
||||||
|
generates:
|
||||||
|
- foo.txt
|
||||||
|
- bar.txt
|
||||||
|
cmds:
|
||||||
|
- for: generates
|
||||||
|
cmd: cat "{{.ITEM}}"
|
||||||
|
|
||||||
|
# Loop over the task's generates when globbed
|
||||||
|
loop-generates-glob:
|
||||||
|
generates:
|
||||||
|
- "*.txt"
|
||||||
|
cmds:
|
||||||
|
- for: generates
|
||||||
|
cmd: cat "{{.ITEM}}"
|
||||||
|
|
||||||
# Loop over the contents of a variable
|
# Loop over the contents of a variable
|
||||||
loop-vars:
|
loop-vars:
|
||||||
vars:
|
vars:
|
||||||
|
2
testdata/for/cmds/testdata/TestForCmds-loop-generates-glob.golden
vendored
Normal file
2
testdata/for/cmds/testdata/TestForCmds-loop-generates-glob.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bar
|
||||||
|
foo
|
2
testdata/for/cmds/testdata/TestForCmds-loop-generates.golden
vendored
Normal file
2
testdata/for/cmds/testdata/TestForCmds-loop-generates.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bar
|
||||||
|
foo
|
21
testdata/for/deps/Taskfile.yml
vendored
21
testdata/for/deps/Taskfile.yml
vendored
@@ -69,6 +69,27 @@ tasks:
|
|||||||
vars:
|
vars:
|
||||||
FILE: "{{.ITEM}}"
|
FILE: "{{.ITEM}}"
|
||||||
|
|
||||||
|
# Loop over the task's generates
|
||||||
|
loop-generates:
|
||||||
|
generates:
|
||||||
|
- foo.txt
|
||||||
|
- bar.txt
|
||||||
|
deps:
|
||||||
|
- for: generates
|
||||||
|
task: cat
|
||||||
|
vars:
|
||||||
|
FILE: "{{.ITEM}}"
|
||||||
|
|
||||||
|
# Loop over the task's generates when globbed
|
||||||
|
loop-generates-glob:
|
||||||
|
generates:
|
||||||
|
- "*.txt"
|
||||||
|
deps:
|
||||||
|
- for: generates
|
||||||
|
task: cat
|
||||||
|
vars:
|
||||||
|
FILE: "{{.ITEM}}"
|
||||||
|
|
||||||
# Loop over the contents of a variable
|
# Loop over the contents of a variable
|
||||||
loop-vars:
|
loop-vars:
|
||||||
vars:
|
vars:
|
||||||
|
2
testdata/for/deps/testdata/TestForDeps-loop-generates-glob.golden
vendored
Normal file
2
testdata/for/deps/testdata/TestForDeps-loop-generates-glob.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bar
|
||||||
|
foo
|
2
testdata/for/deps/testdata/TestForDeps-loop-generates.golden
vendored
Normal file
2
testdata/for/deps/testdata/TestForDeps-loop-generates.golden
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bar
|
||||||
|
foo
|
19
variables.go
19
variables.go
@@ -153,7 +153,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cmd.For != nil {
|
if cmd.For != nil {
|
||||||
list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, vars, origTask.Location, cache)
|
list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, new.Generates, vars, origTask.Location, cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if dep.For != nil {
|
if dep.For != nil {
|
||||||
list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, vars, origTask.Location, cache)
|
list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, new.Generates, vars, origTask.Location, cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -270,6 +270,7 @@ func itemsFromFor(
|
|||||||
f *ast.For,
|
f *ast.For,
|
||||||
dir string,
|
dir string,
|
||||||
sources []*ast.Glob,
|
sources []*ast.Glob,
|
||||||
|
generates []*ast.Glob,
|
||||||
vars *ast.Vars,
|
vars *ast.Vars,
|
||||||
location *ast.Location,
|
location *ast.Location,
|
||||||
cache *templater.Cache,
|
cache *templater.Cache,
|
||||||
@@ -304,6 +305,20 @@ func itemsFromFor(
|
|||||||
}
|
}
|
||||||
values = asAnySlice(glist)
|
values = asAnySlice(glist)
|
||||||
}
|
}
|
||||||
|
// Get the list from the task generates
|
||||||
|
if f.From == "generates" {
|
||||||
|
glist, err := fingerprint.Globs(dir, generates)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// Make the paths relative to the task dir
|
||||||
|
for i, v := range glist {
|
||||||
|
if glist[i], err = filepath.Rel(dir, v); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values = asAnySlice(glist)
|
||||||
|
}
|
||||||
// Get the list from a variable and split it up
|
// Get the list from a variable and split it up
|
||||||
if f.Var != "" {
|
if f.Var != "" {
|
||||||
if vars != nil {
|
if vars != nil {
|
||||||
|
@@ -199,6 +199,9 @@ it is defined as a string, you can give it any of the following values:
|
|||||||
- `sources` - Will run the command for each source file defined on the task.
|
- `sources` - Will run the command for each source file defined on the task.
|
||||||
(Glob patterns will be resolved, so `*.go` will run for every Go file that
|
(Glob patterns will be resolved, so `*.go` will run for every Go file that
|
||||||
matches).
|
matches).
|
||||||
|
- `generates` - Will run the command for each file defined in the task's generates
|
||||||
|
list. (Glob patterns will be resolved, so `*.txt` will run for every text file
|
||||||
|
that matches).
|
||||||
|
|
||||||
If it is defined as a list of strings, the command will be run for each value.
|
If it is defined as a list of strings, the command will be run for each value.
|
||||||
|
|
||||||
|
@@ -1483,6 +1483,48 @@ tasks:
|
|||||||
cmd: cat {{joinPath .MY_DIR .ITEM}}
|
cmd: cat {{joinPath .MY_DIR .ITEM}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Looping over your task's generates
|
||||||
|
|
||||||
|
Similar to sources, you can also loop over the generates of your task:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
generates:
|
||||||
|
- foo.txt
|
||||||
|
- bar.txt
|
||||||
|
cmds:
|
||||||
|
- for: generates
|
||||||
|
cmd: cat {{ .ITEM }}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will also work if you use globbing syntax in your generates. For example, if
|
||||||
|
you specify a generate for `*.txt`, the loop will iterate over all files that
|
||||||
|
match that glob.
|
||||||
|
|
||||||
|
Generate paths will always be returned as paths relative to the task directory. If
|
||||||
|
you need to convert this to an absolute path, you can use the built-in
|
||||||
|
`joinPath` function. There are some [special variables](/reference/templating/#special-variables)
|
||||||
|
that you may find useful for this.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
vars:
|
||||||
|
MY_DIR: /path/to/dir
|
||||||
|
dir: '{{.MY_DIR}}'
|
||||||
|
generates:
|
||||||
|
- foo.txt
|
||||||
|
- bar.txt
|
||||||
|
cmds:
|
||||||
|
- for: generates
|
||||||
|
cmd: cat {{joinPath .MY_DIR .ITEM}}
|
||||||
|
```
|
||||||
|
|
||||||
### Looping over variables
|
### Looping over variables
|
||||||
|
|
||||||
To loop over the contents of a variable, you simply need to specify the variable
|
To loop over the contents of a variable, you simply need to specify the variable
|
||||||
|
@@ -475,7 +475,7 @@
|
|||||||
"for_attribute": {
|
"for_attribute": {
|
||||||
"description": "The task attribute to iterate over",
|
"description": "The task attribute to iterate over",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["sources"]
|
"enum": ["sources", "generates"]
|
||||||
},
|
},
|
||||||
"for_var": {
|
"for_var": {
|
||||||
"description": "Which variables to iterate over. The variable will be split using any whitespace character by default. This can be changed by using the `split` attribute.",
|
"description": "Which variables to iterate over. The variable will be split using any whitespace character by default. This can be changed by using the `split` attribute.",
|
||||||
|
Reference in New Issue
Block a user