2017-06-06 18:01:18 +00:00
|
|
|
package solver
|
|
|
|
|
|
|
|
import (
|
2017-07-06 04:25:51 +00:00
|
|
|
"strings"
|
|
|
|
|
2017-06-22 20:15:46 +00:00
|
|
|
"github.com/moby/buildkit/solver/pb"
|
2017-12-14 00:33:56 +00:00
|
|
|
"github.com/moby/buildkit/source"
|
2017-06-06 18:01:18 +00:00
|
|
|
digest "github.com/opencontainers/go-digest"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
2017-10-02 04:59:34 +00:00
|
|
|
func newVertex(dgst digest.Digest, op *pb.Op, opMeta *pb.OpMetadata, load func(digest.Digest) (interface{}, error)) (*vertex, error) {
|
|
|
|
vtx := &vertex{sys: op.Op, metadata: opMeta, digest: dgst, name: llbOpName(op)}
|
2017-09-26 03:57:38 +00:00
|
|
|
for _, in := range op.Inputs {
|
|
|
|
sub, err := load(in.Digest)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-06-06 18:01:18 +00:00
|
|
|
}
|
2017-12-15 08:06:54 +00:00
|
|
|
vtx.inputs = append(vtx.inputs, &input{index: Index(in.Index), vertex: sub.(*vertex)})
|
2017-06-06 18:01:18 +00:00
|
|
|
}
|
2017-09-26 03:57:38 +00:00
|
|
|
vtx.initClientVertex()
|
|
|
|
return vtx, nil
|
2017-07-06 04:25:51 +00:00
|
|
|
}
|
2017-06-06 18:01:18 +00:00
|
|
|
|
2017-12-15 08:06:54 +00:00
|
|
|
func loadInternalVertexHelper(v Vertex, cache map[digest.Digest]*vertex) *vertex {
|
2017-07-06 04:25:51 +00:00
|
|
|
if v, ok := cache[v.Digest()]; ok {
|
|
|
|
return v
|
|
|
|
}
|
2017-10-02 04:59:34 +00:00
|
|
|
vtx := &vertex{sys: v.Sys(), metadata: v.Metadata(), digest: v.Digest(), name: v.Name()}
|
2017-07-06 04:25:51 +00:00
|
|
|
for _, in := range v.Inputs() {
|
|
|
|
vv := loadInternalVertexHelper(in.Vertex, cache)
|
|
|
|
vtx.inputs = append(vtx.inputs, &input{index: in.Index, vertex: vv})
|
|
|
|
}
|
|
|
|
vtx.initClientVertex()
|
|
|
|
cache[v.Digest()] = vtx
|
|
|
|
return vtx
|
|
|
|
}
|
|
|
|
|
2017-10-02 04:59:34 +00:00
|
|
|
// loadLLB loads LLB.
|
|
|
|
// fn is executed sequentially.
|
2017-12-13 07:39:37 +00:00
|
|
|
func loadLLB(def *pb.Definition, fn func(digest.Digest, *pb.Op, func(digest.Digest) (interface{}, error)) (interface{}, error)) (interface{}, pb.OutputIndex, error) {
|
2017-10-02 04:59:34 +00:00
|
|
|
if len(def.Def) == 0 {
|
2017-09-26 03:57:38 +00:00
|
|
|
return nil, 0, errors.New("invalid empty definition")
|
2017-06-06 18:01:18 +00:00
|
|
|
}
|
2017-09-26 03:57:38 +00:00
|
|
|
|
|
|
|
allOps := make(map[digest.Digest]*pb.Op)
|
|
|
|
|
|
|
|
var dgst digest.Digest
|
|
|
|
|
2017-10-02 04:59:34 +00:00
|
|
|
for _, dt := range def.Def {
|
2017-09-26 03:57:38 +00:00
|
|
|
var op pb.Op
|
|
|
|
if err := (&op).Unmarshal(dt); err != nil {
|
|
|
|
return nil, 0, errors.Wrap(err, "failed to parse llb proto op")
|
2017-06-06 18:01:18 +00:00
|
|
|
}
|
2017-09-26 03:57:38 +00:00
|
|
|
dgst = digest.FromBytes(dt)
|
|
|
|
allOps[dgst] = &op
|
|
|
|
}
|
|
|
|
|
|
|
|
lastOp := allOps[dgst]
|
|
|
|
delete(allOps, dgst)
|
|
|
|
dgst = lastOp.Inputs[0].Digest
|
|
|
|
|
|
|
|
cache := make(map[digest.Digest]interface{})
|
|
|
|
|
|
|
|
var rec func(dgst digest.Digest) (interface{}, error)
|
|
|
|
rec = func(dgst digest.Digest) (interface{}, error) {
|
|
|
|
if v, ok := cache[dgst]; ok {
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
v, err := fn(dgst, allOps[dgst], rec)
|
2017-06-06 18:01:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-09-26 03:57:38 +00:00
|
|
|
cache[dgst] = v
|
|
|
|
return v, nil
|
2017-06-13 21:42:51 +00:00
|
|
|
}
|
2017-09-26 03:57:38 +00:00
|
|
|
|
|
|
|
v, err := rec(dgst)
|
2017-12-13 07:39:37 +00:00
|
|
|
return v, lastOp.Inputs[0].Index, err
|
2017-06-06 18:01:18 +00:00
|
|
|
}
|
2017-07-06 04:25:51 +00:00
|
|
|
|
|
|
|
func llbOpName(op *pb.Op) string {
|
|
|
|
switch op := op.Op.(type) {
|
|
|
|
case *pb.Op_Source:
|
2017-12-14 00:33:56 +00:00
|
|
|
if id, err := source.FromLLB(op); err == nil {
|
|
|
|
if id, ok := id.(*source.LocalIdentifier); ok {
|
|
|
|
if len(id.IncludePatterns) == 1 {
|
|
|
|
return op.Source.Identifier + " (" + id.IncludePatterns[0] + ")"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-06 04:25:51 +00:00
|
|
|
return op.Source.Identifier
|
|
|
|
case *pb.Op_Exec:
|
|
|
|
return strings.Join(op.Exec.Meta.Args, " ")
|
2017-07-21 17:58:24 +00:00
|
|
|
case *pb.Op_Build:
|
|
|
|
return "build"
|
2017-07-06 04:25:51 +00:00
|
|
|
default:
|
|
|
|
return "unknown"
|
|
|
|
}
|
|
|
|
}
|