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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
package ops
import (
"context"
"encoding/json"
"github.com/moby/buildkit/worker"
"github.com/pkg/errors"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/solver/llbsolver/ops/opsutils"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
)
const diffCacheType = "buildkit.diff.v0"
type diffOp struct {
op *pb.DiffOp
worker worker.Worker
vtx solver.Vertex
}
func NewDiffOp(v solver.Vertex, op *pb.Op_Diff, w worker.Worker) (solver.Op, error) {
if err := opsutils.Validate(&pb.Op{Op: op}); err != nil {
return nil, err
}
return &diffOp{
op: op.Diff,
worker: w,
vtx: v,
}, nil
}
func (d *diffOp) CacheMap(ctx context.Context, group session.Group, index int) (*solver.CacheMap, bool, error) {
dt, err := json.Marshal(struct {
Type string
Diff *pb.DiffOp
}{
Type: diffCacheType,
Diff: d.op,
})
if err != nil {
return nil, false, err
}
var depCount int
if d.op.Lower.Input != pb.Empty {
depCount++
}
if d.op.Upper.Input != pb.Empty {
depCount++
}
cm := &solver.CacheMap{
Digest: digest.FromBytes(dt),
Deps: make([]struct {
Selector digest.Digest
ComputeDigestFunc solver.ResultBasedCacheFunc
PreprocessFunc solver.PreprocessFunc
}, depCount),
}
return cm, true, nil
}
func (d *diffOp) Exec(ctx context.Context, g session.Group, inputs []solver.Result) ([]solver.Result, error) {
var curInput int
var lowerRef cache.ImmutableRef
if d.op.Lower.Input != pb.Empty {
if lowerInp := inputs[curInput]; lowerInp != nil {
wref, ok := lowerInp.Sys().(*worker.WorkerRef)
if !ok {
return nil, errors.Errorf("invalid lower reference for diff op %T", lowerInp.Sys())
}
lowerRef = wref.ImmutableRef
} else {
return nil, errors.New("invalid nil lower input for diff op")
}
curInput++
}
var upperRef cache.ImmutableRef
if d.op.Upper.Input != pb.Empty {
if upperInp := inputs[curInput]; upperInp != nil {
wref, ok := upperInp.Sys().(*worker.WorkerRef)
if !ok {
return nil, errors.Errorf("invalid upper reference for diff op %T", upperInp.Sys())
}
upperRef = wref.ImmutableRef
} else {
return nil, errors.New("invalid nil upper input for diff op")
}
}
if lowerRef == nil {
if upperRef == nil {
// The diff of nothing and nothing is nothing. Just return an empty ref.
return []solver.Result{worker.NewWorkerRefResult(nil, d.worker)}, nil
}
// The diff of nothing and upper is upper. Just return a clone of upper
return []solver.Result{worker.NewWorkerRefResult(upperRef.Clone(), d.worker)}, nil
}
if upperRef != nil && lowerRef.ID() == upperRef.ID() {
// The diff of a ref and itself is nothing, return an empty ref.
return []solver.Result{worker.NewWorkerRefResult(nil, d.worker)}, nil
}
diffRef, err := d.worker.CacheManager().Diff(ctx, lowerRef, upperRef, solver.ProgressControllerFromContext(ctx),
cache.WithDescription(d.vtx.Name()))
if err != nil {
return nil, err
}
return []solver.Result{worker.NewWorkerRefResult(diffRef, d.worker)}, nil
}
func (d *diffOp) Acquire(ctx context.Context) (release solver.ReleaseFunc, err error) {
return func() {}, nil
}
|