buildkit/source/identifier.go

186 lines
4.0 KiB
Go

package source
import (
"encoding/json"
"strconv"
"strings"
"github.com/containerd/containerd/reference"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
var (
errInvalid = errors.New("invalid")
errNotFound = errors.New("not found")
)
const (
DockerImageScheme = "docker-image"
GitScheme = "git"
LocalScheme = "local"
HttpScheme = "http"
HttpsScheme = "https"
)
type Identifier interface {
ID() string // until sources are in process this string comparison could be avoided
}
func FromString(s string) (Identifier, error) {
// TODO: improve this
parts := strings.SplitN(s, "://", 2)
if len(parts) != 2 {
return nil, errors.Wrapf(errInvalid, "failed to parse %s", s)
}
switch parts[0] {
case DockerImageScheme:
return NewImageIdentifier(parts[1])
case GitScheme:
return NewGitIdentifier(parts[1])
case LocalScheme:
return NewLocalIdentifier(parts[1])
case HttpsScheme:
return NewHttpIdentifier(parts[1], true)
case HttpScheme:
return NewHttpIdentifier(parts[1], false)
default:
return nil, errors.Wrapf(errNotFound, "unknown schema %s", parts[0])
}
}
func FromLLB(op *pb.Op_Source) (Identifier, error) {
id, err := FromString(op.Source.Identifier)
if err != nil {
return nil, err
}
if id, ok := id.(*GitIdentifier); ok {
for k, v := range op.Source.Attrs {
switch k {
case pb.AttrKeepGitDir:
if v == "true" {
id.KeepGitDir = true
}
}
}
}
if id, ok := id.(*LocalIdentifier); ok {
for k, v := range op.Source.Attrs {
switch k {
case pb.AttrLocalSessionID:
id.SessionID = v
if p := strings.SplitN(v, ":", 2); len(p) == 2 {
id.Name = p[0] + "-" + id.Name
id.SessionID = p[1]
}
case pb.AttrIncludePatterns:
var patterns []string
if err := json.Unmarshal([]byte(v), &patterns); err != nil {
return nil, err
}
id.IncludePatterns = patterns
case pb.AttrExcludePatterns:
var patterns []string
if err := json.Unmarshal([]byte(v), &patterns); err != nil {
return nil, err
}
id.ExcludePatterns = patterns
case pb.AttrSharedKeyHint:
id.SharedKeyHint = v
}
}
}
if id, ok := id.(*HttpIdentifier); ok {
for k, v := range op.Source.Attrs {
switch k {
case pb.AttrHTTPChecksum:
dgst, err := digest.Parse(v)
if err != nil {
return nil, err
}
id.Checksum = dgst
case pb.AttrHTTPFilename:
id.Filename = v
case pb.AttrHTTPPerm:
i, err := strconv.ParseInt(v, 0, 64)
if err != nil {
return nil, err
}
id.Perm = int(i)
case pb.AttrHTTPUID:
i, err := strconv.ParseInt(v, 0, 64)
if err != nil {
return nil, err
}
id.UID = int(i)
case pb.AttrHTTPGID:
i, err := strconv.ParseInt(v, 0, 64)
if err != nil {
return nil, err
}
id.GID = int(i)
}
}
}
return id, nil
}
type ImageIdentifier struct {
Reference reference.Spec
}
func NewImageIdentifier(str string) (*ImageIdentifier, error) {
ref, err := reference.Parse(str)
if err != nil {
return nil, errors.WithStack(err)
}
if ref.Object == "" {
return nil, errors.WithStack(reference.ErrObjectRequired)
}
return &ImageIdentifier{Reference: ref}, nil
}
func (_ *ImageIdentifier) ID() string {
return DockerImageScheme
}
type LocalIdentifier struct {
Name string
SessionID string
IncludePatterns []string
ExcludePatterns []string
SharedKeyHint string
}
func NewLocalIdentifier(str string) (*LocalIdentifier, error) {
return &LocalIdentifier{Name: str}, nil
}
func (*LocalIdentifier) ID() string {
return LocalScheme
}
func NewHttpIdentifier(str string, tls bool) (*HttpIdentifier, error) {
proto := "https://"
if !tls {
proto = "http://"
}
return &HttpIdentifier{TLS: tls, URL: proto + str}, nil
}
type HttpIdentifier struct {
TLS bool
URL string
Checksum digest.Digest
Filename string
Perm int
UID int
GID int
}
func (_ *HttpIdentifier) ID() string {
return HttpsScheme
}