Merge pull request #414 from dagger/dependabot/go_modules/github.com/moby/buildkit-0.8.3
fix pipeline caching when using cache mounts
This commit is contained in:
commit
d8deeb7077
@ -43,6 +43,11 @@ func (v *Value) Lookup(path string) *Value {
|
|||||||
return v.LookupPath(cue.ParsePath(path))
|
return v.LookupPath(cue.ParsePath(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Value) ReferencePath() (*Value, cue.Path) {
|
||||||
|
vv, p := v.val.ReferencePath()
|
||||||
|
return v.cc.Wrap(vv), p
|
||||||
|
}
|
||||||
|
|
||||||
// Proxy function to the underlying cue.Value
|
// Proxy function to the underlying cue.Value
|
||||||
func (v *Value) Len() cue.Value {
|
func (v *Value) Len() cue.Value {
|
||||||
return v.val.Len()
|
return v.val.Len()
|
||||||
|
@ -94,9 +94,9 @@ func (d *Environment) LoadPlan(ctx context.Context, s Solver) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := NewPipeline("[internal] source", s)
|
p := NewPipeline(planSource, s).WithCustomName("[internal] source")
|
||||||
// execute updater script
|
// execute updater script
|
||||||
if err := p.Do(ctx, planSource); err != nil {
|
if err := p.Run(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ func (d *Environment) LoadPlan(ctx context.Context, s Solver) error {
|
|||||||
// by user-specified scripts.
|
// by user-specified scripts.
|
||||||
func (d *Environment) LocalDirs() map[string]string {
|
func (d *Environment) LocalDirs() map[string]string {
|
||||||
dirs := map[string]string{}
|
dirs := map[string]string{}
|
||||||
localdirs := func(code ...*compiler.Value) {
|
localdirs := func(code *compiler.Value) {
|
||||||
Analyze(
|
Analyze(
|
||||||
func(op *compiler.Value) error {
|
func(op *compiler.Value) error {
|
||||||
do, err := op.Lookup("do").String()
|
do, err := op.Lookup("do").String()
|
||||||
@ -137,7 +137,7 @@ func (d *Environment) LocalDirs() map[string]string {
|
|||||||
dirs[dir] = dir
|
dirs[dir] = dir
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
code...,
|
code,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// 1. Scan the environment state
|
// 1. Scan the environment state
|
||||||
@ -245,8 +245,8 @@ func newPipelineRunner(computed *compiler.Value, s Solver) cueflow.RunnerFunc {
|
|||||||
Msg("dependency detected")
|
Msg("dependency detected")
|
||||||
}
|
}
|
||||||
v := compiler.Wrap(t.Value())
|
v := compiler.Wrap(t.Value())
|
||||||
p := NewPipeline(t.Path().String(), s)
|
p := NewPipeline(v, s)
|
||||||
err := p.Do(ctx, v)
|
err := p.Run(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
span.LogFields(otlog.String("error", err.Error()))
|
span.LogFields(otlog.String("error", err.Error()))
|
||||||
ext.Error.Set(span, true)
|
ext.Error.Set(span, true)
|
||||||
|
@ -32,6 +32,7 @@ const (
|
|||||||
|
|
||||||
// An execution pipeline
|
// An execution pipeline
|
||||||
type Pipeline struct {
|
type Pipeline struct {
|
||||||
|
code *compiler.Value
|
||||||
name string
|
name string
|
||||||
s Solver
|
s Solver
|
||||||
state llb.State
|
state llb.State
|
||||||
@ -40,15 +41,21 @@ type Pipeline struct {
|
|||||||
computed *compiler.Value
|
computed *compiler.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPipeline(name string, s Solver) *Pipeline {
|
func NewPipeline(code *compiler.Value, s Solver) *Pipeline {
|
||||||
return &Pipeline{
|
return &Pipeline{
|
||||||
name: name,
|
code: code,
|
||||||
|
name: code.Path().String(),
|
||||||
s: s,
|
s: s,
|
||||||
state: llb.Scratch(),
|
state: llb.Scratch(),
|
||||||
computed: compiler.NewValue(),
|
computed: compiler.NewValue(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Pipeline) WithCustomName(name string) *Pipeline {
|
||||||
|
p.name = name
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Pipeline) State() llb.State {
|
func (p *Pipeline) State() llb.State {
|
||||||
return p.state
|
return p.state
|
||||||
}
|
}
|
||||||
@ -76,38 +83,35 @@ func isComponent(v *compiler.Value) bool {
|
|||||||
return v.Lookup("#up").Exists()
|
return v.Lookup("#up").Exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ops(code ...*compiler.Value) ([]*compiler.Value, error) {
|
func ops(code *compiler.Value) ([]*compiler.Value, error) {
|
||||||
ops := []*compiler.Value{}
|
ops := []*compiler.Value{}
|
||||||
// 1. Decode 'code' into a single flat array of operations.
|
// 1. attachment array
|
||||||
for _, x := range code {
|
if isComponent(code) {
|
||||||
// 1. attachment array
|
xops, err := code.Lookup("#up").List()
|
||||||
if isComponent(x) {
|
if err != nil {
|
||||||
xops, err := x.Lookup("#up").List()
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// 'from' has an executable attached
|
|
||||||
ops = append(ops, xops...)
|
|
||||||
// 2. individual op
|
|
||||||
} else if _, err := x.Lookup("do").String(); err == nil {
|
|
||||||
ops = append(ops, x)
|
|
||||||
// 3. op array
|
|
||||||
} else if xops, err := x.List(); err == nil {
|
|
||||||
ops = append(ops, xops...)
|
|
||||||
} else {
|
|
||||||
// 4. error
|
|
||||||
source, err := x.Source()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("not executable: %s", source)
|
|
||||||
}
|
}
|
||||||
|
// 'from' has an executable attached
|
||||||
|
ops = append(ops, xops...)
|
||||||
|
// 2. individual op
|
||||||
|
} else if _, err := code.Lookup("do").String(); err == nil {
|
||||||
|
ops = append(ops, code)
|
||||||
|
// 3. op array
|
||||||
|
} else if xops, err := code.List(); err == nil {
|
||||||
|
ops = append(ops, xops...)
|
||||||
|
} else {
|
||||||
|
// 4. error
|
||||||
|
source, err := code.Source()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("not executable: %s", source)
|
||||||
}
|
}
|
||||||
return ops, nil
|
return ops, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Analyze(fn func(*compiler.Value) error, code ...*compiler.Value) error {
|
func Analyze(fn func(*compiler.Value) error, code *compiler.Value) error {
|
||||||
ops, err := ops(code...)
|
ops, err := ops(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -144,12 +148,8 @@ func analyzeOp(fn func(*compiler.Value) error, op *compiler.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// x may be:
|
func (p *Pipeline) Run(ctx context.Context) error {
|
||||||
// 1) a single operation
|
ops, err := ops(p.code)
|
||||||
// 2) an array of operations
|
|
||||||
// 3) a value with an attached array of operations
|
|
||||||
func (p *Pipeline) Do(ctx context.Context, code ...*compiler.Value) error {
|
|
||||||
ops, err := ops(code...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -260,8 +260,8 @@ func (p *Pipeline) Copy(ctx context.Context, op *compiler.Value, st llb.State) (
|
|||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
// Execute 'from' in a tmp pipeline, and use the resulting fs
|
// Execute 'from' in a tmp pipeline, and use the resulting fs
|
||||||
from := NewPipeline(op.Lookup("from").Path().String(), p.s)
|
from := NewPipeline(op.Lookup("from"), p.s)
|
||||||
if err := from.Do(ctx, op.Lookup("from")); err != nil {
|
if err := from.Run(ctx); err != nil {
|
||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
return st.File(
|
return st.File(
|
||||||
@ -438,7 +438,7 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value)
|
|||||||
dest,
|
dest,
|
||||||
llb.Scratch(),
|
llb.Scratch(),
|
||||||
llb.AsPersistentCacheDir(
|
llb.AsPersistentCacheDir(
|
||||||
mnt.Path().String(),
|
p.canonicalPath(mnt),
|
||||||
llb.CacheMountShared,
|
llb.CacheMountShared,
|
||||||
),
|
),
|
||||||
), nil
|
), nil
|
||||||
@ -453,8 +453,8 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eg. mount: "/foo": { from: www.source }
|
// eg. mount: "/foo": { from: www.source }
|
||||||
from := NewPipeline(mnt.Lookup("from").Path().String(), p.s)
|
from := NewPipeline(mnt.Lookup("from"), p.s)
|
||||||
if err := from.Do(ctx, mnt.Lookup("from")); err != nil {
|
if err := from.Run(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// possibly construct mount options for LLB from
|
// possibly construct mount options for LLB from
|
||||||
@ -470,6 +470,33 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value)
|
|||||||
return llb.AddMount(dest, from.State(), mo...), nil
|
return llb.AddMount(dest, from.State(), mo...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canonicalPath returns the canonical path of `v`
|
||||||
|
// If the pipeline is a reference to another pipeline, `canonicalPath()` will
|
||||||
|
// return the path of the reference of `v`.
|
||||||
|
// FIXME: this doesn't work with references of references.
|
||||||
|
func (p *Pipeline) canonicalPath(v *compiler.Value) string {
|
||||||
|
// value path
|
||||||
|
vPath := v.Path().Selectors()
|
||||||
|
|
||||||
|
// pipeline path
|
||||||
|
pipelinePath := p.code.Path().Selectors()
|
||||||
|
|
||||||
|
// check if the pipeline is a reference
|
||||||
|
_, ref := p.code.ReferencePath()
|
||||||
|
if len(ref.Selectors()) == 0 {
|
||||||
|
return v.Path().String()
|
||||||
|
}
|
||||||
|
canonicalPipelinePath := ref.Selectors()
|
||||||
|
|
||||||
|
// replace the pipeline path with the canonical pipeline path
|
||||||
|
// 1. strip the pipeline path from the value path
|
||||||
|
vPath = vPath[len(pipelinePath):]
|
||||||
|
// 2. inject the canonical pipeline path
|
||||||
|
vPath = append(canonicalPipelinePath, vPath...)
|
||||||
|
|
||||||
|
return cue.MakePath(vPath...).String()
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Pipeline) Export(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
|
func (p *Pipeline) Export(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
|
||||||
source, err := op.Lookup("source").String()
|
source, err := op.Lookup("source").String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -553,8 +580,8 @@ func unmarshalAnything(data []byte, fn unmarshaller) (interface{}, error) {
|
|||||||
|
|
||||||
func (p *Pipeline) Load(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, 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
|
// Execute 'from' in a tmp pipeline, and use the resulting fs
|
||||||
from := NewPipeline(op.Lookup("from").Path().String(), p.s)
|
from := NewPipeline(op.Lookup("from"), p.s)
|
||||||
if err := from.Do(ctx, op.Lookup("from")); err != nil {
|
if err := from.Run(ctx); err != nil {
|
||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
p.image = from.ImageConfig()
|
p.image = from.ImageConfig()
|
||||||
@ -735,8 +762,8 @@ func (p *Pipeline) DockerBuild(ctx context.Context, op *compiler.Value, st llb.S
|
|||||||
// docker build context. This can come from another component, so we need to
|
// docker build context. This can come from another component, so we need to
|
||||||
// compute it first.
|
// compute it first.
|
||||||
if dockerContext.Exists() {
|
if dockerContext.Exists() {
|
||||||
from := NewPipeline(op.Lookup("context").Path().String(), p.s)
|
from := NewPipeline(op.Lookup("context"), p.s)
|
||||||
if err := from.Do(ctx, dockerContext); err != nil {
|
if err := from.Run(ctx); err != nil {
|
||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
contextDef, err = p.s.Marshal(ctx, from.State())
|
contextDef, err = p.s.Marshal(ctx, from.State())
|
||||||
@ -883,9 +910,9 @@ func (p *Pipeline) WriteFile(ctx context.Context, op *compiler.Value, st llb.Sta
|
|||||||
content = []byte(str)
|
content = []byte(str)
|
||||||
}
|
}
|
||||||
case cue.BottomKind:
|
case cue.BottomKind:
|
||||||
err = fmt.Errorf("%s: WriteFile content is not set", op.Path().String())
|
err = fmt.Errorf("%s: WriteFile content is not set", p.canonicalPath(op))
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("%s: unhandled data type in WriteFile: %s", op.Path().String(), kind)
|
err = fmt.Errorf("%s: unhandled data type in WriteFile: %s", p.canonicalPath(op), kind)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, err
|
return st, err
|
||||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/google/uuid v1.2.0
|
github.com/google/uuid v1.2.0
|
||||||
github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea
|
github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
|
||||||
github.com/moby/buildkit v0.8.2
|
github.com/moby/buildkit v0.8.3
|
||||||
github.com/morikuni/aec v1.0.0
|
github.com/morikuni/aec v1.0.0
|
||||||
github.com/opencontainers/go-digest v1.0.0
|
github.com/opencontainers/go-digest v1.0.0
|
||||||
github.com/opentracing/opentracing-go v1.2.0
|
github.com/opentracing/opentracing-go v1.2.0
|
||||||
|
4
go.sum
4
go.sum
@ -730,8 +730,8 @@ github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5
|
|||||||
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/moby/buildkit v0.8.2 h1:kvb0cLWss4mOhCxcXSTENzzA+t1JR1eIyXFhDrI+73g=
|
github.com/moby/buildkit v0.8.3 h1:vFlwUQ6BZE1loZ8zoZH3fYgmA1djFCS3DrOhCVU6ZZE=
|
||||||
github.com/moby/buildkit v0.8.2/go.mod h1:5PZi7ALzuxG604ggYSeN+rzC+CyJscuXS7WetulJr1Y=
|
github.com/moby/buildkit v0.8.3/go.mod h1:jUezwyOvKdkbcvR66WuKzPYQUO3sQ8i/eChLZ7kEmg8=
|
||||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||||
github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
|
github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
image = "moby/buildkit"
|
image = "moby/buildkit"
|
||||||
version = "v0.8.2"
|
version = "v0.8.3"
|
||||||
imageVersion = image + ":" + version
|
imageVersion = image + ":" + version
|
||||||
containerName = "dagger-buildkitd"
|
containerName = "dagger-buildkitd"
|
||||||
volumeName = "dagger-buildkitd"
|
volumeName = "dagger-buildkitd"
|
||||||
|
@ -24,7 +24,6 @@ setup() {
|
|||||||
|
|
||||||
# cache
|
# cache
|
||||||
run "$DAGGER" compute "$TESTDIR"/ops/mounts/valid/cache
|
run "$DAGGER" compute "$TESTDIR"/ops/mounts/valid/cache
|
||||||
assert_line '{"TestMountCache":"NOT SURE WHAT TO TEST YET"}'
|
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
# component
|
# component
|
||||||
|
9
tests/ops/mounts/valid/cache/main.cue
vendored
9
tests/ops/mounts/valid/cache/main.cue
vendored
@ -1,6 +1,8 @@
|
|||||||
package testing
|
package testing
|
||||||
|
|
||||||
import "dagger.io/dagger/op"
|
import (
|
||||||
|
"dagger.io/dagger/op"
|
||||||
|
)
|
||||||
|
|
||||||
TestMountCache: {
|
TestMountCache: {
|
||||||
string
|
string
|
||||||
@ -11,7 +13,7 @@ TestMountCache: {
|
|||||||
},
|
},
|
||||||
op.#Exec & {
|
op.#Exec & {
|
||||||
args: ["sh", "-c", """
|
args: ["sh", "-c", """
|
||||||
echo -n "NOT SURE WHAT TO TEST YET" > /out
|
echo -n "$RANDOM" > /out
|
||||||
"""]
|
"""]
|
||||||
dir: "/"
|
dir: "/"
|
||||||
mount: something: "cache"
|
mount: something: "cache"
|
||||||
@ -22,3 +24,6 @@ TestMountCache: {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure references to pipelines with cache mounts never get re-executed. #399
|
||||||
|
TestReference: TestMountCache
|
||||||
|
Reference in New Issue
Block a user