vendor: update buildkit to master@31c870e82a48

Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
Justin Chadwell
2023-05-15 18:32:31 +01:00
parent 167cd16acb
commit e61a8cf637
269 changed files with 25798 additions and 3371 deletions

View File

@ -24,7 +24,7 @@ type DefinitionOp struct {
platforms map[digest.Digest]*ocispecs.Platform
dgst digest.Digest
index pb.OutputIndex
inputCache map[digest.Digest][]*DefinitionOp
inputCache *sync.Map // shared and written among DefinitionOps so avoid race on this map using sync.Map
}
// NewDefinitionOp returns a new operation from a marshalled definition.
@ -101,7 +101,7 @@ func NewDefinitionOp(def *pb.Definition) (*DefinitionOp, error) {
platforms: platforms,
dgst: dgst,
index: index,
inputCache: make(map[digest.Digest][]*DefinitionOp),
inputCache: new(sync.Map),
}, nil
}
@ -180,6 +180,18 @@ func (d *DefinitionOp) Output() Output {
}}
}
func (d *DefinitionOp) loadInputCache(dgst digest.Digest) ([]*DefinitionOp, bool) {
a, ok := d.inputCache.Load(dgst.String())
if ok {
return a.([]*DefinitionOp), true
}
return nil, false
}
func (d *DefinitionOp) storeInputCache(dgst digest.Digest, c []*DefinitionOp) {
d.inputCache.Store(dgst.String(), c)
}
func (d *DefinitionOp) Inputs() []Output {
if d.dgst == "" {
return nil
@ -195,7 +207,7 @@ func (d *DefinitionOp) Inputs() []Output {
for _, input := range op.Inputs {
var vtx *DefinitionOp
d.mu.Lock()
if existingIndexes, ok := d.inputCache[input.Digest]; ok {
if existingIndexes, ok := d.loadInputCache(input.Digest); ok {
if int(input.Index) < len(existingIndexes) && existingIndexes[input.Index] != nil {
vtx = existingIndexes[input.Index]
}
@ -211,14 +223,14 @@ func (d *DefinitionOp) Inputs() []Output {
inputCache: d.inputCache,
sources: d.sources,
}
existingIndexes := d.inputCache[input.Digest]
existingIndexes, _ := d.loadInputCache(input.Digest)
indexDiff := int(input.Index) - len(existingIndexes)
if indexDiff >= 0 {
// make room in the slice for the new index being set
existingIndexes = append(existingIndexes, make([]*DefinitionOp, indexDiff+1)...)
}
existingIndexes[input.Index] = vtx
d.inputCache[input.Digest] = existingIndexes
d.storeInputCache(input.Digest, existingIndexes)
}
d.mu.Unlock()

View File

@ -90,6 +90,8 @@ func (m *DiffOp) Inputs() (out []Output) {
return out
}
// Diff returns a state that represents the diff of the lower and upper states.
// The returned State is useful for use with [Merge] where you can merge the lower state with the diff.
func Diff(lower, upper State, opts ...ConstraintsOpt) State {
if lower.Output() == nil {
if upper.Output() == nil {

View File

@ -649,6 +649,7 @@ type SSHInfo struct {
Optional bool
}
// AddSecret is a RunOption that adds a secret to the exec.
func AddSecret(dest string, opts ...SecretOption) RunOption {
return runOptionFunc(func(ei *ExecInfo) {
s := &SecretInfo{ID: dest, Target: dest, Mode: 0400}
@ -696,6 +697,7 @@ func SecretAsEnv(v bool) SecretOption {
})
}
// SecretFileOpt sets the secret's target file uid, gid and permissions.
func SecretFileOpt(uid, gid, mode int) SecretOption {
return secretOptionFunc(func(si *SecretInfo) {
si.UID = uid
@ -704,12 +706,15 @@ func SecretFileOpt(uid, gid, mode int) SecretOption {
})
}
// ReadonlyRootFS sets the execs's root filesystem to be read-only.
func ReadonlyRootFS() RunOption {
return runOptionFunc(func(ei *ExecInfo) {
ei.ReadonlyRootFS = true
})
}
// WithProxy is a RunOption that sets the proxy environment variables in the resulting exec.
// For example `HTTP_PROXY` is a standard environment variable for unix systems that programs may read.
func WithProxy(ps ProxyEnv) RunOption {
return runOptionFunc(func(ei *ExecInfo) {
ei.ProxyEnv = &ps

View File

@ -48,6 +48,7 @@ func NewFileOp(s State, action *FileAction, c Constraints) *FileOp {
}
// CopyInput is either llb.State or *FileActionWithState
// It is used by [Copy] to to specify the source of the copy operation.
type CopyInput interface {
isFileOpCopyInput()
}
@ -131,6 +132,10 @@ type fileActionWithState struct {
func (fas *fileActionWithState) isFileOpCopyInput() {}
// Mkdir creates a FileAction which creates a directory at the given path.
// Example:
//
// llb.Scratch().File(llb.Mkdir("/foo", 0755))
func Mkdir(p string, m os.FileMode, opt ...MkdirOption) *FileAction {
var mi MkdirInfo
for _, o := range opt {
@ -181,6 +186,7 @@ func (fn mkdirOptionFunc) SetMkdirOption(mi *MkdirInfo) {
var _ MkdirOption = &MkdirInfo{}
// WithParents is an option for Mkdir which creates parent directories if they do not exist.
func WithParents(b bool) MkdirOption {
return mkdirOptionFunc(func(mi *MkdirInfo) {
mi.MakeParents = b
@ -282,6 +288,10 @@ func (up *UserOpt) marshal(base pb.InputIndex) *pb.UserOpt {
return &pb.UserOpt{User: &pb.UserOpt_ByID{ByID: uint32(up.UID)}}
}
// Mkfile creates a FileAction which creates a file at the given path with the provided contents.
// Example:
//
// llb.Scratch().File(llb.Mkfile("/foo", 0644, []byte("hello world!")))
func Mkfile(p string, m os.FileMode, dt []byte, opts ...MkfileOption) *FileAction {
var mi MkfileInfo
for _, o := range opts {
@ -332,6 +342,10 @@ func (a *fileActionMkfile) toProtoAction(ctx context.Context, parent string, bas
}, nil
}
// Rm creates a FileAction which removes a file or directory at the given path.
// Example:
//
// llb.Scratch().File(Mkfile("/foo", 0644, []byte("not around for long..."))).File(llb.Rm("/foo"))
func Rm(p string, opts ...RmOption) *FileAction {
var mi RmInfo
for _, o := range opts {
@ -394,6 +408,25 @@ func (a *fileActionRm) toProtoAction(ctx context.Context, parent string, base pb
}, nil
}
// Copy produces a FileAction which copies a file or directory from the source to the destination.
// The "input" parameter is the contents to copy from.
// "src" is the path to copy from within the "input".
// "dest" is the path to copy to within the destination (the state being operated on).
// See [CopyInput] for the valid types of input.
//
// Example:
//
// st := llb.Local(".")
// llb.Scratch().File(llb.Copy(st, "/foo", "/bar"))
//
// The example copies the local (client) directory "./foo" to a new empty directory at /bar.
//
// Note: Copying directories can have different behavior based on if the destination exists or not.
// When the destination already exists, the contents of the source directory is copied underneath the destination, including the directory itself.
// You may need to supply a copy option to copy the dir contents only.
// You may also need to pass in a [CopyOption] which creates parent directories if they do not exist.
//
// See [CopyOption] for more details on what options are available.
func Copy(input CopyInput, src, dest string, opts ...CopyOption) *FileAction {
var state *State
var fas *fileActionWithState

View File

@ -70,6 +70,31 @@ func (m *MergeOp) Inputs() []Output {
return m.inputs
}
// Merge merges multiple states into a single state. This is useful in
// conjunction with [Diff] to create set of patches which are independent of
// each other to a base state without affecting the cache of other merged
// states.
// As an example, lets say you have a rootfs with the following directories:
//
// / /bin /etc /opt /tmp
//
// Now lets say you want to copy a directory /etc/foo from one state and a
// binary /bin/bar from another state.
// [Copy] makes a duplicate of file on top of another directory.
// Merge creates a directory whose contents is an overlay of 2 states on top of each other.
//
// With "Merge" you can do this:
//
// fooState := Diff(rootfs, fooState)
// barState := Diff(rootfs, barState)
//
// Then merge the results with:
//
// Merge(rootfs, fooDiff, barDiff)
//
// The resulting state will have both /etc/foo and /bin/bar, but because Merge
// was used, changing the contents of "fooDiff" does not require copying
// "barDiff" again.
func Merge(inputs []State, opts ...ConstraintsOpt) State {
// filter out any scratch inputs, which have no effect when merged
var filteredInputs []State

View File

@ -91,6 +91,10 @@ func (s *SourceOp) Inputs() []Output {
return nil
}
// Image returns a state that represents a docker image in a registry.
// Example:
//
// st := llb.Image("busybox:latest")
func Image(ref string, opts ...ImageOption) State {
r, err := reference.ParseNormalizedNamed(ref)
if err == nil {
@ -215,6 +219,17 @@ type ImageInfo struct {
RecordType string
}
// Git returns a state that represents a git repository.
// Example:
//
// st := llb.Git("https://github.com/moby/buildkit.git#v0.11.6")
//
// The example fetches the v0.11.6 tag of the buildkit repository.
// You can also use a commit hash or a branch name.
//
// Other URL formats are supported such as "git@github.com:moby/buildkit.git", "git://...", "ssh://..."
// Formats that utilize SSH may need to supply credentials as a [GitOption].
// You may need to check the source code for a full list of supported formats.
func Git(remote, ref string, opts ...GitOption) State {
url := strings.Split(remote, "#")[0]
@ -346,10 +361,12 @@ func MountSSHSock(sshID string) GitOption {
})
}
// Scratch returns a state that represents an empty filesystem.
func Scratch() State {
return NewState(nil)
}
// Local returns a state that represents a directory local to the client.
func Local(name string, opts ...LocalOption) State {
gi := &LocalInfo{}

View File

@ -7,6 +7,16 @@ import (
digest "github.com/opencontainers/go-digest"
)
// SourceMap maps a source file/location to an LLB state/definition.
// SourceMaps are used to provide information for debugging and helpful error messages to the user.
// As an example, lets say you have a Dockerfile with the following content:
//
// FROM alpine
// RUN exit 1
//
// When the "RUN" statement exits with a non-zero exit code buildkit will treat
// it as an error and is able to provide the user with a helpful error message
// pointing to exactly the line in the Dockerfile that caused the error.
type SourceMap struct {
State *State
Definition *Definition

View File

@ -49,6 +49,10 @@ func NewState(o Output) State {
return s
}
// State represents all operations that must be done to produce a given output.
// States are immutable, and all operations return a new state linked to the previous one.
// State is the core type of the LLB API and is used to build a graph of operations.
// The graph is then marshaled into a definition that can be executed by a backend (such as buildkitd).
type State struct {
out Output
prev *State