From 1954c3f7313a918a550311c031ff75780f90ec93 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 29 Jan 2021 17:16:22 -0800 Subject: [PATCH] dagger compute [--input-dir TARGET=DIR] [--input-string TARGET=STRING] [--input-cue CUE] [--input-git REMOTE#REF] Signed-off-by: Solomon Hykes --- README.md | 5 +- cmd/dagger/cmd/compute.go | 66 ++++++++--- dagger/client.go | 88 ++++++-------- dagger/compute.go | 5 +- dagger/env.go | 118 ++++++++++++++----- dagger/env_test.go | 71 +++++++++++ dagger/input.go | 239 ++++++++++++++++++++++++++++++++++++++ dagger/input_test.go | 35 ++++++ dagger/script.go | 11 ++ dagger/value.go | 8 +- examples/tests/test.sh | 6 +- go.mod | 1 + 12 files changed, 543 insertions(+), 110 deletions(-) create mode 100644 dagger/env_test.go create mode 100644 dagger/input.go create mode 100644 dagger/input_test.go diff --git a/README.md b/README.md index 9f8aa5cc..4e99dca9 100644 --- a/README.md +++ b/README.md @@ -93,10 +93,7 @@ which hide the complexity of `dagger compute` (but it will always be available t Here is an example command, using an example configuration: ``` -$ dagger compute \ - ./examples/simple \ - --input 'www: hostname: "www.mysuperapp.com"' \ - --input 'www: source: #dagger: compute: [{do:"fetch-git", remote:"https://github.com/samalba/hello-go", ref:"master"}]' +$ dagger compute ./examples/simple --input-string www.host=mysuperapp.com --input-dir www.source=. ``` diff --git a/cmd/dagger/cmd/compute.go b/cmd/dagger/cmd/compute.go index 87e96af0..ae539d68 100644 --- a/cmd/dagger/cmd/compute.go +++ b/cmd/dagger/cmd/compute.go @@ -12,6 +12,12 @@ import ( "github.com/spf13/viper" ) +var ( + env *dagger.Env + input *dagger.InputValue + updater *dagger.InputValue +) + var computeCmd = &cobra.Command{ Use: "compute CONFIG", Short: "Compute a configuration", @@ -27,17 +33,24 @@ var computeCmd = &cobra.Command{ lg := logger.New() ctx := lg.WithContext(appcontext.Context()) - c, err := dagger.NewClient(ctx, dagger.ClientConfig{ - Input: viper.GetString("input"), - Updater: localUpdater(args[0]), - }) + if err := updater.SourceFlag().Set(args[0]); err != nil { + lg.Fatal().Err(err).Msg("invalid local source") + } + + if err := env.SetUpdater(updater.Value()); err != nil { + lg.Fatal().Err(err).Msg("invalid updater script") + } + lg.Debug().Str("input", input.Value().SourceUnsafe()).Msg("Setting input") + if err := env.SetInput(input.Value()); err != nil { + lg.Fatal().Err(err).Msg("invalid input") + } + lg.Debug().Str("env state", env.State().SourceUnsafe()).Msg("creating client") + c, err := dagger.NewClient(ctx, "") if err != nil { lg.Fatal().Err(err).Msg("unable to create client") } - // FIXME: configure which config to compute (duh) - // FIXME: configure inputs lg.Info().Msg("running") - output, err := c.Compute(ctx) + output, err := c.Compute(ctx, env) if err != nil { lg.Fatal().Err(err).Msg("failed to compute") } @@ -46,18 +59,35 @@ var computeCmd = &cobra.Command{ }, } -func localUpdater(dir string) string { - return fmt.Sprintf(`[ - { - do: "local" - dir: "%s" - include: ["*.cue", "cue.mod"] - } - ]`, dir) -} - func init() { - computeCmd.Flags().String("input", "", "Input overlay") + // Why is this stuff here? + // 1. input must be global for flag parsing + // 2. updater must be global for flag parsing + // 3. env must have same compiler as input & updater, + // therefore it must be global too. + // + // FIXME: roll up InputValue into Env? + var err error + env, err = dagger.NewEnv() + if err != nil { + panic(err) + } + + // Setup --input-* flags + input, err = dagger.NewInputValue(env.Compiler(), "{}") + if err != nil { + panic(err) + } + computeCmd.Flags().Var(input.StringFlag(), "input-string", "TARGET=STRING") + computeCmd.Flags().Var(input.DirFlag(), "input-dir", "TARGET=PATH") + computeCmd.Flags().Var(input.GitFlag(), "input-git", "TARGET=REMOTE#REF") + computeCmd.Flags().Var(input.CueFlag(), "input-cue", "CUE") + + // Setup (future) --from-* flags + updater, err = dagger.NewInputValue(env.Compiler(), "[...{do:string, ...}]") + if err != nil { + panic(err) + } if err := viper.BindPFlags(computeCmd.Flags()); err != nil { panic(err) diff --git a/dagger/client.go b/dagger/client.go index 8110ff35..02267eb4 100644 --- a/dagger/client.go +++ b/dagger/client.go @@ -37,19 +37,26 @@ type Client struct { c *bk.Client localdirs map[string]string - cfg ClientConfig } -type ClientConfig struct { - // Buildkit host address, eg. `docker://buildkitd` - Host string - // Script to update the env config, eg . `[{do:"local",dir:"."}]` - Updater string - // Input values to merge on the base config, eg. `www: source: #dagger: compute: [{do:"local",dir:"./src"}]` - Input string +func NewClient(ctx context.Context, host string) (*Client, error) { + if host == "" { + host = os.Getenv("BUILDKIT_HOST") + } + if host == "" { + host = defaultBuildkitHost + } + c, err := bk.New(ctx, host) + if err != nil { + return nil, errors.Wrap(err, "buildkit client") + } + return &Client{ + c: c, + }, nil } -func NewClient(ctx context.Context, cfg ClientConfig) (result *Client, err error) { +// FIXME: return completed *Env, instead of *Value +func (c *Client) Compute(ctx context.Context, env *Env) (o *Value, err error) { lg := log.Ctx(ctx) defer func() { if err != nil { @@ -57,26 +64,11 @@ func NewClient(ctx context.Context, cfg ClientConfig) (result *Client, err error err = cueErr(err) } }() - // Load partial env client-side, to validate & scan local dirs - env, err := NewEnv(cfg.Updater) - if err != nil { - return nil, errors.Wrap(err, "updater") - } - if err := env.SetInput(cfg.Input); err != nil { - return nil, errors.Wrap(err, "input") - } + // Scan local dirs to grant access localdirs, err := env.LocalDirs(ctx) if err != nil { return nil, errors.Wrap(err, "scan local dirs") } - envsrc, err := env.state.SourceString() - if err != nil { - return nil, err - } - lg.Debug(). - Str("func", "NewClient"). - Str("env", envsrc). - Msg("loaded partial env client-side") for label, dir := range localdirs { abs, err := filepath.Abs(dir) if err != nil { @@ -84,32 +76,14 @@ func NewClient(ctx context.Context, cfg ClientConfig) (result *Client, err error } localdirs[label] = abs } - // Configure buildkit client - if cfg.Host == "" { - cfg.Host = os.Getenv("BUILDKIT_HOST") - } - if cfg.Host == "" { - cfg.Host = defaultBuildkitHost - } - c, err := bk.New(ctx, cfg.Host) - if err != nil { - return nil, errors.Wrap(err, "buildkit client") - } - return &Client{ - c: c, - cfg: cfg, - localdirs: localdirs, - }, nil -} + c.localdirs = localdirs -func (c *Client) Compute(ctx context.Context) (*Value, error) { - lg := log.Ctx(ctx) - - cc := &Compiler{} - out, err := cc.EmptyStruct() + // FIXME: merge this into env output. + out, err := env.Compiler().EmptyStruct() if err != nil { return nil, err } + // Spawn Build() goroutine eg, ctx := errgroup.WithContext(ctx) events := make(chan *bk.SolveStatus) @@ -118,7 +92,7 @@ func (c *Client) Compute(ctx context.Context) (*Value, error) { // Spawn build function eg.Go(func() error { defer outw.Close() - return c.buildfn(ctx, events, outw) + return c.buildfn(ctx, env, events, outw) }) // Spawn print function(s) @@ -154,19 +128,28 @@ func (c *Client) Compute(ctx context.Context) (*Value, error) { // Retrieve output eg.Go(func() error { defer outr.Close() - return c.outputfn(ctx, outr, out, cc) + return c.outputfn(ctx, outr, out, env.cc) }) return out, eg.Wait() } -func (c *Client) buildfn(ctx context.Context, ch chan *bk.SolveStatus, w io.WriteCloser) error { +func (c *Client) buildfn(ctx context.Context, env *Env, ch chan *bk.SolveStatus, w io.WriteCloser) error { lg := log.Ctx(ctx) + // Serialize input and updater + input, err := env.Input().SourceString() + if err != nil { + return errors.Wrap(err, "serialize env input") + } + updater, err := env.Updater().Value().SourceString() + if err != nil { + return errors.Wrap(err, "serialize updater script") + } // Setup solve options opts := bk.SolveOpt{ FrontendAttrs: map[string]string{ - bkInputKey: c.cfg.Input, - bkUpdaterKey: c.cfg.Updater, + bkInputKey: input, + bkUpdaterKey: updater, }, LocalDirs: c.localdirs, // FIXME: catch output & return as cue value @@ -183,7 +166,6 @@ func (c *Client) buildfn(ctx context.Context, ch chan *bk.SolveStatus, w io.Writ lg.Debug(). Interface("localdirs", opts.LocalDirs). Interface("attrs", opts.FrontendAttrs). - Interface("host", c.cfg.Host). Msg("spawning buildkit job") resp, err := c.c.Build(ctx, opts, "", Compute, ch) if err != nil { diff --git a/dagger/compute.go b/dagger/compute.go index 0823d83c..a8d30dec 100644 --- a/dagger/compute.go +++ b/dagger/compute.go @@ -27,10 +27,13 @@ func Compute(ctx context.Context, c bkgw.Client) (r *bkgw.Result, err error) { if o, exists := c.BuildOpts().Opts[bkUpdaterKey]; exists { updater = o } - env, err := NewEnv(updater) + env, err := NewEnv() if err != nil { return nil, err } + if err := env.SetUpdater(updater); err != nil { + return nil, err + } if err := env.Update(ctx, s); err != nil { return nil, err } diff --git a/dagger/env.go b/dagger/env.go index b8eb6ce0..c09f31aa 100644 --- a/dagger/env.go +++ b/dagger/env.go @@ -35,39 +35,82 @@ type Env struct { cc *Compiler } -func NewEnv(updater interface{}) (*Env, error) { - var ( - env = &Env{} - cc = &Compiler{} - err error - ) - // 1. Updater - if updater == nil { - updater = "[]" +func (env *Env) Updater() *Script { + return env.updater +} + +// Set the updater script for this environment. +// u may be: +// - A compiled script: *Script +// - A compiled value: *Value +// - A cue source: string, []byte, io.Reader +func (env *Env) SetUpdater(u interface{}) error { + if v, ok := u.(*Value); ok { + updater, err := NewScript(v) + if err != nil { + return errors.Wrap(err, "invalid updater script") + } + env.updater = updater + return nil } - env.updater, err = cc.CompileScript("updater", updater) + if updater, ok := u.(*Script); ok { + env.updater = updater + return nil + } + if u == nil { + u = "[]" + } + updater, err := env.cc.CompileScript("updater", u) if err != nil { - return nil, err + return err } - // 2. initialize empty values + env.updater = updater + return nil +} + +func NewEnv() (*Env, error) { + cc := &Compiler{} empty, err := cc.EmptyStruct() if err != nil { return nil, err } - env.input = empty - env.base = empty - env.state = empty - env.output = empty - // 3. compiler - env.cc = cc + env := &Env{ + cc: cc, + base: empty, + input: empty, + output: empty, + state: empty, + } + if err := env.SetUpdater(nil); err != nil { + return nil, err + } return env, nil } -func (env *Env) SetInput(src interface{}) error { - if src == nil { - src = "{}" +func (env *Env) Compiler() *Compiler { + return env.cc +} + +func (env *Env) State() *Value { + return env.state +} + +func (env *Env) Input() *Value { + return env.input +} + +func (env *Env) SetInput(i interface{}) error { + if input, ok := i.(*Value); ok { + return env.set( + env.base, + input, + env.output, + ) } - input, err := env.cc.Compile("input", src) + if i == nil { + i = "{}" + } + input, err := env.cc.Compile("input", i) if err != nil { return err } @@ -98,6 +141,14 @@ func (env *Env) Update(ctx context.Context, s Solver) error { ) } +func (env *Env) Base() *Value { + return env.base +} + +func (env *Env) Output() *Value { + return env.output +} + // Scan all scripts in the environment for references to local directories (do:"local"), // and return all referenced directory names. // This is used by clients to grant access to local directories when they are referenced @@ -105,8 +156,15 @@ func (env *Env) Update(ctx context.Context, s Solver) error { func (env *Env) LocalDirs(ctx context.Context) (map[string]string, error) { lg := log.Ctx(ctx) dirs := map[string]string{} + lg.Debug(). + Str("func", "Env.LocalDirs"). + Str("state", env.state.SourceUnsafe()). + Str("updater", env.updater.Value().SourceUnsafe()). + Msg("starting") + defer func() { + lg.Debug().Str("func", "Env.LocalDirs").Interface("result", dirs).Msg("done") + }() // 1. Walk env state, scan compute script for each component. - lg.Debug().Msg("walking env client-side for local dirs") _, err := env.Walk(ctx, func(ctx context.Context, c *Component, out *Fillable) error { lg.Debug(). Str("func", "Env.LocalDirs"). @@ -163,22 +221,24 @@ func (env *Env) Compute(ctx context.Context, s Solver) error { } // FIXME: this is just a 3-way merge. Add var args to Value.Merge. -func (env *Env) set(base, input, output *Value) error { +func (env *Env) set(base, input, output *Value) (err error) { // FIXME: make this cleaner in *Value by keeping intermediary instances // FIXME: state.CueInst() must return an instance with the same // contents as state.v, for the purposes of cueflow. // That is not currently how *Value works, so we prepare the cue // instance manually. // --> refactor the Value API to do this for us. - baseInst := base.CueInst() - inputInst := input.CueInst() - outputInst := output.CueInst() + stateInst := env.state.CueInst() - stateInst, err := baseInst.Fill(inputInst.Value()) + stateInst, err = stateInst.Fill(base.val) if err != nil { return errors.Wrap(err, "merge base & input") } - stateInst, err = stateInst.Fill(outputInst.Value()) + stateInst, err = stateInst.Fill(input.val) + if err != nil { + return errors.Wrap(err, "merge base & input") + } + stateInst, err = stateInst.Fill(output.val) if err != nil { return errors.Wrap(err, "merge output with base & input") } diff --git a/dagger/env_test.go b/dagger/env_test.go new file mode 100644 index 00000000..f22f943c --- /dev/null +++ b/dagger/env_test.go @@ -0,0 +1,71 @@ +package dagger + +import ( + "context" + "testing" +) + +func TestSimpleEnvSet(t *testing.T) { + env, err := NewEnv() + if err != nil { + t.Fatal(err) + } + if err := env.SetInput(`hello: "world"`); err != nil { + t.Fatal(err) + } + hello, err := env.State().Get("hello").String() + if err != nil { + t.Fatal(err) + } + if hello != "world" { + t.Fatal(hello) + } +} + +func TestSimpleEnvSetFromInputValue(t *testing.T) { + env, err := NewEnv() + if err != nil { + t.Fatal(err) + } + + v, err := env.Compiler().Compile("", `hello: "world"`) + if err != nil { + t.Fatal(err) + } + if err := env.SetInput(v); err != nil { + t.Fatal(err) + } + hello, err := env.State().Get("hello").String() + if err != nil { + t.Fatal(err) + } + if hello != "world" { + t.Fatal(hello) + } +} + +func TestEnvInputComponent(t *testing.T) { + env, err := NewEnv() + if err != nil { + t.Fatal(err) + } + + v, err := env.Compiler().Compile("", `foo: #dagger: compute: [{do:"local",dir:"."}]`) + if err != nil { + t.Fatal(err) + } + if err := env.SetInput(v); err != nil { + t.Fatal(err) + } + + localdirs, err := env.LocalDirs(context.TODO()) + if err != nil { + t.Fatal(err) + } + if len(localdirs) != 1 { + t.Fatal(localdirs) + } + if dir, ok := localdirs["."]; !ok || dir != "." { + t.Fatal(localdirs) + } +} diff --git a/dagger/input.go b/dagger/input.go new file mode 100644 index 00000000..b0bf1ba4 --- /dev/null +++ b/dagger/input.go @@ -0,0 +1,239 @@ +package dagger + +import ( + "encoding/json" + "fmt" + "net/url" + "strings" + + "cuelang.org/go/cue" + "github.com/spf13/pflag" +) + +// A mutable cue value with an API suitable for user inputs, +// such as command-line flag parsing. +type InputValue struct { + root *Value + cc *Compiler +} + +func (iv *InputValue) Value() *Value { + return iv.root +} + +func (iv *InputValue) String() string { + s, _ := iv.root.SourceString() + return s +} + +func NewInputValue(cc *Compiler, base interface{}) (*InputValue, error) { + root, err := cc.Compile("base", base) + if err != nil { + return nil, err + } + return &InputValue{ + cc: cc, + root: root, + }, nil +} + +func (iv *InputValue) Set(s string, enc func(string, *Compiler) (interface{}, error)) error { + // Split from eg. 'foo.bar={bla:"bla"}` + k, vRaw := splitkv(s) + v, err := enc(vRaw, iv.cc) + if err != nil { + return err + } + root, err := iv.root.MergePath(v, k) + if err != nil { + return err + } + iv.root = root + return nil +} + +// Adapter to receive string values from pflag +func (iv *InputValue) StringFlag() pflag.Value { + return stringFlag{ + iv: iv, + } +} + +type stringFlag struct { + iv *InputValue +} + +func (sf stringFlag) Set(s string) error { + return sf.iv.Set(s, func(s string, _ *Compiler) (interface{}, error) { + return s, nil + }) +} + +func (sf stringFlag) String() string { + return sf.iv.String() +} + +func (sf stringFlag) Type() string { + return "STRING" +} + +// DIR FLAG +// Receive a local directory path and translate it into a component +func (iv *InputValue) DirFlag(include ...string) pflag.Value { + if include == nil { + include = []string{} + } + return dirFlag{ + iv: iv, + include: include, + } +} + +type dirFlag struct { + iv *InputValue + include []string +} + +func (f dirFlag) Set(s string) error { + return f.iv.Set(s, func(s string, cc *Compiler) (interface{}, error) { + // FIXME: this is a hack because cue API can't merge into a list + include, err := json.Marshal(f.include) + if err != nil { + return nil, err + } + return cc.Compile("", fmt.Sprintf( + `#dagger: compute: [{do:"local",dir:"%s", include:%s}]`, + s, + include, + )) + }) +} + +func (f dirFlag) String() string { + return f.iv.String() +} + +func (f dirFlag) Type() string { + return "PATH" +} + +// GIT FLAG +// Receive a git repository reference and translate it into a component +func (iv *InputValue) GitFlag() pflag.Value { + return gitFlag{ + iv: iv, + } +} + +type gitFlag struct { + iv *InputValue +} + +func (f gitFlag) Set(s string) error { + return f.iv.Set(s, func(s string, cc *Compiler) (interface{}, error) { + u, err := url.Parse(s) + if err != nil { + return nil, fmt.Errorf("invalid git url") + } + ref := u.Fragment // eg. #main + u.Fragment = "" + remote := u.String() + + return cc.Compile("", fmt.Sprintf( + `#dagger: compute: [{do:"fetch-git", remote:"%s", ref:"%s"}]`, + remote, + ref, + )) + }) +} + +func (f gitFlag) String() string { + return f.iv.String() +} + +func (f gitFlag) Type() string { + return "REMOTE,REF" +} + +// SOURCE FLAG +// Adapter to receive a simple source description and translate it to a loader script. +// For example 'git+https://github.com/cuelang/cue#master` -> [{do:"git",remote:"https://github.com/cuelang/cue",ref:"master"}] + +func (iv *InputValue) SourceFlag() pflag.Value { + return sourceFlag{ + iv: iv, + } +} + +type sourceFlag struct { + iv *InputValue +} + +func (f sourceFlag) Set(s string) error { + return f.iv.Set(s, func(s string, cc *Compiler) (interface{}, error) { + u, err := url.Parse(s) + if err != nil { + return nil, err + } + switch u.Scheme { + case "", "file": + return cc.Compile( + "source", + // FIXME: include only cue files as a shortcut. Make this configurable somehow. + fmt.Sprintf(`[{do:"local",dir:"%s",include:["*.cue","cue.mod"]}]`, u.Host+u.Path), + ) + default: + return nil, fmt.Errorf("unsupported source scheme: %q", u.Scheme) + } + }) +} + +func (f sourceFlag) String() string { + return f.iv.String() +} + +func (f sourceFlag) Type() string { + return "PATH | file://PATH | git+ssh://HOST/PATH | git+https://HOST/PATH" +} + +// RAW CUE FLAG +// Adapter to receive raw cue values from pflag +func (iv *InputValue) CueFlag() pflag.Value { + return cueFlag{ + iv: iv, + } +} + +type cueFlag struct { + iv *InputValue +} + +func (f cueFlag) Set(s string) error { + return f.iv.Set(s, func(s string, cc *Compiler) (interface{}, error) { + return cc.Compile("cue input", s) + }) +} + +func (f cueFlag) String() string { + return f.iv.String() +} + +func (f cueFlag) Type() string { + return "CUE" +} + +// UTILITIES + +func splitkv(kv string) (cue.Path, string) { + parts := strings.SplitN(kv, "=", 2) + if len(parts) == 2 { + if parts[0] == "." || parts[0] == "" { + return cue.MakePath(), parts[1] + } + return cue.ParsePath(parts[0]), parts[1] + } + if len(parts) == 1 { + return cue.MakePath(), parts[0] + } + return cue.MakePath(), "" +} diff --git a/dagger/input_test.go b/dagger/input_test.go new file mode 100644 index 00000000..ce079b08 --- /dev/null +++ b/dagger/input_test.go @@ -0,0 +1,35 @@ +package dagger + +import ( + "context" + "testing" +) + +func TestEnvInputFlag(t *testing.T) { + env, err := NewEnv() + if err != nil { + t.Fatal(err) + } + + input, err := NewInputValue(env.Compiler(), `{}`) + if err != nil { + t.Fatal(err) + } + if err := input.DirFlag().Set("www.source=."); err != nil { + t.Fatal(err) + } + if err := env.SetInput(input.Value()); err != nil { + t.Fatal(err) + } + + localdirs, err := env.LocalDirs(context.TODO()) + if err != nil { + t.Fatal(err) + } + if len(localdirs) != 1 { + t.Fatal(localdirs) + } + if dir, ok := localdirs["."]; !ok || dir != "." { + t.Fatal(localdirs) + } +} diff --git a/dagger/script.go b/dagger/script.go index 93391662..3a198e59 100644 --- a/dagger/script.go +++ b/dagger/script.go @@ -101,6 +101,11 @@ func (s *Script) Walk(ctx context.Context, fn func(op *Op) error) error { } func (s *Script) LocalDirs(ctx context.Context) (map[string]string, error) { + lg := log.Ctx(ctx) + lg.Debug(). + Str("func", "Script.LocalDirs"). + Str("location", s.Value().Path().String()). + Msg("starting") dirs := map[string]string{} err := s.Walk(ctx, func(op *Op) error { if err := op.Validate("#Local"); err != nil { @@ -114,5 +119,11 @@ func (s *Script) LocalDirs(ctx context.Context) (map[string]string, error) { dirs[dir] = dir return nil }) + lg.Debug(). + Str("func", "Script.LocalDirs"). + Str("location", s.Value().Path().String()). + Interface("err", err). + Interface("result", dirs). + Msg("done") return dirs, err } diff --git a/dagger/value.go b/dagger/value.go index e936deb8..d2823650 100644 --- a/dagger/value.go +++ b/dagger/value.go @@ -32,8 +32,7 @@ func wrapValue(v cue.Value, inst *cue.Instance, cc *Compiler) *Value { } } -// Fill is a concurrency safe wrapper around cue.Value.Fill() -// This is the only method which changes the value in-place. +// Fill the value in-place, unlike Merge which returns a copy. func (v *Value) Fill(x interface{}) error { v.cc.Lock() defer v.cc.Unlock() @@ -96,6 +95,11 @@ func (v *Value) String() (string, error) { return v.val.String() } +func (v *Value) SourceUnsafe() string { + s, _ := v.SourceString() + return s +} + // Proxy function to the underlying cue.Value func (v *Value) Path() cue.Path { return v.val.Path() diff --git a/examples/tests/test.sh b/examples/tests/test.sh index a27e49f3..ed592b76 100755 --- a/examples/tests/test.sh +++ b/examples/tests/test.sh @@ -94,7 +94,7 @@ test::exec(){ test::one "Exec: env valid" --exit=0 --stdout={} \ "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute "$d"/exec/env/valid test::one "Exec: env with overlay" --exit=0 \ - "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input 'bar: "overlay environment"' "$d"/exec/env/overlay + "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input-cue 'bar: "overlay environment"' "$d"/exec/env/overlay test::one "Exec: non existent dir" --exit=0 --stdout={} \ "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute "$d"/exec/dir/doesnotexist @@ -191,13 +191,13 @@ test::input() { "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute "$d"/input/simple test::one "Input: simple input" --exit=0 --stdout='{"in":"foobar","test":"received: foobar"}' \ - "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input 'in: "foobar"' "$d"/input/simple + "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input-cue 'in: "foobar"' "$d"/input/simple test::one "Input: default values" --exit=0 --stdout='{"in":"default input","test":"received: default input"}' \ "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute "$d"/input/default test::one "Input: override default value" --exit=0 --stdout='{"in":"foobar","test":"received: foobar"}' \ - "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input 'in: "foobar"' "$d"/input/default + "$dagger" "${DAGGER_BINARY_ARGS[@]}" compute --input-cue 'in: "foobar"' "$d"/input/default } diff --git a/go.mod b/go.mod index 15143f1c..ab846694 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.20.0 github.com/spf13/cobra v1.0.0 + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9