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  }