forked from moby/buildkit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
load.go
97 lines (83 loc) · 2.43 KB
/
load.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package solver
import (
"strings"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
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)}
for _, in := range op.Inputs {
sub, err := load(in.Digest)
if err != nil {
return nil, err
}
vtx.inputs = append(vtx.inputs, &input{index: Index(in.Index), vertex: sub.(*vertex)})
}
vtx.initClientVertex()
return vtx, nil
}
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(), metadata: v.Metadata(), 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
}
// loadLLB loads LLB.
// fn is executed sequentially.
func loadLLB(def *pb.Definition, fn func(digest.Digest, *pb.Op, func(digest.Digest) (interface{}, error)) (interface{}, error)) (interface{}, Index, error) {
if len(def.Def) == 0 {
return nil, 0, errors.New("invalid empty definition")
}
allOps := make(map[digest.Digest]*pb.Op)
var dgst digest.Digest
for _, dt := range def.Def {
var op pb.Op
if err := (&op).Unmarshal(dt); err != nil {
return nil, 0, errors.Wrap(err, "failed to parse llb proto op")
}
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)
if err != nil {
return nil, err
}
cache[dgst] = v
return v, nil
}
v, err := rec(dgst)
return v, Index(lastOp.Inputs[0].Index), err
}
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"
}
}