Skip to content

Commit 7af75e7

Browse files
committed
solver: move AddBuildConfig into llbsolver package
The data structures used by llbsolver shouldn't be bundled into the same package as the actual creation of the build config. As it was, it wasn't possible to use the data structures (in tests, external libraries using buildkit, etc) without pulling in more of buildkit than was probably intended. Signed-off-by: Justin Chadwell <[email protected]>
1 parent 80b91c5 commit 7af75e7

File tree

2 files changed

+155
-160
lines changed

2 files changed

+155
-160
lines changed

solver/llbsolver/provenance.go

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ func NewProvenanceCreator(ctx context.Context, cp *provenance.Capture, res solve
425425
pr.Invocation.Parameters.Secrets = nil
426426
pr.Invocation.Parameters.SSH = nil
427427
case "max":
428-
dgsts, err := provenance.AddBuildConfig(ctx, pr, res)
428+
dgsts, err := AddBuildConfig(ctx, pr, res)
429429
if err != nil {
430430
return nil, err
431431
}
@@ -571,3 +571,157 @@ func resolveRemotes(ctx context.Context, res solver.Result) ([]*solver.Remote, e
571571
}
572572
return remotes, nil
573573
}
574+
575+
func AddBuildConfig(ctx context.Context, p *provenance.ProvenancePredicate, rp solver.ResultProxy) (map[digest.Digest]int, error) {
576+
def := rp.Definition()
577+
steps, indexes, err := toBuildSteps(def)
578+
if err != nil {
579+
return nil, err
580+
}
581+
582+
bc := &provenance.BuildConfig{
583+
Definition: steps,
584+
DigestMapping: digestMap(indexes),
585+
}
586+
587+
p.BuildConfig = bc
588+
589+
if def.Source != nil {
590+
sis := make([]provenance.SourceInfo, len(def.Source.Infos))
591+
for i, si := range def.Source.Infos {
592+
steps, indexes, err := toBuildSteps(si.Definition)
593+
if err != nil {
594+
return nil, err
595+
}
596+
s := provenance.SourceInfo{
597+
Filename: si.Filename,
598+
Data: si.Data,
599+
Language: si.Language,
600+
Definition: steps,
601+
DigestMapping: digestMap(indexes),
602+
}
603+
sis[i] = s
604+
}
605+
606+
if len(def.Source.Infos) != 0 {
607+
locs := map[string]*pb.Locations{}
608+
for k, l := range def.Source.Locations {
609+
idx, ok := indexes[digest.Digest(k)]
610+
if !ok {
611+
continue
612+
}
613+
locs[fmt.Sprintf("step%d", idx)] = l
614+
}
615+
616+
if p.Metadata == nil {
617+
p.Metadata = &provenance.ProvenanceMetadata{}
618+
}
619+
p.Metadata.BuildKitMetadata.Source = &provenance.Source{
620+
Infos: sis,
621+
Locations: locs,
622+
}
623+
}
624+
}
625+
626+
return indexes, nil
627+
}
628+
629+
func digestMap(idx map[digest.Digest]int) map[digest.Digest]string {
630+
m := map[digest.Digest]string{}
631+
for k, v := range idx {
632+
m[k] = fmt.Sprintf("step%d", v)
633+
}
634+
return m
635+
}
636+
637+
func toBuildSteps(def *pb.Definition) ([]provenance.BuildStep, map[digest.Digest]int, error) {
638+
if def == nil || len(def.Def) == 0 {
639+
return nil, nil, nil
640+
}
641+
642+
ops := make(map[digest.Digest]*pb.Op)
643+
defs := make(map[digest.Digest][]byte)
644+
645+
var dgst digest.Digest
646+
for _, dt := range def.Def {
647+
var op pb.Op
648+
if err := (&op).Unmarshal(dt); err != nil {
649+
return nil, nil, errors.Wrap(err, "failed to parse llb proto op")
650+
}
651+
if src := op.GetSource(); src != nil {
652+
for k := range src.Attrs {
653+
if k == "local.session" || k == "local.unique" {
654+
delete(src.Attrs, k)
655+
}
656+
}
657+
}
658+
dgst = digest.FromBytes(dt)
659+
ops[dgst] = &op
660+
defs[dgst] = dt
661+
}
662+
663+
if dgst == "" {
664+
return nil, nil, nil
665+
}
666+
667+
// depth first backwards
668+
dgsts := make([]digest.Digest, 0, len(def.Def))
669+
op := ops[dgst]
670+
671+
if op.Op != nil {
672+
return nil, nil, errors.Errorf("invalid last vertex: %T", op.Op)
673+
}
674+
675+
if len(op.Inputs) != 1 {
676+
return nil, nil, errors.Errorf("invalid last vertex inputs: %v", len(op.Inputs))
677+
}
678+
679+
visited := map[digest.Digest]struct{}{}
680+
dgsts, err := walkDigests(dgsts, ops, dgst, visited)
681+
if err != nil {
682+
return nil, nil, err
683+
}
684+
indexes := map[digest.Digest]int{}
685+
for i, dgst := range dgsts {
686+
indexes[dgst] = i
687+
}
688+
689+
out := make([]provenance.BuildStep, 0, len(dgsts))
690+
for i, dgst := range dgsts {
691+
op := *ops[dgst]
692+
inputs := make([]string, len(op.Inputs))
693+
for i, inp := range op.Inputs {
694+
inputs[i] = fmt.Sprintf("step%d:%d", indexes[inp.Digest], inp.Index)
695+
}
696+
op.Inputs = nil
697+
out = append(out, provenance.BuildStep{
698+
ID: fmt.Sprintf("step%d", i),
699+
Inputs: inputs,
700+
Op: op,
701+
})
702+
}
703+
return out, indexes, nil
704+
}
705+
706+
func walkDigests(dgsts []digest.Digest, ops map[digest.Digest]*pb.Op, dgst digest.Digest, visited map[digest.Digest]struct{}) ([]digest.Digest, error) {
707+
if _, ok := visited[dgst]; ok {
708+
return dgsts, nil
709+
}
710+
op, ok := ops[dgst]
711+
if !ok {
712+
return nil, errors.Errorf("failed to find input %v", dgst)
713+
}
714+
if op == nil {
715+
return nil, errors.Errorf("invalid nil input %v", dgst)
716+
}
717+
visited[dgst] = struct{}{}
718+
for _, inp := range op.Inputs {
719+
var err error
720+
dgsts, err = walkDigests(dgsts, ops, inp.Digest, visited)
721+
if err != nil {
722+
return nil, err
723+
}
724+
}
725+
dgsts = append(dgsts, dgst)
726+
return dgsts, nil
727+
}
Lines changed: 0 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
package provenance
22

33
import (
4-
"context"
5-
"fmt"
6-
7-
"github.com/moby/buildkit/solver"
84
"github.com/moby/buildkit/solver/pb"
95
digest "github.com/opencontainers/go-digest"
10-
"github.com/pkg/errors"
116
)
127

138
type BuildConfig struct {
@@ -33,157 +28,3 @@ type SourceInfo struct {
3328
Definition []BuildStep `json:"llbDefinition,omitempty"`
3429
DigestMapping map[digest.Digest]string `json:"digestMapping,omitempty"`
3530
}
36-
37-
func digestMap(idx map[digest.Digest]int) map[digest.Digest]string {
38-
m := map[digest.Digest]string{}
39-
for k, v := range idx {
40-
m[k] = fmt.Sprintf("step%d", v)
41-
}
42-
return m
43-
}
44-
45-
func AddBuildConfig(ctx context.Context, p *ProvenancePredicate, rp solver.ResultProxy) (map[digest.Digest]int, error) {
46-
def := rp.Definition()
47-
steps, indexes, err := toBuildSteps(def)
48-
if err != nil {
49-
return nil, err
50-
}
51-
52-
bc := &BuildConfig{
53-
Definition: steps,
54-
DigestMapping: digestMap(indexes),
55-
}
56-
57-
p.BuildConfig = bc
58-
59-
if def.Source != nil {
60-
sis := make([]SourceInfo, len(def.Source.Infos))
61-
for i, si := range def.Source.Infos {
62-
steps, indexes, err := toBuildSteps(si.Definition)
63-
if err != nil {
64-
return nil, err
65-
}
66-
s := SourceInfo{
67-
Filename: si.Filename,
68-
Data: si.Data,
69-
Language: si.Language,
70-
Definition: steps,
71-
DigestMapping: digestMap(indexes),
72-
}
73-
sis[i] = s
74-
}
75-
76-
if len(def.Source.Infos) != 0 {
77-
locs := map[string]*pb.Locations{}
78-
for k, l := range def.Source.Locations {
79-
idx, ok := indexes[digest.Digest(k)]
80-
if !ok {
81-
continue
82-
}
83-
locs[fmt.Sprintf("step%d", idx)] = l
84-
}
85-
86-
if p.Metadata == nil {
87-
p.Metadata = &ProvenanceMetadata{}
88-
}
89-
p.Metadata.BuildKitMetadata.Source = &Source{
90-
Infos: sis,
91-
Locations: locs,
92-
}
93-
}
94-
}
95-
96-
return indexes, nil
97-
}
98-
99-
func toBuildSteps(def *pb.Definition) ([]BuildStep, map[digest.Digest]int, error) {
100-
if def == nil || len(def.Def) == 0 {
101-
return nil, nil, nil
102-
}
103-
104-
ops := make(map[digest.Digest]*pb.Op)
105-
defs := make(map[digest.Digest][]byte)
106-
107-
var dgst digest.Digest
108-
for _, dt := range def.Def {
109-
var op pb.Op
110-
if err := (&op).Unmarshal(dt); err != nil {
111-
return nil, nil, errors.Wrap(err, "failed to parse llb proto op")
112-
}
113-
if src := op.GetSource(); src != nil {
114-
for k := range src.Attrs {
115-
if k == "local.session" || k == "local.unique" {
116-
delete(src.Attrs, k)
117-
}
118-
}
119-
}
120-
dgst = digest.FromBytes(dt)
121-
ops[dgst] = &op
122-
defs[dgst] = dt
123-
}
124-
125-
if dgst == "" {
126-
return nil, nil, nil
127-
}
128-
129-
// depth first backwards
130-
dgsts := make([]digest.Digest, 0, len(def.Def))
131-
op := ops[dgst]
132-
133-
if op.Op != nil {
134-
return nil, nil, errors.Errorf("invalid last vertex: %T", op.Op)
135-
}
136-
137-
if len(op.Inputs) != 1 {
138-
return nil, nil, errors.Errorf("invalid last vertex inputs: %v", len(op.Inputs))
139-
}
140-
141-
visited := map[digest.Digest]struct{}{}
142-
dgsts, err := walkDigests(dgsts, ops, dgst, visited)
143-
if err != nil {
144-
return nil, nil, err
145-
}
146-
indexes := map[digest.Digest]int{}
147-
for i, dgst := range dgsts {
148-
indexes[dgst] = i
149-
}
150-
151-
out := make([]BuildStep, 0, len(dgsts))
152-
for i, dgst := range dgsts {
153-
op := *ops[dgst]
154-
inputs := make([]string, len(op.Inputs))
155-
for i, inp := range op.Inputs {
156-
inputs[i] = fmt.Sprintf("step%d:%d", indexes[inp.Digest], inp.Index)
157-
}
158-
op.Inputs = nil
159-
out = append(out, BuildStep{
160-
ID: fmt.Sprintf("step%d", i),
161-
Inputs: inputs,
162-
Op: op,
163-
})
164-
}
165-
return out, indexes, nil
166-
}
167-
168-
func walkDigests(dgsts []digest.Digest, ops map[digest.Digest]*pb.Op, dgst digest.Digest, visited map[digest.Digest]struct{}) ([]digest.Digest, error) {
169-
if _, ok := visited[dgst]; ok {
170-
return dgsts, nil
171-
}
172-
op, ok := ops[dgst]
173-
if !ok {
174-
return nil, errors.Errorf("failed to find input %v", dgst)
175-
}
176-
if op == nil {
177-
return nil, errors.Errorf("invalid nil input %v", dgst)
178-
}
179-
visited[dgst] = struct{}{}
180-
for _, inp := range op.Inputs {
181-
var err error
182-
dgsts, err = walkDigests(dgsts, ops, inp.Digest, visited)
183-
if err != nil {
184-
return nil, err
185-
}
186-
}
187-
dgsts = append(dgsts, dgst)
188-
return dgsts, nil
189-
}

0 commit comments

Comments
 (0)