diff --git a/dagger/client.go b/dagger/client.go index 265ecffb..22030f5a 100644 --- a/dagger/client.go +++ b/dagger/client.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strings" + "cuelang.org/go/cue" "golang.org/x/sync/errgroup" "github.com/opentracing/opentracing-go" @@ -92,7 +93,7 @@ func (c *Client) Up(ctx context.Context, deployment *Deployment) (*compiler.Valu return err }) - return out, compiler.Err(eg.Wait()) + return out, eg.Wait() } func (c *Client) buildfn(ctx context.Context, deployment *Deployment, ch chan *bk.SolveStatus, w io.WriteCloser) error { @@ -139,7 +140,7 @@ func (c *Client) buildfn(ctx context.Context, deployment *Deployment, ch chan *b // Compute output overlay lg.Debug().Msg("computing deployment") if err := deployment.Up(ctx, s, nil); err != nil { - return nil, err + return nil, compiler.Err(err) } // Export deployment to a cue directory @@ -206,8 +207,8 @@ func (c *Client) outputfn(ctx context.Context, r io.Reader) (*compiler.Value, er if err != nil { return nil, err } - if err := out.Fill(v); err != nil { - return nil, fmt.Errorf("%s: %w", h.Name, err) + if err := out.FillPath(cue.MakePath(), v); err != nil { + return nil, fmt.Errorf("%s: %w", h.Name, compiler.Err(err)) } } return out, nil diff --git a/dagger/compiler/compiler_test.go b/dagger/compiler/compiler_test.go index c4ff093f..7b21d947 100644 --- a/dagger/compiler/compiler_test.go +++ b/dagger/compiler/compiler_test.go @@ -11,8 +11,8 @@ func TestFieldNotExist(t *testing.T) { c := &Compiler{} root, err := c.Compile("test.cue", `foo: "bar"`) require.NoError(t, err) - require.True(t, root.Get("foo").Exists()) - require.False(t, root.Get("bar").Exists()) + require.True(t, root.Lookup("foo").Exists()) + require.False(t, root.Lookup("bar").Exists()) } // Test that a non-existing definition is detected correctly @@ -20,8 +20,8 @@ func TestDefNotExist(t *testing.T) { c := &Compiler{} root, err := c.Compile("test.cue", `foo: #bla: "bar"`) require.NoError(t, err) - require.True(t, root.Get("foo.#bla").Exists()) - require.False(t, root.Get("foo.#nope").Exists()) + require.True(t, root.Lookup("foo.#bla").Exists()) + require.False(t, root.Lookup("foo.#nope").Exists()) } func TestJSON(t *testing.T) { @@ -30,6 +30,6 @@ func TestJSON(t *testing.T) { require.NoError(t, err) require.Equal(t, `{"foo":{"hello":"world"}}`, string(v.JSON())) - // Reproduce a bug where Value.Get().JSON() ignores Get() - require.Equal(t, `{"hello":"world"}`, string(v.Get("foo").JSON())) + // Reproduce a bug where Value.Lookup().JSON() ignores Lookup() + require.Equal(t, `{"hello":"world"}`, string(v.Lookup("foo").JSON())) } diff --git a/dagger/compiler/utils.go b/dagger/compiler/utils.go deleted file mode 100644 index 1ea36789..00000000 --- a/dagger/compiler/utils.go +++ /dev/null @@ -1,22 +0,0 @@ -package compiler - -import ( - "cuelang.org/go/cue" -) - -func cueStringsToCuePath(parts ...string) cue.Path { - selectors := make([]cue.Selector, 0, len(parts)) - for _, part := range parts { - selectors = append(selectors, cue.Str(part)) - } - return cue.MakePath(selectors...) -} - -func cuePathToStrings(p cue.Path) []string { - selectors := p.Selectors() - out := make([]string, len(selectors)) - for i, sel := range selectors { - out[i] = sel.String() - } - return out -} diff --git a/dagger/compiler/value.go b/dagger/compiler/value.go index d0ee9477..2833134d 100644 --- a/dagger/compiler/value.go +++ b/dagger/compiler/value.go @@ -31,19 +31,19 @@ func wrapValue(v cue.Value, inst *cue.Instance, cc *Compiler) *Value { } } -// Fill the value in-place, unlike Merge which returns a copy. -func (v *Value) Fill(x interface{}) error { +// FillPath fills the value in-place +func (v *Value) FillPath(p cue.Path, x interface{}) error { v.cc.lock() defer v.cc.unlock() // If calling Fill() with a Value, we want to use the underlying // cue.Value to fill. if val, ok := x.(*Value); ok { - v.val = v.val.Fill(val.val) + v.val = v.val.FillPath(p, val.val) } else { - v.val = v.val.Fill(x) + v.val = v.val.FillPath(p, x) } - return v.Validate() + return v.val.Err() } // LookupPath is a concurrency safe wrapper around cue.Value.LookupPath @@ -55,13 +55,8 @@ func (v *Value) LookupPath(p cue.Path) *Value { } // Lookup is a helper function to lookup by path parts. -func (v *Value) Lookup(path ...string) *Value { - return v.LookupPath(cueStringsToCuePath(path...)) -} - -// Get is a helper function to lookup by path string -func (v *Value) Get(target string) *Value { - return v.LookupPath(cue.ParsePath(target)) +func (v *Value) Lookup(path string) *Value { + return v.LookupPath(cue.ParsePath(path)) } // Proxy function to the underlying cue.Value @@ -146,30 +141,6 @@ func (v *Value) List() ([]*Value, error) { return l, nil } -// FIXME: receive string path? -func (v *Value) Merge(x interface{}, path ...string) (*Value, error) { - if xval, ok := x.(*Value); ok { - x = xval.val - } - - v.cc.lock() - result := v.Wrap(v.val.Fill(x, path...)) - v.cc.unlock() - - return result, result.Validate() -} - -func (v *Value) MergePath(x interface{}, p cue.Path) (*Value, error) { - // FIXME: array indexes and defs are not supported, - // they will be silently converted to regular fields. - // eg. `foo.#bar[0]` will become `foo["#bar"]["0"]` - return v.Merge(x, cuePathToStrings(p)...) -} - -func (v *Value) MergeTarget(x interface{}, target string) (*Value, error) { - return v.MergePath(x, cue.ParsePath(target)) -} - // Recursive concreteness check. func (v *Value) IsConcreteR() error { return v.val.Validate(cue.Concrete(true)) @@ -198,6 +169,15 @@ func (v *Value) Walk(before func(*Value) bool, after func(*Value)) { // Contrast with cue.Value.MarshalJSON which requires all values // to be concrete. func (v *Value) JSON() JSON { + cuePathToStrings := func(p cue.Path) []string { + selectors := p.Selectors() + out := make([]string, len(selectors)) + for i, sel := range selectors { + out[i] = sel.String() + } + return out + } + var out JSON v.val.Walk( func(v cue.Value) bool { diff --git a/dagger/deployment.go b/dagger/deployment.go index e813d3a6..8b0ad574 100644 --- a/dagger/deployment.go +++ b/dagger/deployment.go @@ -93,9 +93,9 @@ func NewDeployment(st *DeploymentState) (*Deployment, error) { return nil, err } if input.Key == "" { - d.input, err = d.input.Merge(v) + err = d.input.FillPath(cue.MakePath(), v) } else { - d.input, err = d.input.MergeTarget(v, input.Key) + err = d.input.FillPath(cue.ParsePath(input.Key), v) } if err != nil { return nil, err @@ -176,14 +176,14 @@ func (d *Deployment) LocalDirs() map[string]string { localdirs := func(code ...*compiler.Value) { Analyze( func(op *compiler.Value) error { - do, err := op.Get("do").String() + do, err := op.Lookup("do").String() if err != nil { return err } if do != "local" { return nil } - dir, err := op.Get("dir").String() + dir, err := op.Lookup("dir").String() if err != nil { return err } @@ -199,7 +199,7 @@ func (d *Deployment) LocalDirs() map[string]string { flow := cueflow.New(&cueflow.Config{}, inst, newTaskFunc(inst, noOpRunner)) for _, t := range flow.Tasks() { v := compiler.Wrap(t.Value(), inst) - localdirs(v.Get("#compute")) + localdirs(v.Lookup("#compute")) } // 2. Scan the plan @@ -277,8 +277,7 @@ func (d *Deployment) Up(ctx context.Context, s Solver, _ *UpOpts) error { return nil } // Merge task value into output - var err error - d.output, err = d.output.MergePath(t.Value(), t.Path()) + err := d.output.FillPath(t.Path(), t.Value()) if err != nil { lg. Error(). diff --git a/dagger/pipeline.go b/dagger/pipeline.go index c7ec55d3..5819ccec 100644 --- a/dagger/pipeline.go +++ b/dagger/pipeline.go @@ -61,7 +61,7 @@ func (p *Pipeline) FS() fs.FS { } func isComponent(v *compiler.Value) bool { - return v.Get("#compute").Exists() + return v.Lookup("#compute").Exists() } func ops(code ...*compiler.Value) ([]*compiler.Value, error) { @@ -70,14 +70,14 @@ func ops(code ...*compiler.Value) ([]*compiler.Value, error) { for _, x := range code { // 1. attachment array if isComponent(x) { - xops, err := x.Get("#compute").List() + xops, err := x.Lookup("#compute").List() if err != nil { return nil, err } // 'from' has an executable attached ops = append(ops, xops...) // 2. individual op - } else if _, err := x.Get("do").String(); err == nil { + } else if _, err := x.Lookup("do").String(); err == nil { ops = append(ops, x) // 3. op array } else if xops, err := x.List(); err == nil { @@ -111,20 +111,20 @@ func analyzeOp(fn func(*compiler.Value) error, op *compiler.Value) error { if err := fn(op); err != nil { return err } - do, err := op.Get("do").String() + do, err := op.Lookup("do").String() if err != nil { return err } switch do { case "load", "copy": - return Analyze(fn, op.Get("from")) + return Analyze(fn, op.Lookup("from")) case "exec": - fields, err := op.Get("mount").Fields() + fields, err := op.Lookup("mount").Fields() if err != nil { return err } for _, mnt := range fields { - if from := mnt.Value.Get("from"); from.Exists() { + if from := mnt.Value.Lookup("from"); from.Exists() { return Analyze(fn, from) } } @@ -174,7 +174,7 @@ func (p *Pipeline) Do(ctx context.Context, code ...*compiler.Value) error { } func (p *Pipeline) doOp(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - do, err := op.Get("do").String() + do, err := op.Lookup("do").String() if err != nil { return st, err } @@ -218,7 +218,7 @@ func (p *Pipeline) Subdir(ctx context.Context, op *compiler.Value, st llb.State) // FIXME: this could be more optimized by carrying subdir path as metadata, // and using it in copy, load or mount. - dir, err := op.Get("dir").String() + dir, err := op.Lookup("dir").String() if err != nil { return st, err } @@ -237,17 +237,17 @@ func (p *Pipeline) Subdir(ctx context.Context, op *compiler.Value, st llb.State) func (p *Pipeline) Copy(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { // Decode copy options - src, err := op.Get("src").String() + src, err := op.Lookup("src").String() if err != nil { return st, err } - dest, err := op.Get("dest").String() + dest, err := op.Lookup("dest").String() if err != nil { return st, err } // Execute 'from' in a tmp pipeline, and use the resulting fs - from := NewPipeline(op.Get("from").Path().String(), p.s, nil) - if err := from.Do(ctx, op.Get("from")); err != nil { + from := NewPipeline(op.Lookup("from").Path().String(), p.s, nil) + if err := from.Do(ctx, op.Lookup("from")); err != nil { return st, err } fromResult, err := from.Result() @@ -272,7 +272,7 @@ func (p *Pipeline) Copy(ctx context.Context, op *compiler.Value, st llb.State) ( } func (p *Pipeline) Local(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - dir, err := op.Get("dir").String() + dir, err := op.Lookup("dir").String() if err != nil { return st, err } @@ -362,8 +362,8 @@ func (p *Pipeline) Exec(ctx context.Context, op *compiler.Value, st llb.State) ( opts = append(opts, llb.Dir(cmd.Dir)) // env - if env := op.Get("env"); env.Exists() { - envs, err := op.Get("env").Fields() + if env := op.Lookup("env"); env.Exists() { + envs, err := op.Lookup("env").Fields() if err != nil { return st, err } @@ -446,8 +446,8 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value) } } // eg. mount: "/foo": { from: www.source } - from := NewPipeline(mnt.Get("from").Path().String(), p.s, nil) - if err := from.Do(ctx, mnt.Get("from")); err != nil { + from := NewPipeline(mnt.Lookup("from").Path().String(), p.s, nil) + if err := from.Do(ctx, mnt.Lookup("from")); err != nil { return nil, err } fromResult, err := from.Result() @@ -468,11 +468,11 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value) } func (p *Pipeline) Export(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - source, err := op.Get("source").String() + source, err := op.Lookup("source").String() if err != nil { return st, err } - format, err := op.Get("format").String() + format, err := op.Lookup("format").String() if err != nil { return st, err } @@ -550,15 +550,15 @@ func unmarshalAnything(data []byte, fn unmarshaller) (interface{}, error) { func (p *Pipeline) Load(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { // Execute 'from' in a tmp pipeline, and use the resulting fs - from := NewPipeline(op.Get("from").Path().String(), p.s, nil) - if err := from.Do(ctx, op.Get("from")); err != nil { + from := NewPipeline(op.Lookup("from").Path().String(), p.s, nil) + if err := from.Do(ctx, op.Lookup("from")); err != nil { return st, err } return from.Result() } func (p *Pipeline) FetchContainer(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - rawRef, err := op.Get("ref").String() + rawRef, err := op.Lookup("ref").String() if err != nil { return st, err } @@ -609,7 +609,7 @@ func parseKeyValue(env string) (string, string) { } func (p *Pipeline) PushContainer(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - rawRef, err := op.Get("ref").String() + rawRef, err := op.Lookup("ref").String() if err != nil { return st, err } @@ -638,11 +638,11 @@ func (p *Pipeline) PushContainer(ctx context.Context, op *compiler.Value, st llb } func (p *Pipeline) FetchGit(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - remote, err := op.Get("remote").String() + remote, err := op.Lookup("remote").String() if err != nil { return st, err } - ref, err := op.Get("ref").String() + ref, err := op.Lookup("ref").String() if err != nil { return st, err } @@ -793,17 +793,17 @@ func (p *Pipeline) DockerBuild(ctx context.Context, op *compiler.Value, st llb.S } func (p *Pipeline) WriteFile(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - content, err := op.Get("content").String() + content, err := op.Lookup("content").String() if err != nil { return st, err } - dest, err := op.Get("dest").String() + dest, err := op.Lookup("dest").String() if err != nil { return st, err } - mode, err := op.Get("mode").Int64() + mode, err := op.Lookup("mode").Int64() if err != nil { return st, err } @@ -815,17 +815,17 @@ func (p *Pipeline) WriteFile(ctx context.Context, op *compiler.Value, st llb.Sta } func (p *Pipeline) Mkdir(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) { - path, err := op.Get("path").String() + path, err := op.Lookup("path").String() if err != nil { return st, err } - dir, err := op.Get("dir").String() + dir, err := op.Lookup("dir").String() if err != nil { return st, err } - mode, err := op.Get("mode").Int64() + mode, err := op.Lookup("mode").Int64() if err != nil { return st, err } diff --git a/go.mod b/go.mod index a1d7cfe3..47d0cc9e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module dagger.io/go go 1.16 require ( - cuelang.org/go v0.3.0-beta.7 + cuelang.org/go v0.3.0-beta.8 github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db github.com/containerd/console v1.0.1 github.com/docker/distribution v2.7.1+incompatible diff --git a/go.sum b/go.sum index fac2bece..7a578f88 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ cuelang.org/go v0.3.0-beta.6 h1:od1S/Hbl2S45TLSONl95X3O4TXN1za6CUSD13bTxCVk= cuelang.org/go v0.3.0-beta.6/go.mod h1:Ikvs157igkGV5gFUdYSFa+lWp/CDteVhubPTXyvPRtA= cuelang.org/go v0.3.0-beta.7 h1:Ui7Jtp9rEFI6J8FcGiI17CB/XiGtQlCCIrvR5A15GEU= cuelang.org/go v0.3.0-beta.7/go.mod h1:jvMO35Q4D2D3m2ujAmKESICaYkjMbu5+D+2zIGuWTpQ= +cuelang.org/go v0.3.0-beta.8 h1:+ZAPv23ciGjVvmgAD8iOcwMOwm7A5zqhLimrAaaoYlg= +cuelang.org/go v0.3.0-beta.8/go.mod h1:jvMO35Q4D2D3m2ujAmKESICaYkjMbu5+D+2zIGuWTpQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037 h1:+PdD6GLKejR9DizMAKT5DpSAkKswvZrurk1/eEt9+pw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/stdlib/dagger/dagger.cue b/stdlib/dagger/dagger.cue index af657d60..3758fbff 100644 --- a/stdlib/dagger/dagger.cue +++ b/stdlib/dagger/dagger.cue @@ -6,10 +6,11 @@ import ( // An artifact such as source code checkout, container image, binary archive... // May be passed as user input, or computed by a buildkit pipeline -#Artifact: #compute: [...llb.#Op] - -// deprecated, use #Artifact instead. -#Dir: #Artifact +#Artifact: { + #compute: [...llb.#Op] + _ + ... +} // Secret value // FIXME: currently aliased as a string to mark secrets diff --git a/stdlib/docker/docker.cue b/stdlib/docker/docker.cue index c7d68eb0..fee51bf6 100644 --- a/stdlib/docker/docker.cue +++ b/stdlib/docker/docker.cue @@ -9,7 +9,7 @@ import ( // Build a docker container image #Build: { - source: dagger.#Dir + source: dagger.#Artifact image: #compute: [ llb.#DockerBuild & {context: source},