mirror of
https://github.com/go-task/task.git
synced 2025-06-17 00:17:51 +02:00
Add support for delegating CLI arguments with "--" and a special CLI_ARGS variable
Closes #327
This commit is contained in:
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Add support for delegating CLI arguments to commands with `--` and a
|
||||||
|
special `CLI_ARGS` variable
|
||||||
|
([#327](https://github.com/go-task/task/issues/327)).
|
||||||
- Add a `--concurrency` (alias `-C`) flag, to limit the number of tasks that
|
- Add a `--concurrency` (alias `-C`) flag, to limit the number of tasks that
|
||||||
run concurrently. This is useful for heavy workloads.
|
run concurrently. This is useful for heavy workloads.
|
||||||
([#345](https://github.com/go-task/task/pull/345)).
|
([#345](https://github.com/go-task/task/pull/345)).
|
||||||
|
10
args/args.go
10
args/args.go
@ -9,7 +9,7 @@ import (
|
|||||||
// ParseV3 parses command line argument: tasks and global variables
|
// ParseV3 parses command line argument: tasks and global variables
|
||||||
func ParseV3(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
func ParseV3(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
||||||
var calls []taskfile.Call
|
var calls []taskfile.Call
|
||||||
var globals *taskfile.Vars
|
var globals = &taskfile.Vars{}
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if !strings.Contains(arg, "=") {
|
if !strings.Contains(arg, "=") {
|
||||||
@ -17,9 +17,6 @@ func ParseV3(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if globals == nil {
|
|
||||||
globals = &taskfile.Vars{}
|
|
||||||
}
|
|
||||||
name, value := splitVar(arg)
|
name, value := splitVar(arg)
|
||||||
globals.Set(name, taskfile.Var{Static: value})
|
globals.Set(name, taskfile.Var{Static: value})
|
||||||
}
|
}
|
||||||
@ -34,7 +31,7 @@ func ParseV3(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
|||||||
// ParseV2 parses command line argument: tasks and vars of each task
|
// ParseV2 parses command line argument: tasks and vars of each task
|
||||||
func ParseV2(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
func ParseV2(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
||||||
var calls []taskfile.Call
|
var calls []taskfile.Call
|
||||||
var globals *taskfile.Vars
|
var globals = &taskfile.Vars{}
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if !strings.Contains(arg, "=") {
|
if !strings.Contains(arg, "=") {
|
||||||
@ -43,9 +40,6 @@ func ParseV2(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(calls) < 1 {
|
if len(calls) < 1 {
|
||||||
if globals == nil {
|
|
||||||
globals = &taskfile.Vars{}
|
|
||||||
}
|
|
||||||
name, value := splitVar(arg)
|
name, value := splitVar(arg)
|
||||||
globals.Set(name, taskfile.Var{Static: value})
|
globals.Set(name, taskfile.Var{Static: value})
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,7 +96,9 @@ func TestArgsV3(t *testing.T) {
|
|||||||
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
||||||
calls, globals := args.ParseV3(test.Args...)
|
calls, globals := args.ParseV3(test.Args...)
|
||||||
assert.Equal(t, test.ExpectedCalls, calls)
|
assert.Equal(t, test.ExpectedCalls, calls)
|
||||||
assert.Equal(t, test.ExpectedGlobals, globals)
|
if test.ExpectedGlobals.Len() > 0 || globals.Len() > 0 {
|
||||||
|
assert.Equal(t, test.ExpectedGlobals, globals)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,7 +200,10 @@ func TestArgsV2(t *testing.T) {
|
|||||||
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
||||||
calls, globals := args.ParseV2(test.Args...)
|
calls, globals := args.ParseV2(test.Args...)
|
||||||
assert.Equal(t, test.ExpectedCalls, calls)
|
assert.Equal(t, test.ExpectedCalls, calls)
|
||||||
assert.Equal(t, test.ExpectedGlobals, globals)
|
if test.ExpectedGlobals.Len() > 0 || globals.Len() > 0 {
|
||||||
|
assert.Equal(t, test.ExpectedGlobals, globals)
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
@ -157,14 +158,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
calls []taskfile.Call
|
calls []taskfile.Call
|
||||||
globals *taskfile.Vars
|
globals *taskfile.Vars
|
||||||
|
tasksAndVars, cliArgs = getArgs()
|
||||||
)
|
)
|
||||||
|
|
||||||
if v >= 3.0 {
|
if v >= 3.0 {
|
||||||
calls, globals = args.ParseV3(pflag.Args()...)
|
calls, globals = args.ParseV3(tasksAndVars...)
|
||||||
} else {
|
} else {
|
||||||
calls, globals = args.ParseV2(pflag.Args()...)
|
calls, globals = args.ParseV2(tasksAndVars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
globals.Set("CLI_ARGS", taskfile.Var{Static: strings.Join(cliArgs, " ")})
|
||||||
e.Taskfile.Vars.Merge(globals)
|
e.Taskfile.Vars.Merge(globals)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -185,6 +190,22 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getArgs() (tasksAndVars, cliArgs []string) {
|
||||||
|
var (
|
||||||
|
args = pflag.Args()
|
||||||
|
doubleDashPos = pflag.CommandLine.ArgsLenAtDash()
|
||||||
|
)
|
||||||
|
|
||||||
|
if doubleDashPos != -1 {
|
||||||
|
tasksAndVars = args[:doubleDashPos]
|
||||||
|
cliArgs = args[doubleDashPos:]
|
||||||
|
} else {
|
||||||
|
tasksAndVars = args
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func getSignalContext() context.Context {
|
func getSignalContext() context.Context {
|
||||||
ch := make(chan os.Signal, 1)
|
ch := make(chan os.Signal, 1)
|
||||||
signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
|
signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
|
@ -520,6 +520,27 @@ tasks:
|
|||||||
|
|
||||||
This works for all types of variables.
|
This works for all types of variables.
|
||||||
|
|
||||||
|
## Forwarding CLI arguments to commands
|
||||||
|
|
||||||
|
If `--` is given in the CLI, all following paramaters are added to a
|
||||||
|
special `.CLI_ARGS` variable. This is useful to forward arguments to another
|
||||||
|
command.
|
||||||
|
|
||||||
|
The below example will run `yarn install`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ task yarn -- install
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
yarn:
|
||||||
|
cmds:
|
||||||
|
- yarn {{.CLI_ARGS}}
|
||||||
|
```
|
||||||
|
|
||||||
## Go's template engine
|
## Go's template engine
|
||||||
|
|
||||||
Task parse commands as [Go's template engine][gotemplate] before executing
|
Task parse commands as [Go's template engine][gotemplate] before executing
|
||||||
|
@ -63,7 +63,7 @@ func (r *Templater) ReplaceSlice(strs []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Templater) ReplaceVars(vars *taskfile.Vars) *taskfile.Vars {
|
func (r *Templater) ReplaceVars(vars *taskfile.Vars) *taskfile.Vars {
|
||||||
if r.err != nil || vars == nil || len(vars.Keys) == 0 {
|
if r.err != nil || vars.Len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ func (vs *Vars) Range(yield func(key string, value Var) error) error {
|
|||||||
// ToCacheMap converts Vars to a map containing only the static
|
// ToCacheMap converts Vars to a map containing only the static
|
||||||
// variables
|
// variables
|
||||||
func (vs *Vars) ToCacheMap() (m map[string]interface{}) {
|
func (vs *Vars) ToCacheMap() (m map[string]interface{}) {
|
||||||
m = make(map[string]interface{}, len(vs.Keys))
|
m = make(map[string]interface{}, vs.Len())
|
||||||
vs.Range(func(k string, v Var) error {
|
vs.Range(func(k string, v Var) error {
|
||||||
if v.Sh != "" {
|
if v.Sh != "" {
|
||||||
// Dynamic variable is not yet resolved; trigger
|
// Dynamic variable is not yet resolved; trigger
|
||||||
@ -93,6 +93,14 @@ func (vs *Vars) ToCacheMap() (m map[string]interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the size of the map
|
||||||
|
func (vs *Vars) Len() int {
|
||||||
|
if vs == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(vs.Keys)
|
||||||
|
}
|
||||||
|
|
||||||
// Var represents either a static or dynamic variable.
|
// Var represents either a static or dynamic variable.
|
||||||
type Var struct {
|
type Var struct {
|
||||||
Static string
|
Static string
|
||||||
|
Reference in New Issue
Block a user