Skip to content

Commit

Permalink
Merge pull request #170 from lets-cli/fix-ref-args
Browse files Browse the repository at this point in the history
Fix ref args
  • Loading branch information
kindermax authored Feb 16, 2022
2 parents ff6b775 + ccf964f commit f146ff6
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 55 deletions.
6 changes: 2 additions & 4 deletions cmd/subcommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,11 @@ func newCmdGeneric(command config.Command, conf *config.Config, out io.Writer) *
1,
)

commandToRun := command
if command.Ref != "" {
refCmd := command
commandToRun = conf.Commands[refCmd.Ref].FromRef(refCmd, conf)
command = conf.Commands[command.Ref].FromRef(command)
}

return runner.NewRunner(&commandToRun, conf, out).Execute(cmd.Context())
return runner.NewRunner(&command, conf, out).Execute(cmd.Context())
},
// we use docopt to parse flags on our own, so any flag is valid flag here
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Expand Down
17 changes: 4 additions & 13 deletions config/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"strings"

"github.com/lets-cli/lets/checksum"
)
Expand Down Expand Up @@ -59,7 +57,7 @@ type Command struct {
// ref is basically a command name to use with predefined args, env
Ref string
// can be specified only with ref
RefArgs string
RefArgs []string
}

// NewCommand creates new command struct.
Expand All @@ -78,20 +76,13 @@ func (cmd Command) WithArgs(args []string) Command {
return newCmd
}

func (cmd Command) FromRef(refCommand Command, cfg *Config) Command {
func (cmd Command) FromRef(refCommand Command) Command {
newCmd := cmd

// we have to expand env here on our own, since this args not came from users tty, and not expanded before lets
refArgsRaw := os.Expand(refCommand.RefArgs, func(key string) string {
return cfg.Env[key]
})

refArgs := strings.Split(refArgsRaw, " ")

if len(newCmd.Args) == 0 {
newCmd.Args = append([]string{cmd.Name}, refArgs...)
newCmd.Args = append([]string{cmd.Name}, refCommand.RefArgs...)
} else {
newCmd.Args = append(newCmd.Args, refArgs...)
newCmd.Args = append(newCmd.Args, refCommand.RefArgs...)
}

newCmd.CommandArgs = newCmd.Args[1:]
Expand Down
41 changes: 36 additions & 5 deletions config/parser/args.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
package parser

import (
"fmt"
"os"

"github.com/kballard/go-shellquote"
"github.com/lets-cli/lets/config/config"
)

func parseArgs(rawArgs interface{}, newCmd *config.Command) error {
args, ok := rawArgs.(string)
if !ok {
switch args := rawArgs.(type) {
case string:
argsList, err := shellquote.Split(args)
if err != nil {
return parseError(
"can not parse into args list",
newCmd.Name,
ARGS,
err.Error(),
)
}

newCmd.RefArgs = argsList
case []string:
newCmd.RefArgs = args
case []interface{}:
for _, arg := range args {
newCmd.RefArgs = append(newCmd.RefArgs, fmt.Sprintf("%s", arg))
}
default:
return parseError(
"must be a string",
"must be a string or a list of string",
newCmd.Name,
ARGS,
"",
)
}

newCmd.RefArgs = args

return nil
}

func postprocessRefArgs(cfg *config.Config) {
for _, cmd := range cfg.Commands {
for idx, arg := range cmd.RefArgs {
// we have to expand env here on our own, since this args not came from users tty, and not expanded before lets
cmd.RefArgs[idx] = os.Expand(arg, func(key string) string {
return cfg.Env[key]
})
}
}
}
42 changes: 22 additions & 20 deletions config/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,6 @@ func newConfigParseError(msg string, name string, field string) error {
}

func parseConfigGeneral(rawKeyValue map[string]interface{}, cfg *config.Config) error {
if cmds, ok := rawKeyValue[config.COMMANDS]; ok {
cmdsMap, ok := cmds.(map[string]interface{})
if !ok {
return newConfigParseError(
"must be a mapping",
config.COMMANDS,
"",
)
}

commands, err := parseCommands(cmdsMap, cfg)
if err != nil {
return err
}

for _, c := range commands {
cfg.Commands[c.Name] = c
}
}

rawEnv := make(map[string]interface{})

if env, ok := rawKeyValue[ENV]; ok {
Expand Down Expand Up @@ -123,6 +103,26 @@ func parseConfigGeneral(rawKeyValue map[string]interface{}, cfg *config.Config)
}
}

if cmds, ok := rawKeyValue[config.COMMANDS]; ok {
cmdsMap, ok := cmds.(map[string]interface{})
if !ok {
return newConfigParseError(
"must be a mapping",
config.COMMANDS,
"",
)
}

commands, err := parseCommands(cmdsMap, cfg)
if err != nil {
return err
}

for _, c := range commands {
cfg.Commands[c.Name] = c
}
}

return nil
}

Expand Down Expand Up @@ -176,6 +176,8 @@ func parseConfig(rawKeyValue map[string]interface{}, cfg *config.Config) error {
}
}

postprocessRefArgs(cfg)

return nil
}

Expand Down
4 changes: 4 additions & 0 deletions docs/docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ title: Changelog

## [Unreleased]

## [0.0.45]

* `[Fixed]` **`Breaking change`** Fix duplicate files for checksum.
This will change checksum output if the same file has been read multiple times.
* `[Fixed]` Fix parsing for ref args when declared as string.
* `[Added]` ref `args` can be a list of string

## [0.0.44](https://github.com/lets-cli/lets/releases/tag/v0.0.44)

Expand Down
16 changes: 10 additions & 6 deletions docs/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -700,19 +700,23 @@ Now:

```yaml
commands:
ls:
cmd: [ls]
hello:
cmd: echo Hello $@
ls-table:
ref: ls
args: -l
hello-world:
ref: hello
args: World
hello-by-name:
ref: hello
args: [Dear, Friend]
```

### `args`

`key: args`

`type: string`
`type: string or list of string`

**`Experimental feature`**

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/juju/errors v0.0.0-20200330140219-3fe23663418f // indirect
github.com/juju/testing v0.0.0-20201216035041-2be42bba85f3 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CIm
github.com/juju/version v0.0.0-20191219164919-81c1be00b9a6/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
github.com/julienschmidt/httprouter v1.1.1-0.20151013225520-77a895ad01eb/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down
13 changes: 6 additions & 7 deletions runner/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,10 @@ func NewRunner(cmd *config.Command, cfg *config.Config, out io.Writer) *Runner {
}

func NewChildRunner(cmd *config.Command, parentRunner *Runner) *Runner {
cfg := parentRunner.cfg
if cmd.Ref != "" {
newCmd := cfg.Commands[cmd.Ref].FromRef(*cmd, cfg)
cmd = &newCmd
}

return &Runner{
cmd: cmd,
parentCmd: parentRunner.cmd,
cfg: cfg,
cfg: parentRunner.cfg,
out: parentRunner.out,
}
}
Expand Down Expand Up @@ -337,6 +331,11 @@ func (r *Runner) runDepends(ctx context.Context) error {
if len(dep.Env) != 0 {
dependCmd = dependCmd.WithEnv(dep.Env)
}

if dependCmd.Ref != "" {
dependCmd = r.cfg.Commands[dependCmd.Ref].FromRef(dependCmd)
}

err := NewChildRunner(&dependCmd, r).Execute(ctx)
if err != nil {
// must return error to root
Expand Down
6 changes: 6 additions & 0 deletions tests/command_ref.bats
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ setup() {
assert_success
assert_line --index 0 "Hello World"
}

@test "command ref: run existing command with args as list from ref" {
run lets hello-list
assert_success
assert_line --index 0 "Hello Fellow friend"
}
4 changes: 4 additions & 0 deletions tests/command_ref/lets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ commands:
hello-world:
ref: hello
args: World

hello-list:
ref: hello
args: [Fellow, friend]

0 comments on commit f146ff6

Please sign in to comment.