identifier.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package source
  2. import (
  3. "encoding/json"
  4. "strconv"
  5. "strings"
  6. "github.com/containerd/containerd/reference"
  7. "github.com/moby/buildkit/client"
  8. "github.com/moby/buildkit/solver/pb"
  9. digest "github.com/opencontainers/go-digest"
  10. specs "github.com/opencontainers/image-spec/specs-go/v1"
  11. "github.com/pkg/errors"
  12. )
  13. var (
  14. errInvalid = errors.New("invalid")
  15. errNotFound = errors.New("not found")
  16. )
  17. type ResolveMode int
  18. const (
  19. ResolveModeDefault ResolveMode = iota
  20. ResolveModeForcePull
  21. ResolveModePreferLocal
  22. )
  23. const (
  24. DockerImageScheme = "docker-image"
  25. GitScheme = "git"
  26. LocalScheme = "local"
  27. HttpScheme = "http"
  28. HttpsScheme = "https"
  29. )
  30. type Identifier interface {
  31. ID() string // until sources are in process this string comparison could be avoided
  32. }
  33. func FromString(s string) (Identifier, error) {
  34. // TODO: improve this
  35. parts := strings.SplitN(s, "://", 2)
  36. if len(parts) != 2 {
  37. return nil, errors.Wrapf(errInvalid, "failed to parse %s", s)
  38. }
  39. switch parts[0] {
  40. case DockerImageScheme:
  41. return NewImageIdentifier(parts[1])
  42. case GitScheme:
  43. return NewGitIdentifier(parts[1])
  44. case LocalScheme:
  45. return NewLocalIdentifier(parts[1])
  46. case HttpsScheme:
  47. return NewHttpIdentifier(parts[1], true)
  48. case HttpScheme:
  49. return NewHttpIdentifier(parts[1], false)
  50. default:
  51. return nil, errors.Wrapf(errNotFound, "unknown schema %s", parts[0])
  52. }
  53. }
  54. func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) {
  55. id, err := FromString(op.Source.Identifier)
  56. if err != nil {
  57. return nil, err
  58. }
  59. if id, ok := id.(*ImageIdentifier); ok {
  60. if platform != nil {
  61. id.Platform = &specs.Platform{
  62. OS: platform.OS,
  63. Architecture: platform.Architecture,
  64. Variant: platform.Variant,
  65. OSVersion: platform.OSVersion,
  66. OSFeatures: platform.OSFeatures,
  67. }
  68. }
  69. for k, v := range op.Source.Attrs {
  70. switch k {
  71. case pb.AttrImageResolveMode:
  72. rm, err := ParseImageResolveMode(v)
  73. if err != nil {
  74. return nil, err
  75. }
  76. id.ResolveMode = rm
  77. case pb.AttrImageRecordType:
  78. rt, err := parseImageRecordType(v)
  79. if err != nil {
  80. return nil, err
  81. }
  82. id.RecordType = rt
  83. }
  84. }
  85. }
  86. if id, ok := id.(*GitIdentifier); ok {
  87. for k, v := range op.Source.Attrs {
  88. switch k {
  89. case pb.AttrKeepGitDir:
  90. if v == "true" {
  91. id.KeepGitDir = true
  92. }
  93. case pb.AttrFullRemoteURL:
  94. id.Remote = v
  95. case pb.AttrAuthHeaderSecret:
  96. id.AuthHeaderSecret = v
  97. case pb.AttrAuthTokenSecret:
  98. id.AuthTokenSecret = v
  99. }
  100. }
  101. }
  102. if id, ok := id.(*LocalIdentifier); ok {
  103. for k, v := range op.Source.Attrs {
  104. switch k {
  105. case pb.AttrLocalSessionID:
  106. id.SessionID = v
  107. if p := strings.SplitN(v, ":", 2); len(p) == 2 {
  108. id.Name = p[0] + "-" + id.Name
  109. id.SessionID = p[1]
  110. }
  111. case pb.AttrIncludePatterns:
  112. var patterns []string
  113. if err := json.Unmarshal([]byte(v), &patterns); err != nil {
  114. return nil, err
  115. }
  116. id.IncludePatterns = patterns
  117. case pb.AttrExcludePatterns:
  118. var patterns []string
  119. if err := json.Unmarshal([]byte(v), &patterns); err != nil {
  120. return nil, err
  121. }
  122. id.ExcludePatterns = patterns
  123. case pb.AttrFollowPaths:
  124. var paths []string
  125. if err := json.Unmarshal([]byte(v), &paths); err != nil {
  126. return nil, err
  127. }
  128. id.FollowPaths = paths
  129. case pb.AttrSharedKeyHint:
  130. id.SharedKeyHint = v
  131. }
  132. }
  133. }
  134. if id, ok := id.(*HttpIdentifier); ok {
  135. for k, v := range op.Source.Attrs {
  136. switch k {
  137. case pb.AttrHTTPChecksum:
  138. dgst, err := digest.Parse(v)
  139. if err != nil {
  140. return nil, err
  141. }
  142. id.Checksum = dgst
  143. case pb.AttrHTTPFilename:
  144. id.Filename = v
  145. case pb.AttrHTTPPerm:
  146. i, err := strconv.ParseInt(v, 0, 64)
  147. if err != nil {
  148. return nil, err
  149. }
  150. id.Perm = int(i)
  151. case pb.AttrHTTPUID:
  152. i, err := strconv.ParseInt(v, 0, 64)
  153. if err != nil {
  154. return nil, err
  155. }
  156. id.UID = int(i)
  157. case pb.AttrHTTPGID:
  158. i, err := strconv.ParseInt(v, 0, 64)
  159. if err != nil {
  160. return nil, err
  161. }
  162. id.GID = int(i)
  163. }
  164. }
  165. }
  166. return id, nil
  167. }
  168. type ImageIdentifier struct {
  169. Reference reference.Spec
  170. Platform *specs.Platform
  171. ResolveMode ResolveMode
  172. RecordType client.UsageRecordType
  173. }
  174. func NewImageIdentifier(str string) (*ImageIdentifier, error) {
  175. ref, err := reference.Parse(str)
  176. if err != nil {
  177. return nil, errors.WithStack(err)
  178. }
  179. if ref.Object == "" {
  180. return nil, errors.WithStack(reference.ErrObjectRequired)
  181. }
  182. return &ImageIdentifier{Reference: ref}, nil
  183. }
  184. func (_ *ImageIdentifier) ID() string {
  185. return DockerImageScheme
  186. }
  187. type LocalIdentifier struct {
  188. Name string
  189. SessionID string
  190. IncludePatterns []string
  191. ExcludePatterns []string
  192. FollowPaths []string
  193. SharedKeyHint string
  194. }
  195. func NewLocalIdentifier(str string) (*LocalIdentifier, error) {
  196. return &LocalIdentifier{Name: str}, nil
  197. }
  198. func (*LocalIdentifier) ID() string {
  199. return LocalScheme
  200. }
  201. func NewHttpIdentifier(str string, tls bool) (*HttpIdentifier, error) {
  202. proto := "https://"
  203. if !tls {
  204. proto = "http://"
  205. }
  206. return &HttpIdentifier{TLS: tls, URL: proto + str}, nil
  207. }
  208. type HttpIdentifier struct {
  209. TLS bool
  210. URL string
  211. Checksum digest.Digest
  212. Filename string
  213. Perm int
  214. UID int
  215. GID int
  216. }
  217. func (_ *HttpIdentifier) ID() string {
  218. return HttpsScheme
  219. }
  220. func (r ResolveMode) String() string {
  221. switch r {
  222. case ResolveModeDefault:
  223. return pb.AttrImageResolveModeDefault
  224. case ResolveModeForcePull:
  225. return pb.AttrImageResolveModeForcePull
  226. case ResolveModePreferLocal:
  227. return pb.AttrImageResolveModePreferLocal
  228. default:
  229. return ""
  230. }
  231. }
  232. func ParseImageResolveMode(v string) (ResolveMode, error) {
  233. switch v {
  234. case pb.AttrImageResolveModeDefault, "":
  235. return ResolveModeDefault, nil
  236. case pb.AttrImageResolveModeForcePull:
  237. return ResolveModeForcePull, nil
  238. case pb.AttrImageResolveModePreferLocal:
  239. return ResolveModePreferLocal, nil
  240. default:
  241. return 0, errors.Errorf("invalid resolvemode: %s", v)
  242. }
  243. }
  244. func parseImageRecordType(v string) (client.UsageRecordType, error) {
  245. switch client.UsageRecordType(v) {
  246. case "", client.UsageRecordTypeRegular:
  247. return client.UsageRecordTypeRegular, nil
  248. case client.UsageRecordTypeInternal:
  249. return client.UsageRecordTypeInternal, nil
  250. case client.UsageRecordTypeFrontend:
  251. return client.UsageRecordTypeFrontend, nil
  252. default:
  253. return "", errors.Errorf("invalid record type %s", v)
  254. }
  255. }