Jonathan A. Sternberg 8fb1157b5f
vendor: github.com/moby/buildkit v0.21.0-rc1
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-04-09 10:28:03 -05:00

170 lines
3.9 KiB
Go

package llb
import (
"io"
"slices"
"sync"
cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/platforms"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
"google.golang.org/protobuf/proto"
)
// Definition is the LLB definition structure with per-vertex metadata entries
// Corresponds to the Definition structure defined in solver/pb.Definition.
type Definition struct {
Def [][]byte
Metadata map[digest.Digest]OpMetadata
Source *pb.Source
Constraints *Constraints
}
func (def *Definition) ToPB() *pb.Definition {
metas := make(map[string]*pb.OpMetadata, len(def.Metadata))
for dgst, meta := range def.Metadata {
metas[string(dgst)] = meta.ToPB()
}
return &pb.Definition{
Def: def.Def,
Source: def.Source,
Metadata: metas,
}
}
func (def *Definition) FromPB(x *pb.Definition) {
def.Def = x.Def
def.Source = x.Source
def.Metadata = make(map[digest.Digest]OpMetadata, len(x.Metadata))
for dgst, meta := range x.Metadata {
def.Metadata[digest.Digest(dgst)] = NewOpMetadata(meta)
}
}
func (def *Definition) Head() (digest.Digest, error) {
if len(def.Def) == 0 {
return "", nil
}
last := def.Def[len(def.Def)-1]
var pop pb.Op
if err := pop.UnmarshalVT(last); err != nil {
return "", err
}
if len(pop.Inputs) == 0 {
return "", nil
}
return digest.Digest(pop.Inputs[0].Digest), nil
}
func WriteTo(def *Definition, w io.Writer) error {
b, err := def.ToPB().Marshal()
if err != nil {
return err
}
_, err = w.Write(b)
return err
}
func ReadFrom(r io.Reader) (*Definition, error) {
b, err := io.ReadAll(r)
if err != nil {
return nil, err
}
var pbDef pb.Definition
if err := pbDef.UnmarshalVT(b); err != nil {
return nil, err
}
var def Definition
def.FromPB(&pbDef)
return &def, nil
}
func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) {
c := *base
c.WorkerConstraints = slices.Clone(c.WorkerConstraints)
if p := override.Platform; p != nil {
c.Platform = p
}
c.WorkerConstraints = append(c.WorkerConstraints, override.WorkerConstraints...)
c.Metadata = mergeMetadata(c.Metadata, override.Metadata)
if c.Platform == nil {
defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
c.Platform = &defaultPlatform
}
opPlatform := pb.Platform{
OS: c.Platform.OS,
Architecture: c.Platform.Architecture,
Variant: c.Platform.Variant,
OSVersion: c.Platform.OSVersion,
}
if c.Platform.OSFeatures != nil {
opPlatform.OSFeatures = slices.Clone(c.Platform.OSFeatures)
}
return &pb.Op{
Platform: &opPlatform,
Constraints: &pb.WorkerConstraints{
Filter: c.WorkerConstraints,
},
}, c.Metadata.ToPB()
}
type MarshalCache struct {
mu sync.Mutex
cache map[*Constraints]*marshalCacheResult
}
type MarshalCacheInstance struct {
*MarshalCache
}
func (mc *MarshalCache) Acquire() *MarshalCacheInstance {
mc.mu.Lock()
return &MarshalCacheInstance{mc}
}
func (mc *MarshalCacheInstance) Load(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
res, ok := mc.cache[c]
if !ok {
return "", nil, nil, nil, cerrdefs.ErrNotFound
}
return res.digest, res.dt, res.md, res.srcs, nil
}
func (mc *MarshalCacheInstance) Store(dt []byte, md *pb.OpMetadata, srcs []*SourceLocation, c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
res := &marshalCacheResult{
digest: digest.FromBytes(dt),
dt: dt,
md: md,
srcs: srcs,
}
if mc.cache == nil {
mc.cache = make(map[*Constraints]*marshalCacheResult)
}
mc.cache[c] = res
return res.digest, res.dt, res.md, res.srcs, nil
}
func (mc *MarshalCacheInstance) Release() {
mc.mu.Unlock()
}
type marshalCacheResult struct {
digest digest.Digest
dt []byte
md *pb.OpMetadata
srcs []*SourceLocation
}
func deterministicMarshal[Message proto.Message](m Message) ([]byte, error) {
return proto.MarshalOptions{Deterministic: true}.Marshal(m)
}