Skip to content

Commit

Permalink
Accept any --feild=value flags!
Browse files Browse the repository at this point in the history
  • Loading branch information
fujiwara committed Jul 4, 2024
1 parent 83353fb commit 53c69c3
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 21 deletions.
21 changes: 10 additions & 11 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"testing"

"github.com/alecthomas/kong"
sdkclient "github.com/fujiwara/awslim"
)

Expand Down Expand Up @@ -160,17 +158,23 @@ var TestCases = []TestCase{
Env: map[string]string{},
IsError: true,
},
{
Name: "call baz#Client.Echo with dynamic flags",
Args: []string{"baz", "Echo", "--foo-Foo", "FOO", `{Baz:"baz"}`, "-c", "--bar=BAR"},
Expect: `{"Bar":"BAR","Baz":"baz","FooFoo":"FOO"}`,
},
}

func TestRun(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", "testdata") // don't use real config
for _, tc := range TestCases {
ctx := context.Background()
t.Run(tc.Name, func(t *testing.T) {
for k, v := range tc.Env {
t.Setenv(k, v)
}
buf := &bytes.Buffer{}
c, err := newCLI(tc.Args, buf)
c, err := newCLI(ctx, tc.Args, buf)
if err != nil {
t.Fatal(err)
}
Expand All @@ -190,16 +194,11 @@ func TestRun(t *testing.T) {
}
}

func newCLI(args []string, w io.Writer) (*sdkclient.CLI, error) {
c := &sdkclient.CLI{}
c.SetWriter(w)
p, err := kong.New(c)
if err != nil {
return nil, err
}
_, err = p.Parse(args)
func newCLI(ctx context.Context, args []string, out *bytes.Buffer) (*sdkclient.CLI, error) {
c, err := sdkclient.NewCLI(ctx, args)
if err != nil {
return nil, err
}
c.SetWriter(out)
return c, nil
}
57 changes: 57 additions & 0 deletions flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package sdkclient

import (
"fmt"
"strings"

"github.com/alecthomas/kong"
)

func flagExists(k *kong.Kong, flagName string) bool {
for _, flagSet := range k.Model.AllFlags(false) {
for _, f := range flagSet {
if f.Name == flagName {
return true
}
}
}
return false
}

func parseDynamicFlags(k *kong.Kong, args []string, convert func(string) string) ([]string, map[string]any, error) {
if convert == nil {
convert = func(s string) string { return s }
}
dynamicFlags := make(map[string]any)
rArgs := make([]string, 0, len(args))
for i := 0; i < len(args); i++ {
arg := args[i]
if arg == "--" {
break
}
if !strings.HasPrefix(arg, "--") {
rArgs = append(rArgs, arg)
continue
}
parts := strings.SplitN(arg, "=", 2)
name := strings.TrimPrefix(parts[0], "--")
if flagExists(k, name) {
rArgs = append(rArgs, arg)
continue
}
if len(parts) == 2 {
// --flag=value
dynamicFlags[convert(name)] = parts[1]
} else {
// --flag value
// read next arg as value
if i+1 < len(args) {
dynamicFlags[convert(name)] = args[i+1]
i++
} else {
return nil, nil, fmt.Errorf("flag %s requires a value", arg)
}
}
}
return rArgs, dynamicFlags, nil
}
38 changes: 28 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type CLI struct {
Service string `arg:"" help:"service name" default:""`
Method string `arg:"" help:"method name" default:""`
Input string `arg:"" help:"input JSON/Jsonnet struct or filename" default:"{}"`
Args []string `arg:"" optional:"" help:"additional arguments"`
Args []string `arg:"" optional:"" help:"additional flags/args"`

InputStream string `short:"i" help:"bind input filename or '-' to io.Reader field in the input struct"`
OutputStream string `short:"o" help:"bind output filename or '-' to io.ReadCloser field in the output struct"`
Expand All @@ -57,8 +57,9 @@ type CLI struct {
Version bool `short:"v" help:"show version"`
Debug bool `help:"turn on debug logging"`

w io.Writer
rc *RuntimeConfig
w io.Writer
rc *RuntimeConfig
dynamicFlags map[string]any
}

func enableDebug(args []string) {
Expand All @@ -71,32 +72,45 @@ func enableDebug(args []string) {
}

func Run(ctx context.Context) error {
c, err := NewCLI(ctx, os.Args[1:])
if err != nil {
return err
}
return c.Dispatch(ctx)
}

func NewCLI(ctx context.Context, args []string) (*CLI, error) {
enableDebug(os.Args[1:])
var c CLI

if rc, err := loadRuntimeConfig(); err != nil {
return fmt.Errorf("failed to load runtime config: %w", err)
return nil, fmt.Errorf("failed to load runtime config: %w", err)
} else {
c.rc = rc
}
slog.Debug("runtime config", "config", c.rc)

c.w = os.Stdout
args, err := c.resolveAliases(os.Args[1:])
args, err := c.resolveAliases(args)
if err != nil {
return err
return nil, err
}
slog.Debug("resolved args", "args", args)

k, err := kong.New(&c, kong.Vars{"version": Version})
if err != nil {
return err
return nil, err
}
args, c.dynamicFlags, err = parseDynamicFlags(k, args, kebabToPascal)
if err != nil {
return nil, err
}
if _, err := k.Parse(args); err != nil {
return err
return nil, err
}
slog.Debug("extra args", "args", c.Args)
slog.Debug("extra args", "args", c.Args, "dynamicFlags", c.dynamicFlags)

return c.Dispatch(ctx)
return &c, nil
}

func (c *CLI) Dispatch(ctx context.Context) error {
Expand Down Expand Up @@ -304,6 +318,10 @@ func (c *CLI) clientMethodParam(ctx context.Context) (*clientMethodParam, error)
p.cleanup = append(p.cleanup, f.Close)
}

if err := p.InjectMap(c.dynamicFlags); err != nil {
return nil, err
}

return p, nil
}

Expand Down
16 changes: 16 additions & 0 deletions param.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ func (p *clientMethodParam) Validate(name, inputReaderField, outputReadCloserFie
return nil
}

func (p *clientMethodParam) InjectMap(in map[string]any) error {
v := make(map[string]any)
if err := json.Unmarshal(p.InputBytes, &v); err != nil {
return fmt.Errorf("failed to unmarshal %s: %w", p.InputBytes, err)
}
for field, value := range in {
v[field] = value
}
if b, err := json.Marshal(v); err != nil {
return fmt.Errorf("failed to marshal %v: %w", v, err)
} else {
p.InputBytes = b
}
return nil
}

func (p *clientMethodParam) Inject(field string, value any) error {
v := make(map[string]any)
if err := json.Unmarshal(p.InputBytes, &v); err != nil {
Expand Down

0 comments on commit 53c69c3

Please sign in to comment.