buildkit/solver/load.go

92 lines
2.2 KiB
Go

package solver
import (
"strings"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
func LoadLLB(ops [][]byte) (Vertex, error) {
if len(ops) == 0 {
return nil, errors.New("invalid empty definition")
}
allOps := make(map[digest.Digest]*pb.Op)
var lastOp *pb.Op
var lastDigest digest.Digest
for _, dt := range ops {
var op pb.Op
if err := (&op).Unmarshal(dt); err != nil {
return nil, errors.Wrap(err, "failed to parse llb proto op")
}
lastOp = &op
lastDigest = digest.FromBytes(dt)
allOps[lastDigest] = &op
}
delete(allOps, lastDigest) // avoid loops
cache := make(map[digest.Digest]*vertex)
// TODO: validate the connections
return loadLLBVertexRecursive(lastDigest, lastOp, allOps, cache)
}
func toInternalVertex(v Vertex) *vertex {
cache := make(map[digest.Digest]*vertex)
return loadInternalVertexHelper(v, cache)
}
func loadInternalVertexHelper(v Vertex, cache map[digest.Digest]*vertex) *vertex {
if v, ok := cache[v.Digest()]; ok {
return v
}
vtx := &vertex{sys: v.Sys(), digest: v.Digest(), name: v.Name()}
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
}
func loadLLBVertexRecursive(dgst digest.Digest, op *pb.Op, all map[digest.Digest]*pb.Op, cache map[digest.Digest]*vertex) (*vertex, error) {
if v, ok := cache[dgst]; ok {
return v, nil
}
vtx := &vertex{sys: op.Op, digest: dgst, name: llbOpName(op)}
for _, in := range op.Inputs {
dgst := digest.Digest(in.Digest)
op, ok := all[dgst]
if !ok {
return nil, errors.Errorf("failed to find %s", in)
}
sub, err := loadLLBVertexRecursive(dgst, op, all, cache)
if err != nil {
return nil, err
}
vtx.inputs = append(vtx.inputs, &input{index: Index(in.Index), vertex: sub})
}
vtx.initClientVertex()
cache[dgst] = vtx
return vtx, nil
}
func llbOpName(op *pb.Op) string {
switch op := op.Op.(type) {
case *pb.Op_Source:
return op.Source.Identifier
case *pb.Op_Exec:
return strings.Join(op.Exec.Meta.Args, " ")
case *pb.Op_Build:
return "build"
default:
return "unknown"
}
}