github.com/docker/cnab-to-oci@v0.3.0-beta4/remotes/fixuphelpers.go (about) 1 package remotes 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "io/ioutil" 9 10 "github.com/cnabio/cnab-go/bundle" 11 "github.com/containerd/containerd/images" 12 "github.com/containerd/containerd/remotes" 13 "github.com/docker/distribution/reference" 14 "github.com/opencontainers/go-digest" 15 ocischemav1 "github.com/opencontainers/image-spec/specs-go/v1" 16 ) 17 18 type sourceFetcherAdder interface { 19 remotes.Fetcher 20 Add(data []byte) digest.Digest 21 } 22 23 type sourceFetcherWithLocalData struct { 24 inner remotes.Fetcher 25 localData map[digest.Digest][]byte 26 } 27 28 func newSourceFetcherWithLocalData(inner remotes.Fetcher) *sourceFetcherWithLocalData { 29 return &sourceFetcherWithLocalData{ 30 inner: inner, 31 localData: make(map[digest.Digest][]byte), 32 } 33 } 34 35 func (s *sourceFetcherWithLocalData) Add(data []byte) digest.Digest { 36 d := digest.FromBytes(data) 37 s.localData[d] = data 38 return d 39 } 40 41 func (s *sourceFetcherWithLocalData) Fetch(ctx context.Context, desc ocischemav1.Descriptor) (io.ReadCloser, error) { 42 if v, ok := s.localData[desc.Digest]; ok { 43 return ioutil.NopCloser(bytes.NewReader(v)), nil 44 } 45 return s.inner.Fetch(ctx, desc) 46 } 47 48 type imageFixupInfo struct { 49 targetRepo reference.Named 50 sourceRef reference.Named 51 resolvedDescriptor ocischemav1.Descriptor 52 } 53 54 func makeEventNotifier(events chan<- FixupEvent, baseImage string, targetRef reference.Named) (eventNotifier, *progress) { 55 progress := &progress{} 56 return func(eventType FixupEventType, message string, err error) { 57 events <- FixupEvent{ 58 DestinationRef: targetRef, 59 SourceImage: baseImage, 60 EventType: eventType, 61 Message: message, 62 Error: err, 63 Progress: progress.snapshot(), 64 } 65 }, progress 66 } 67 68 func makeSourceFetcher(ctx context.Context, resolver remotes.Resolver, sourceRef string) (*sourceFetcherWithLocalData, error) { 69 sourceRepoOnly, err := reference.ParseNormalizedNamed(sourceRef) 70 if err != nil { 71 return nil, err 72 } 73 f, err := resolver.Fetcher(ctx, sourceRepoOnly.Name()) 74 if err != nil { 75 return nil, err 76 } 77 return newSourceFetcherWithLocalData(f), nil 78 } 79 80 func makeManifestWalker(ctx context.Context, sourceFetcher remotes.Fetcher, 81 notifyEvent eventNotifier, cfg fixupConfig, fixupInfo imageFixupInfo, progress *progress) (promise, func(), error) { 82 copier, err := newDescriptorCopier(ctx, cfg.resolver, sourceFetcher, fixupInfo.targetRepo.String(), notifyEvent, fixupInfo.sourceRef) 83 if err != nil { 84 return promise{}, nil, err 85 } 86 descriptorContentHandler := &descriptorContentHandler{ 87 descriptorCopier: copier, 88 targetRepo: fixupInfo.targetRepo.String(), 89 } 90 ctx, cancel := context.WithCancel(ctx) 91 scheduler := newErrgroupScheduler(ctx, cfg.maxConcurrentJobs, cfg.jobsBufferLength) 92 cleaner := func() { 93 cancel() 94 scheduler.drain() //nolint:errcheck 95 } 96 walker := newManifestWalker(notifyEvent, scheduler, progress, descriptorContentHandler) 97 return walker.walk(scheduler.ctx(), fixupInfo.resolvedDescriptor, nil), cleaner, nil 98 } 99 100 func notifyError(notifyEvent eventNotifier, err error) error { 101 notifyEvent(FixupEventTypeCopyImageEnd, "", err) 102 return err 103 } 104 105 func checkBaseImage(baseImage *bundle.BaseImage) error { 106 switch baseImage.ImageType { 107 case "docker": 108 case "oci": 109 case "": 110 baseImage.ImageType = "oci" 111 default: 112 return fmt.Errorf("image type %q is not supported", baseImage.ImageType) 113 } 114 115 switch baseImage.MediaType { 116 case ocischemav1.MediaTypeImageIndex: 117 case ocischemav1.MediaTypeImageManifest: 118 case images.MediaTypeDockerSchema2Manifest: 119 case images.MediaTypeDockerSchema2ManifestList: 120 case "": 121 default: 122 return fmt.Errorf("image media type %q is not supported", baseImage.MediaType) 123 } 124 125 return nil 126 }