llb: force platform in llb and allow constraints

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
docker-18.09
Tonis Tiigi 2018-06-21 14:09:38 -07:00
parent 25d975ce6e
commit dc9de85069
9 changed files with 220 additions and 137 deletions

View File

@ -17,8 +17,8 @@ type Meta struct {
ProxyEnv *ProxyEnv ProxyEnv *ProxyEnv
} }
func NewExecOp(root Output, meta Meta, readOnly bool, md OpMetadata) *ExecOp { func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp {
e := &ExecOp{meta: meta, cachedOpMetadata: md} e := &ExecOp{meta: meta, constraints: c}
rootMount := &mount{ rootMount := &mount{
target: pb.RootMount, target: pb.RootMount,
source: root, source: root,
@ -48,13 +48,12 @@ type mount struct {
} }
type ExecOp struct { type ExecOp struct {
root Output MarshalCache
mounts []*mount root Output
meta Meta mounts []*mount
cachedPBDigest digest.Digest meta Meta
cachedPB []byte constraints Constraints
cachedOpMetadata OpMetadata isValidated bool
isValidated bool
} }
func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output { func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output {
@ -73,7 +72,7 @@ func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Outp
} else { } else {
m.output = &output{vertex: e, getIndex: e.getMountIndexFn(m)} m.output = &output{vertex: e, getIndex: e.getMountIndexFn(m)}
} }
e.cachedPB = nil e.Store(nil, nil, nil)
e.isValidated = false e.isValidated = false
return m.output return m.output
} }
@ -108,9 +107,9 @@ func (e *ExecOp) Validate() error {
return nil return nil
} }
func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) { func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
if e.cachedPB != nil { if e.Cached(c) {
return e.cachedPBDigest, e.cachedPB, &e.cachedOpMetadata, nil return e.Load()
} }
if err := e.Validate(); err != nil { if err := e.Validate(); err != nil {
return "", nil, nil, err return "", nil, nil, err
@ -138,10 +137,9 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
} }
} }
pop := &pb.Op{ pop, md := MarshalConstraints(c, &e.constraints)
Op: &pb.Op_Exec{ pop.Op = &pb.Op_Exec{
Exec: peo, Exec: peo,
},
} }
outIndex := 0 outIndex := 0
@ -151,7 +149,7 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
if m.tmpfs { if m.tmpfs {
return "", nil, nil, errors.Errorf("tmpfs mounts must use scratch") return "", nil, nil, errors.Errorf("tmpfs mounts must use scratch")
} }
inp, err := m.source.ToInput() inp, err := m.source.ToInput(c)
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
@ -210,9 +208,8 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
e.cachedPBDigest = digest.FromBytes(dt) e.Store(dt, md, c)
e.cachedPB = dt return e.Load()
return e.cachedPBDigest, dt, &e.cachedOpMetadata, nil
} }
func (e *ExecOp) Output() Output { func (e *ExecOp) Output() Output {
@ -376,7 +373,7 @@ func WithProxy(ps ProxyEnv) RunOption {
} }
type ExecInfo struct { type ExecInfo struct {
opMetaWrapper constraintsWrapper
State State State State
Mounts []MountInfo Mounts []MountInfo
ReadonlyRootFS bool ReadonlyRootFS bool

View File

@ -17,19 +17,20 @@ func NewBuildOp(source llb.Output, opt ...BuildOption) llb.Vertex {
for _, o := range opt { for _, o := range opt {
o(info) o(info)
} }
return &build{source: source, info: info, cachedOpMetadata: info.OpMetadata} return &build{source: source, info: info, constraints: info.Constraints}
} }
type build struct { type build struct {
source llb.Output llb.MarshalCache
info *BuildInfo source llb.Output
cachedPBDigest digest.Digest info *BuildInfo
cachedPB []byte cachedPBDigest digest.Digest
cachedOpMetadata llb.OpMetadata cachedPB []byte
constraints llb.Constraints
} }
func (b *build) ToInput() (*pb.Input, error) { func (b *build) ToInput(c *llb.Constraints) (*pb.Input, error) {
dgst, _, _, err := b.Marshal() dgst, _, _, err := b.Marshal(c)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -44,9 +45,9 @@ func (b *build) Validate() error {
return nil return nil
} }
func (b *build) Marshal() (digest.Digest, []byte, *llb.OpMetadata, error) { func (b *build) Marshal(c *llb.Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
if b.cachedPB != nil { if b.Cached(c) {
return b.cachedPBDigest, b.cachedPB, &b.cachedOpMetadata, nil return b.Load()
} }
pbo := &pb.BuildOp{ pbo := &pb.BuildOp{
Builder: pb.LLBBuilder, Builder: pb.LLBBuilder,
@ -60,13 +61,12 @@ func (b *build) Marshal() (digest.Digest, []byte, *llb.OpMetadata, error) {
pbo.Attrs[pb.AttrLLBDefinitionFilename] = b.info.DefinitionFilename pbo.Attrs[pb.AttrLLBDefinitionFilename] = b.info.DefinitionFilename
} }
pop := &pb.Op{ pop, md := llb.MarshalConstraints(c, &b.constraints)
Op: &pb.Op_Build{ pop.Op = &pb.Op_Build{
Build: pbo, Build: pbo,
},
} }
inp, err := b.source.ToInput() inp, err := b.source.ToInput(c)
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
@ -77,9 +77,8 @@ func (b *build) Marshal() (digest.Digest, []byte, *llb.OpMetadata, error) {
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
b.cachedPB = dt b.Store(dt, md, c)
b.cachedPBDigest = digest.FromBytes(dt) return b.Load()
return b.cachedPBDigest, dt, &b.cachedOpMetadata, nil
} }
func (b *build) Output() llb.Output { func (b *build) Output() llb.Output {
@ -91,7 +90,7 @@ func (b *build) Inputs() []llb.Output {
} }
type BuildInfo struct { type BuildInfo struct {
llb.OpMetadata llb.Constraints
DefinitionFilename string DefinitionFilename string
} }
@ -103,8 +102,8 @@ func WithFilename(fn string) BuildOption {
} }
} }
func WithMetadata(md llb.MetadataOpt) BuildOption { func WithConstraints(co llb.ConstraintsOpt) BuildOption {
return func(b *BuildInfo) { return func(b *BuildInfo) {
md.SetMetadataOption(&b.OpMetadata) co.SetConstraintsOption(&b.Constraints)
} }
} }

View File

@ -12,7 +12,7 @@ import (
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
t.Parallel() t.Parallel()
b := NewBuildOp(newDummyOutput("foobar"), WithFilename("myfilename")) b := NewBuildOp(newDummyOutput("foobar"), WithFilename("myfilename"))
dgst, dt, opMeta, err := b.Marshal() dgst, dt, opMeta, err := b.Marshal(&llb.Constraints{})
_ = opMeta _ = opMeta
require.NoError(t, err) require.NoError(t, err)
@ -42,7 +42,7 @@ type dummyOutput struct {
dgst digest.Digest dgst digest.Digest
} }
func (d *dummyOutput) ToInput() (*pb.Input, error) { func (d *dummyOutput) ToInput(*llb.Constraints) (*pb.Input, error) {
return &pb.Input{ return &pb.Input{
Digest: d.dgst, Digest: d.dgst,
Index: pb.OutputIndex(7), // random constant Index: pb.OutputIndex(7), // random constant

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"github.com/containerd/containerd/platforms"
"github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
) )
@ -12,11 +13,11 @@ import (
// Corresponds to the Definition structure defined in solver/pb.Definition. // Corresponds to the Definition structure defined in solver/pb.Definition.
type Definition struct { type Definition struct {
Def [][]byte Def [][]byte
Metadata map[digest.Digest]OpMetadata Metadata map[digest.Digest]pb.OpMetadata
} }
func (def *Definition) ToPB() *pb.Definition { func (def *Definition) ToPB() *pb.Definition {
md := make(map[digest.Digest]OpMetadata) md := make(map[digest.Digest]pb.OpMetadata)
for k, v := range def.Metadata { for k, v := range def.Metadata {
md[k] = v md[k] = v
} }
@ -28,14 +29,12 @@ func (def *Definition) ToPB() *pb.Definition {
func (def *Definition) FromPB(x *pb.Definition) { func (def *Definition) FromPB(x *pb.Definition) {
def.Def = x.Def def.Def = x.Def
def.Metadata = make(map[digest.Digest]OpMetadata) def.Metadata = make(map[digest.Digest]pb.OpMetadata)
for k, v := range x.Metadata { for k, v := range x.Metadata {
def.Metadata[k] = v def.Metadata[k] = v
} }
} }
type OpMetadata = pb.OpMetadata
func WriteTo(def *Definition, w io.Writer) error { func WriteTo(def *Definition, w io.Writer) error {
b, err := def.ToPB().Marshal() b, err := def.ToPB().Marshal()
if err != nil { if err != nil {
@ -58,3 +57,56 @@ func ReadFrom(r io.Reader) (*Definition, error) {
def.FromPB(&pbDef) def.FromPB(&pbDef)
return &def, nil return &def, nil
} }
func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) {
c := base
c.WorkerConstraints = append([]string{}, c.WorkerConstraints...)
if p := override.Platform; p != nil {
c.Platform = p
}
for _, wc := range override.WorkerConstraints {
c.WorkerConstraints = append(c.WorkerConstraints, wc)
}
c.Metadata = mergeMetadata(c.Metadata, override.Metadata)
if c.Platform == nil {
defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
c.Platform = &defaultPlatform
}
return &pb.Op{
Platform: &pb.Platform{
OS: c.Platform.OS,
Architecture: c.Platform.Architecture,
Variant: c.Platform.Variant,
OSVersion: c.Platform.OSVersion,
OSFeatures: c.Platform.OSFeatures,
},
Constraints: &pb.WorkerConstraints{
Filter: c.WorkerConstraints,
},
}, &c.Metadata
}
type MarshalCache struct {
digest digest.Digest
dt []byte
md *pb.OpMetadata
constraints *Constraints
}
func (mc *MarshalCache) Cached(c *Constraints) bool {
return mc.dt != nil && mc.constraints == c
}
func (mc *MarshalCache) Load() (digest.Digest, []byte, *pb.OpMetadata, error) {
return mc.digest, mc.dt, mc.md, nil
}
func (mc *MarshalCache) Store(dt []byte, md *pb.OpMetadata, c *Constraints) {
mc.digest = digest.FromBytes(dt)
mc.dt = dt
mc.md = md
mc.constraints = c
}

View File

@ -15,20 +15,19 @@ import (
) )
type SourceOp struct { type SourceOp struct {
id string MarshalCache
attrs map[string]string id string
output Output attrs map[string]string
cachedPBDigest digest.Digest output Output
cachedPB []byte constraints Constraints
cachedOpMetadata OpMetadata err error
err error
} }
func NewSource(id string, attrs map[string]string, md OpMetadata) *SourceOp { func NewSource(id string, attrs map[string]string, c Constraints) *SourceOp {
s := &SourceOp{ s := &SourceOp{
id: id, id: id,
attrs: attrs, attrs: attrs,
cachedOpMetadata: md, constraints: c,
} }
s.output = &output{vertex: s} s.output = &output{vertex: s}
return s return s
@ -44,26 +43,26 @@ func (s *SourceOp) Validate() error {
return nil return nil
} }
func (s *SourceOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) { func (s *SourceOp) Marshal(constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
if s.cachedPB != nil { if s.Cached(constraints) {
return s.cachedPBDigest, s.cachedPB, &s.cachedOpMetadata, nil return s.Load()
} }
if err := s.Validate(); err != nil { if err := s.Validate(); err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
proto := &pb.Op{ proto, md := MarshalConstraints(constraints, &s.constraints)
Op: &pb.Op_Source{
Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs}, proto.Op = &pb.Op_Source{
}, Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
} }
dt, err := proto.Marshal() dt, err := proto.Marshal()
if err != nil { if err != nil {
return "", nil, nil, err return "", nil, nil, err
} }
s.cachedPB = dt
s.cachedPBDigest = digest.FromBytes(dt) s.Store(dt, md, constraints)
return s.cachedPBDigest, dt, &s.cachedOpMetadata, nil return s.Load()
} }
func (s *SourceOp) Output() Output { func (s *SourceOp) Output() Output {
@ -74,10 +73,6 @@ func (s *SourceOp) Inputs() []Output {
return nil return nil
} }
func Source(id string) State {
return NewState(NewSource(id, nil, OpMetadata{}).Output())
}
func Image(ref string, opts ...ImageOption) State { func Image(ref string, opts ...ImageOption) State {
r, err := reference.ParseNormalizedNamed(ref) r, err := reference.ParseNormalizedNamed(ref)
if err == nil { if err == nil {
@ -136,7 +131,7 @@ func (fn ImageOptionFunc) SetImageOption(ii *ImageInfo) {
} }
type ImageInfo struct { type ImageInfo struct {
opMetaWrapper constraintsWrapper
metaResolver ImageMetaResolver metaResolver ImageMetaResolver
} }
@ -183,7 +178,7 @@ func (fn gitOptionFunc) SetGitOption(gi *GitInfo) {
} }
type GitInfo struct { type GitInfo struct {
opMetaWrapper constraintsWrapper
KeepGitDir bool KeepGitDir bool
} }
@ -280,7 +275,7 @@ func SharedKeyHint(h string) LocalOption {
} }
type LocalInfo struct { type LocalInfo struct {
opMetaWrapper constraintsWrapper
SessionID string SessionID string
IncludePatterns string IncludePatterns string
ExcludePatterns string ExcludePatterns string
@ -315,7 +310,7 @@ func HTTP(url string, opts ...HTTPOption) State {
} }
type HTTPInfo struct { type HTTPInfo struct {
opMetaWrapper constraintsWrapper
Checksum digest.Digest Checksum digest.Digest
Filename string Filename string
Perm int Perm int

View File

@ -3,21 +3,23 @@ package llb
import ( import (
"context" "context"
"github.com/containerd/containerd/platforms"
"github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/system" "github.com/moby/buildkit/util/system"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go/v1"
) )
type StateOption func(State) State type StateOption func(State) State
type Output interface { type Output interface {
ToInput() (*pb.Input, error) ToInput(*Constraints) (*pb.Input, error)
Vertex() Vertex Vertex() Vertex
} }
type Vertex interface { type Vertex interface {
Validate() error Validate() error
Marshal() (digest.Digest, []byte, *OpMetadata, error) Marshal(*Constraints) (digest.Digest, []byte, *pb.OpMetadata, error)
Output() Output Output() Output
Inputs() []Output Inputs() []Output
} }
@ -48,18 +50,27 @@ func (s State) Value(k interface{}) interface{} {
return s.ctx.Value(k) return s.ctx.Value(k)
} }
func (s State) Marshal(md ...MetadataOpt) (*Definition, error) { func (s State) Marshal(co ...ConstraintsOpt) (*Definition, error) {
def := &Definition{ def := &Definition{
Metadata: make(map[digest.Digest]OpMetadata, 0), Metadata: make(map[digest.Digest]pb.OpMetadata, 0),
} }
if s.Output() == nil { if s.Output() == nil {
return def, nil return def, nil
} }
def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, md)
defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
c := &Constraints{
Platform: &defaultPlatform,
}
for _, o := range co {
o.SetConstraintsOption(c)
}
def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, c)
if err != nil { if err != nil {
return def, err return def, err
} }
inp, err := s.Output().ToInput() inp, err := s.Output().ToInput(c)
if err != nil { if err != nil {
return def, err return def, err
} }
@ -72,29 +83,25 @@ func (s State) Marshal(md ...MetadataOpt) (*Definition, error) {
return def, nil return def, nil
} }
func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, md []MetadataOpt) (*Definition, error) { func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, c *Constraints) (*Definition, error) {
if _, ok := vertexCache[v]; ok { if _, ok := vertexCache[v]; ok {
return def, nil return def, nil
} }
for _, inp := range v.Inputs() { for _, inp := range v.Inputs() {
var err error var err error
def, err = marshal(inp.Vertex(), def, cache, vertexCache, md) def, err = marshal(inp.Vertex(), def, cache, vertexCache, c)
if err != nil { if err != nil {
return def, err return def, err
} }
} }
dgst, dt, opMeta, err := v.Marshal() dgst, dt, opMeta, err := v.Marshal(c)
if err != nil { if err != nil {
return def, err return def, err
} }
vertexCache[v] = struct{}{} vertexCache[v] = struct{}{}
if opMeta != nil { if opMeta != nil {
m := mergeMetadata(def.Metadata[dgst], *opMeta) def.Metadata[dgst] = mergeMetadata(def.Metadata[dgst], *opMeta)
for _, f := range md {
f.SetMetadataOption(&m)
}
def.Metadata[dgst] = m
} }
if _, ok := cache[dgst]; ok { if _, ok := cache[dgst]; ok {
return def, nil return def, nil
@ -191,7 +198,7 @@ type output struct {
err error err error
} }
func (o *output) ToInput() (*pb.Input, error) { func (o *output) ToInput(c *Constraints) (*pb.Input, error) {
if o.err != nil { if o.err != nil {
return nil, o.err return nil, o.err
} }
@ -203,7 +210,7 @@ func (o *output) ToInput() (*pb.Input, error) {
return nil, err return nil, err
} }
} }
dgst, _, _, err := o.vertex.Marshal() dgst, _, _, err := o.vertex.Marshal(c)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -214,8 +221,8 @@ func (o *output) Vertex() Vertex {
return o.vertex return o.vertex
} }
type MetadataOpt interface { type ConstraintsOpt interface {
SetMetadataOption(*OpMetadata) SetConstraintsOption(*Constraints)
RunOption RunOption
LocalOption LocalOption
HTTPOption HTTPOption
@ -223,33 +230,33 @@ type MetadataOpt interface {
GitOption GitOption
} }
type metadataOptFunc func(m *OpMetadata) type constraintsOptFunc func(m *Constraints)
func (fn metadataOptFunc) SetMetadataOption(m *OpMetadata) { func (fn constraintsOptFunc) SetConstraintsOption(m *Constraints) {
fn(m) fn(m)
} }
func (fn metadataOptFunc) SetRunOption(ei *ExecInfo) { func (fn constraintsOptFunc) SetRunOption(ei *ExecInfo) {
ei.ApplyMetadata(fn) ei.applyConstraints(fn)
} }
func (fn metadataOptFunc) SetLocalOption(li *LocalInfo) { func (fn constraintsOptFunc) SetLocalOption(li *LocalInfo) {
li.ApplyMetadata(fn) li.applyConstraints(fn)
} }
func (fn metadataOptFunc) SetHTTPOption(hi *HTTPInfo) { func (fn constraintsOptFunc) SetHTTPOption(hi *HTTPInfo) {
hi.ApplyMetadata(fn) hi.applyConstraints(fn)
} }
func (fn metadataOptFunc) SetImageOption(ii *ImageInfo) { func (fn constraintsOptFunc) SetImageOption(ii *ImageInfo) {
ii.ApplyMetadata(fn) ii.applyConstraints(fn)
} }
func (fn metadataOptFunc) SetGitOption(gi *GitInfo) { func (fn constraintsOptFunc) SetGitOption(gi *GitInfo) {
gi.ApplyMetadata(fn) gi.applyConstraints(fn)
} }
func mergeMetadata(m1, m2 OpMetadata) OpMetadata { func mergeMetadata(m1, m2 pb.OpMetadata) pb.OpMetadata {
if m2.IgnoreCache { if m2.IgnoreCache {
m1.IgnoreCache = true m1.IgnoreCache = true
} }
@ -268,49 +275,81 @@ func mergeMetadata(m1, m2 OpMetadata) OpMetadata {
return m1 return m1
} }
var IgnoreCache = metadataOptFunc(func(md *OpMetadata) { var IgnoreCache = constraintsOptFunc(func(c *Constraints) {
md.IgnoreCache = true c.Metadata.IgnoreCache = true
}) })
func WithDescription(m map[string]string) MetadataOpt { func WithDescription(m map[string]string) ConstraintsOpt {
return metadataOptFunc(func(md *OpMetadata) { return constraintsOptFunc(func(c *Constraints) {
md.Description = m c.Metadata.Description = m
}) })
} }
// WithExportCache forces results for this vertex to be exported with the cache // WithExportCache forces results for this vertex to be exported with the cache
func WithExportCache() MetadataOpt { func WithExportCache() ConstraintsOpt {
return metadataOptFunc(func(md *OpMetadata) { return constraintsOptFunc(func(c *Constraints) {
md.ExportCache = &pb.ExportCache{Value: true} c.Metadata.ExportCache = &pb.ExportCache{Value: true}
}) })
} }
// WithoutExportCache sets results for this vertex to be not exported with // WithoutExportCache sets results for this vertex to be not exported with
// the cache // the cache
func WithoutExportCache() MetadataOpt { func WithoutExportCache() ConstraintsOpt {
return metadataOptFunc(func(md *OpMetadata) { return constraintsOptFunc(func(c *Constraints) {
// ExportCache with value false means to disable exporting // ExportCache with value false means to disable exporting
md.ExportCache = &pb.ExportCache{Value: false} c.Metadata.ExportCache = &pb.ExportCache{Value: false}
}) })
} }
// WithoutDefaultExportCache resets the cache export for the vertex to use // WithoutDefaultExportCache resets the cache export for the vertex to use
// the default defined by the build configuration. // the default defined by the build configuration.
func WithoutDefaultExportCache() MetadataOpt { func WithoutDefaultExportCache() ConstraintsOpt {
return metadataOptFunc(func(md *OpMetadata) { return constraintsOptFunc(func(c *Constraints) {
// nil means no vertex based config has been set // nil means no vertex based config has been set
md.ExportCache = nil c.Metadata.ExportCache = nil
}) })
} }
type opMetaWrapper struct { type constraintsWrapper struct {
OpMetadata Constraints
} }
func (mw *opMetaWrapper) ApplyMetadata(f func(m *OpMetadata)) { func (cw *constraintsWrapper) applyConstraints(f func(c *Constraints)) {
f(&mw.OpMetadata) f(&cw.Constraints)
} }
func (mw *opMetaWrapper) Metadata() OpMetadata { func (cw *constraintsWrapper) Metadata() Constraints {
return mw.OpMetadata return cw.Constraints
}
type Constraints struct {
Platform *specs.Platform
WorkerConstraints []string
Metadata pb.OpMetadata
}
func Platform(p specs.Platform) ConstraintsOpt {
return constraintsOptFunc(func(c *Constraints) {
c.Platform = &p
})
}
var (
LinuxAmd64 = Platform(specs.Platform{OS: "linux", Architecture: "amd64"})
LinuxArmhf = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v7"})
LinuxArm = LinuxArmhf
LinuxArmel = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v6"})
LinuxArm64 = Platform(specs.Platform{OS: "linux", Architecture: "arm64"})
LinuxS390x = Platform(specs.Platform{OS: "linux", Architecture: "s390x"})
LinuxPpc64le = Platform(specs.Platform{OS: "linux", Architecture: "ppc64le"})
Darwin = Platform(specs.Platform{OS: "darwin", Architecture: "amd64"})
Windows = Platform(specs.Platform{OS: "windows", Architecture: "amd64"})
)
func Require(filters ...string) ConstraintsOpt {
return constraintsOptFunc(func(c *Constraints) {
for _, f := range filters {
c.WorkerConstraints = append(c.WorkerConstraints, f)
}
})
} }

View File

@ -9,7 +9,7 @@ import (
func TestStateMeta(t *testing.T) { func TestStateMeta(t *testing.T) {
t.Parallel() t.Parallel()
s := Source("foo") s := Image("foo")
s = s.AddEnv("BAR", "abc").Dir("/foo/bar") s = s.AddEnv("BAR", "abc").Dir("/foo/bar")
v, ok := s.GetEnv("BAR") v, ok := s.GetEnv("BAR")
@ -18,7 +18,7 @@ func TestStateMeta(t *testing.T) {
assert.Equal(t, "/foo/bar", s.GetDir()) assert.Equal(t, "/foo/bar", s.GetDir())
s2 := Source("foo2") s2 := Image("foo2")
s2 = s2.AddEnv("BAZ", "def").Reset(s) s2 = s2.AddEnv("BAZ", "def").Reset(s)
_, ok = s2.GetEnv("BAZ") _, ok = s2.GetEnv("BAZ")

View File

@ -87,10 +87,11 @@ func read(r io.Reader, clicontext *cli.Context) (*llb.Definition, error) {
dgst := digest.FromBytes(dt) dgst := digest.FromBytes(dt)
opMetadata, ok := def.Metadata[dgst] opMetadata, ok := def.Metadata[dgst]
if !ok { if !ok {
opMetadata = llb.OpMetadata{} opMetadata = pb.OpMetadata{}
} }
llb.IgnoreCache(&opMetadata) c := llb.Constraints{Metadata: opMetadata}
def.Metadata[dgst] = opMetadata llb.IgnoreCache(&c)
def.Metadata[dgst] = c.Metadata
} }
} }
return def, nil return def, nil

View File

@ -771,7 +771,7 @@ func getArgValue(arg instructions.ArgCommand) string {
return v return v
} }
func dfCmd(cmd interface{}) llb.MetadataOpt { func dfCmd(cmd interface{}) llb.ConstraintsOpt {
// TODO: add fmt.Stringer to instructions.Command to remove interface{} // TODO: add fmt.Stringer to instructions.Command to remove interface{}
var cmdStr string var cmdStr string
if cmd, ok := cmd.(fmt.Stringer); ok { if cmd, ok := cmd.(fmt.Stringer); ok {