llb: force platform in llb and allow constraints
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
25d975ce6e
commit
dc9de85069
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue