| package contentutil |
| |
| import ( |
| "context" |
| "io" |
| "sync" |
| |
| "github.com/containerd/containerd/content" |
| "github.com/containerd/containerd/images" |
| "github.com/containerd/containerd/remotes" |
| "github.com/moby/buildkit/util/resolver/retryhandler" |
| ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| "github.com/pkg/errors" |
| ) |
| |
| func Copy(ctx context.Context, ingester content.Ingester, provider content.Provider, desc ocispec.Descriptor, logger func([]byte)) error { |
| if _, err := retryhandler.New(remotes.FetchHandler(ingester, &localFetcher{provider}), logger)(ctx, desc); err != nil { |
| return err |
| } |
| return nil |
| } |
| |
| type localFetcher struct { |
| content.Provider |
| } |
| |
| func (f *localFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { |
| r, err := f.Provider.ReaderAt(ctx, desc) |
| if err != nil { |
| return nil, err |
| } |
| return &rc{ReaderAt: r}, nil |
| } |
| |
| type rc struct { |
| content.ReaderAt |
| offset int |
| } |
| |
| func (r *rc) Read(b []byte) (int, error) { |
| n, err := r.ReadAt(b, int64(r.offset)) |
| r.offset += n |
| if n > 0 && err == io.EOF { |
| err = nil |
| } |
| return n, err |
| } |
| |
| func CopyChain(ctx context.Context, ingester content.Ingester, provider content.Provider, desc ocispec.Descriptor) error { |
| var m sync.Mutex |
| manifestStack := []ocispec.Descriptor{} |
| |
| filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { |
| switch desc.MediaType { |
| case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest, |
| images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: |
| m.Lock() |
| manifestStack = append(manifestStack, desc) |
| m.Unlock() |
| return nil, images.ErrStopHandler |
| default: |
| return nil, nil |
| } |
| }) |
| handlers := []images.Handler{ |
| images.ChildrenHandler(provider), |
| filterHandler, |
| retryhandler.New(remotes.FetchHandler(ingester, &localFetcher{provider}), nil), |
| } |
| |
| if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil { |
| return errors.WithStack(err) |
| } |
| |
| for i := len(manifestStack) - 1; i >= 0; i-- { |
| if err := Copy(ctx, ingester, provider, manifestStack[i], nil); err != nil { |
| return errors.WithStack(err) |
| } |
| } |
| |
| return nil |
| } |