| package registry |
| |
| import ( |
| "context" |
| "strconv" |
| |
| "github.com/containerd/containerd/content" |
| "github.com/containerd/containerd/remotes/docker" |
| "github.com/docker/distribution/reference" |
| "github.com/moby/buildkit/cache/remotecache" |
| "github.com/moby/buildkit/session" |
| "github.com/moby/buildkit/util/contentutil" |
| "github.com/moby/buildkit/util/resolver" |
| digest "github.com/opencontainers/go-digest" |
| ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| specs "github.com/opencontainers/image-spec/specs-go/v1" |
| "github.com/pkg/errors" |
| ) |
| |
| func canonicalizeRef(rawRef string) (string, error) { |
| if rawRef == "" { |
| return "", errors.New("missing ref") |
| } |
| parsed, err := reference.ParseNormalizedNamed(rawRef) |
| if err != nil { |
| return "", err |
| } |
| return reference.TagNameOnly(parsed).String(), nil |
| } |
| |
| const ( |
| attrRef = "ref" |
| attrOCIMediatypes = "oci-mediatypes" |
| ) |
| |
| func ResolveCacheExporterFunc(sm *session.Manager, hosts docker.RegistryHosts) remotecache.ResolveCacheExporterFunc { |
| return func(ctx context.Context, g session.Group, attrs map[string]string) (remotecache.Exporter, error) { |
| ref, err := canonicalizeRef(attrs[attrRef]) |
| if err != nil { |
| return nil, err |
| } |
| ociMediatypes := true |
| if v, ok := attrs[attrOCIMediatypes]; ok { |
| b, err := strconv.ParseBool(v) |
| if err != nil { |
| return nil, errors.Wrapf(err, "failed to parse %s", attrOCIMediatypes) |
| } |
| ociMediatypes = b |
| } |
| remote := resolver.DefaultPool.GetResolver(hosts, ref, "push", sm, g) |
| pusher, err := remote.Pusher(ctx, ref) |
| if err != nil { |
| return nil, err |
| } |
| return remotecache.NewExporter(contentutil.FromPusher(pusher), ociMediatypes), nil |
| } |
| } |
| |
| func ResolveCacheImporterFunc(sm *session.Manager, cs content.Store, hosts docker.RegistryHosts) remotecache.ResolveCacheImporterFunc { |
| return func(ctx context.Context, g session.Group, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) { |
| ref, err := canonicalizeRef(attrs[attrRef]) |
| if err != nil { |
| return nil, specs.Descriptor{}, err |
| } |
| remote := resolver.DefaultPool.GetResolver(hosts, ref, "pull", sm, g) |
| xref, desc, err := remote.Resolve(ctx, ref) |
| if err != nil { |
| return nil, specs.Descriptor{}, err |
| } |
| fetcher, err := remote.Fetcher(ctx, xref) |
| if err != nil { |
| return nil, specs.Descriptor{}, err |
| } |
| src := &withDistributionSourceLabel{ |
| Provider: contentutil.FromFetcher(fetcher), |
| ref: ref, |
| source: cs, |
| } |
| return remotecache.NewImporter(src), desc, nil |
| } |
| } |
| |
| type withDistributionSourceLabel struct { |
| content.Provider |
| ref string |
| source content.Manager |
| } |
| |
| var _ remotecache.DistributionSourceLabelSetter = &withDistributionSourceLabel{} |
| |
| func (dsl *withDistributionSourceLabel) SetDistributionSourceLabel(ctx context.Context, dgst digest.Digest) error { |
| hf, err := docker.AppendDistributionSourceLabel(dsl.source, dsl.ref) |
| if err != nil { |
| return err |
| } |
| _, err = hf(ctx, ocispec.Descriptor{Digest: dgst}) |
| return err |
| } |
| |
| func (dsl *withDistributionSourceLabel) SetDistributionSourceAnnotation(desc ocispec.Descriptor) ocispec.Descriptor { |
| if desc.Annotations == nil { |
| desc.Annotations = map[string]string{} |
| } |
| desc.Annotations["containerd.io/distribution.source.ref"] = dsl.ref |
| return desc |
| } |