196 lines
3.7 KiB
Go
196 lines
3.7 KiB
Go
package llb
|
|
|
|
import (
|
|
"context"
|
|
_ "crypto/sha256"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/docker/distribution/reference"
|
|
"github.com/moby/buildkit/solver/pb"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type SourceOp struct {
|
|
id string
|
|
attrs map[string]string
|
|
output Output
|
|
cachedPB []byte
|
|
cachedOpMetadata *pb.OpMetadata
|
|
err error
|
|
}
|
|
|
|
func NewSource(id string, attrs map[string]string) *SourceOp {
|
|
s := &SourceOp{
|
|
id: id,
|
|
attrs: attrs,
|
|
}
|
|
s.output = &output{vertex: s}
|
|
return s
|
|
}
|
|
|
|
func (s *SourceOp) Validate() error {
|
|
if s.err != nil {
|
|
return s.err
|
|
}
|
|
if s.id == "" {
|
|
return errors.Errorf("source identifier can't be empty")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SourceOp) Marshal() ([]byte, *pb.OpMetadata, error) {
|
|
if s.cachedPB != nil {
|
|
return s.cachedPB, s.cachedOpMetadata, nil
|
|
}
|
|
if err := s.Validate(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
proto := &pb.Op{
|
|
Op: &pb.Op_Source{
|
|
Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
|
|
},
|
|
}
|
|
dt, err := proto.Marshal()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
s.cachedPB = dt
|
|
s.cachedOpMetadata = &pb.OpMetadata{}
|
|
return dt, s.cachedOpMetadata, nil
|
|
}
|
|
|
|
func (s *SourceOp) Output() Output {
|
|
return s.output
|
|
}
|
|
|
|
func (s *SourceOp) Inputs() []Output {
|
|
return nil
|
|
}
|
|
|
|
func Source(id string) State {
|
|
return NewState(NewSource(id, nil).Output())
|
|
}
|
|
|
|
func Image(ref string, opts ...ImageOption) State {
|
|
r, err := reference.ParseNormalizedNamed(ref)
|
|
if err == nil {
|
|
ref = reference.TagNameOnly(r).String()
|
|
}
|
|
src := NewSource("docker-image://"+ref, nil) // controversial
|
|
if err != nil {
|
|
src.err = err
|
|
}
|
|
var info ImageInfo
|
|
for _, opt := range opts {
|
|
opt(&info)
|
|
}
|
|
if info.metaResolver != nil {
|
|
_, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref)
|
|
if err != nil {
|
|
src.err = err
|
|
} else {
|
|
var img ocispec.Image
|
|
if err := json.Unmarshal(dt, &img); err != nil {
|
|
src.err = err
|
|
} else {
|
|
st := NewState(src.Output())
|
|
for _, env := range img.Config.Env {
|
|
parts := strings.SplitN(env, "=", 2)
|
|
if len(parts[0]) > 0 {
|
|
var v string
|
|
if len(parts) > 1 {
|
|
v = parts[1]
|
|
}
|
|
st = st.AddEnv(parts[0], v)
|
|
}
|
|
}
|
|
st = st.Dir(img.Config.WorkingDir)
|
|
return st
|
|
}
|
|
}
|
|
}
|
|
return NewState(src.Output())
|
|
}
|
|
|
|
type ImageOption func(*ImageInfo)
|
|
|
|
type ImageInfo struct {
|
|
metaResolver ImageMetaResolver
|
|
}
|
|
|
|
func Git(remote, ref string, opts ...GitOption) State {
|
|
id := remote
|
|
if ref != "" {
|
|
id += "#" + ref
|
|
}
|
|
|
|
gi := &GitInfo{}
|
|
for _, o := range opts {
|
|
o(gi)
|
|
}
|
|
attrs := map[string]string{}
|
|
if gi.KeepGitDir {
|
|
attrs[pb.AttrKeepGitDir] = "true"
|
|
}
|
|
|
|
source := NewSource("git://"+id, attrs)
|
|
return NewState(source.Output())
|
|
}
|
|
|
|
type GitOption func(*GitInfo)
|
|
|
|
type GitInfo struct {
|
|
KeepGitDir bool
|
|
}
|
|
|
|
func KeepGitDir() GitOption {
|
|
return func(gi *GitInfo) {
|
|
gi.KeepGitDir = true
|
|
}
|
|
}
|
|
|
|
func Scratch() State {
|
|
return NewState(nil)
|
|
}
|
|
|
|
func Local(name string, opts ...LocalOption) State {
|
|
gi := &LocalInfo{}
|
|
|
|
for _, o := range opts {
|
|
o(gi)
|
|
}
|
|
attrs := map[string]string{}
|
|
if gi.SessionID != "" {
|
|
attrs[pb.AttrLocalSessionID] = gi.SessionID
|
|
}
|
|
if gi.IncludePatterns != "" {
|
|
attrs[pb.AttrIncludePatterns] = gi.IncludePatterns
|
|
}
|
|
|
|
source := NewSource("local://"+name, attrs)
|
|
return NewState(source.Output())
|
|
}
|
|
|
|
type LocalOption func(*LocalInfo)
|
|
|
|
func SessionID(id string) LocalOption {
|
|
return func(li *LocalInfo) {
|
|
li.SessionID = id
|
|
}
|
|
}
|
|
|
|
func IncludePatterns(p []string) LocalOption {
|
|
return func(li *LocalInfo) {
|
|
dt, _ := json.Marshal(p) // empty on error
|
|
li.IncludePatterns = string(dt)
|
|
}
|
|
}
|
|
|
|
type LocalInfo struct {
|
|
SessionID string
|
|
IncludePatterns string
|
|
}
|