diff --git a/executor_test.go b/executor_test.go index 3f4220ab..a79845cb 100644 --- a/executor_test.go +++ b/executor_test.go @@ -759,6 +759,8 @@ func TestForCmds(t *testing.T) { }, {name: "loop-sources"}, {name: "loop-sources-glob"}, + {name: "loop-generates"}, + {name: "loop-generates-glob"}, {name: "loop-vars"}, {name: "loop-vars-sh"}, {name: "loop-task"}, @@ -800,6 +802,8 @@ func TestForDeps(t *testing.T) { }, {name: "loop-sources"}, {name: "loop-sources-glob"}, + {name: "loop-generates"}, + {name: "loop-generates-glob"}, {name: "loop-vars"}, {name: "loop-vars-sh"}, {name: "loop-task"}, diff --git a/testdata/for/cmds/Taskfile.yml b/testdata/for/cmds/Taskfile.yml index a4196a96..e9a95234 100644 --- a/testdata/for/cmds/Taskfile.yml +++ b/testdata/for/cmds/Taskfile.yml @@ -57,6 +57,23 @@ tasks: - for: sources 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-vars: vars: diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-generates-glob.golden b/testdata/for/cmds/testdata/TestForCmds-loop-generates-glob.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-generates-glob.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-generates.golden b/testdata/for/cmds/testdata/TestForCmds-loop-generates.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-generates.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/Taskfile.yml b/testdata/for/deps/Taskfile.yml index 002ef38c..66567cc6 100644 --- a/testdata/for/deps/Taskfile.yml +++ b/testdata/for/deps/Taskfile.yml @@ -69,6 +69,27 @@ tasks: vars: 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-vars: vars: diff --git a/testdata/for/deps/testdata/TestForDeps-loop-generates-glob.golden b/testdata/for/deps/testdata/TestForDeps-loop-generates-glob.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-generates-glob.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-generates.golden b/testdata/for/deps/testdata/TestForDeps-loop-generates.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-generates.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/variables.go b/variables.go index c99ea3c1..ba108b02 100644 --- a/variables.go +++ b/variables.go @@ -153,7 +153,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err continue } 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 { return nil, err } @@ -200,7 +200,7 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err continue } 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 { return nil, err } @@ -270,6 +270,7 @@ func itemsFromFor( f *ast.For, dir string, sources []*ast.Glob, + generates []*ast.Glob, vars *ast.Vars, location *ast.Location, cache *templater.Cache, @@ -304,6 +305,20 @@ func itemsFromFor( } 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 if f.Var != "" { if vars != nil { diff --git a/website/docs/reference/schema.mdx b/website/docs/reference/schema.mdx index 29050e75..f426e3fa 100644 --- a/website/docs/reference/schema.mdx +++ b/website/docs/reference/schema.mdx @@ -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. (Glob patterns will be resolved, so `*.go` will run for every Go file that 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. diff --git a/website/docs/usage.mdx b/website/docs/usage.mdx index 6c480902..3def7114 100644 --- a/website/docs/usage.mdx +++ b/website/docs/usage.mdx @@ -1483,6 +1483,48 @@ tasks: 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 To loop over the contents of a variable, you simply need to specify the variable diff --git a/website/static/schema.json b/website/static/schema.json index 1aaeaa90..0a942697 100644 --- a/website/static/schema.json +++ b/website/static/schema.json @@ -475,7 +475,7 @@ "for_attribute": { "description": "The task attribute to iterate over", "type": "string", - "enum": ["sources"] + "enum": ["sources", "generates"] }, "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.",