copy/copy.go
func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, srcRef types.ImageReference, options *Options) (manifest []byte, retErr error) {
	// NOTE this function uses an output parameter for the error return value.
	// Setting this and returning is the ideal way to return an error.
	//
	// the defers in this routine will wrap the error return with its own errors
	// which can be valuable context in the middle of a multi-streamed copy.
	if options == nil {
		options = &Options{}
	}

	reportWriter := ioutil.Discard

	if options.ReportWriter != nil {
		reportWriter = options.ReportWriter
	}

	dest, err := destRef.NewImageDestination(ctx, options.DestinationCtx)
	if err != nil {
		return nil, errors.Wrapf(err, "Error initializing destination %s", transports.ImageName(destRef))
	}
	defer func() {
		if err := dest.Close(); err != nil {
			retErr = errors.Wrapf(retErr, " (dest: %v)", err)
		}
	}()

	rawSource, err := srcRef.NewImageSource(ctx, options.SourceCtx)
	if err != nil {
		return nil, errors.Wrapf(err, "Error initializing source %s", transports.ImageName(srcRef))
	}
	defer func() {
		if err := rawSource.Close(); err != nil {
			retErr = errors.Wrapf(retErr, " (src: %v)", err)
		}
	}()

	// If reportWriter is not a TTY (e.g., when piping to a file), do not
	// print the progress bars to avoid long and hard to parse output.
	// createProgressBar() will print a single line instead.
	progressOutput := reportWriter
	if !isTTY(reportWriter) {
		progressOutput = ioutil.Discard
	}
	copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
	c := &copier{
		dest:             dest,
		rawSource:        rawSource,
		reportWriter:     reportWriter,
		progressOutput:   progressOutput,
		progressInterval: options.ProgressInterval,
		progress:         options.Progress,
		copyInParallel:   copyInParallel,
		// FIXME? The cache is used for sources and destinations equally, but we only have a SourceCtx and DestinationCtx.
		// For now, use DestinationCtx (because blob reuse changes the behavior of the destination side more); eventually
		// we might want to add a separate CommonCtx — or would that be too confusing?
		blobInfoCache: blobinfocache.DefaultCache(options.DestinationCtx),
	}

	unparsedToplevel := image.UnparsedInstance(rawSource, nil)
	multiImage, err := isMultiImage(ctx, unparsedToplevel)
	if err != nil {
		return nil, errors.Wrapf(err, "Error determining manifest MIME type for %s", transports.ImageName(srcRef))
	}

	if !multiImage {
		// The simple case: Just copy a single image.
		if manifest, err = c.copyOneImage(ctx, policyContext, options, unparsedToplevel); err != nil {
			return nil, err
		}
	} else {
		// This is a manifest list. Choose a single image and copy it.
		// FIXME: Copy to destinations which support manifest lists, one image at a time.
		instanceDigest, err := image.ChooseManifestInstanceFromManifestList(ctx, options.SourceCtx, unparsedToplevel)
		if err != nil {
			return nil, errors.Wrapf(err, "Error choosing an image from manifest list %s", transports.ImageName(srcRef))
		}
		logrus.Debugf("Source is a manifest list; copying (only) instance %s", instanceDigest)
		unparsedInstance := image.UnparsedInstance(rawSource, &instanceDigest)

		if manifest, err = c.copyOneImage(ctx, policyContext, options, unparsedInstance); err != nil {
			return nil, err
		}
	}

	if err := c.dest.Commit(ctx); err != nil {
		return nil, errors.Wrap(err, "Error committing the finished image")
	}

	return manifest, nil
}
func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, srcRef types.ImageReference, options *Options) (manifest []byte, retErr error) {
	// NOTE this function uses an output parameter for the error return value.
	// Setting this and returning is the ideal way to return an error.
	//
	// the defers in this routine will wrap the error return with its own errors
	// which can be valuable context in the middle of a multi-streamed copy.
	if options == nil {
		options = &Options{}
	}

	reportWriter := ioutil.Discard

	if options.ReportWriter != nil {
		reportWriter = options.ReportWriter
	}

	dest, err := destRef.NewImageDestination(ctx, options.DestinationCtx)
	if err != nil {
		return nil, errors.Wrapf(err, "Error initializing destination %s", transports.ImageName(destRef))
	}
	defer func() {
		if err := dest.Close(); err != nil {
			retErr = errors.Wrapf(retErr, " (dest: %v)", err)
		}
	}()

	rawSource, err := srcRef.NewImageSource(ctx, options.SourceCtx)
	if err != nil {
		return nil, errors.Wrapf(err, "Error initializing source %s", transports.ImageName(srcRef))
	}
	defer func() {
		if err := rawSource.Close(); err != nil {
			retErr = errors.Wrapf(retErr, " (src: %v)", err)
		}
	}()

	// If reportWriter is not a TTY (e.g., when piping to a file), do not
	// print the progress bars to avoid long and hard to parse output.
	// createProgressBar() will print a single line instead.
	progressOutput := reportWriter
	if !isTTY(reportWriter) {
		progressOutput = ioutil.Discard
	}
	copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
	c := &copier{
		dest:             dest,
		rawSource:        rawSource,
		reportWriter:     reportWriter,
		progressOutput:   progressOutput,
		progressInterval: options.ProgressInterval,
		progress:         options.Progress,
		copyInParallel:   copyInParallel,
		// FIXME? The cache is used for sources and destinations equally, but we only have a SourceCtx and DestinationCtx.
		// For now, use DestinationCtx (because blob reuse changes the behavior of the destination side more); eventually
		// we might want to add a separate CommonCtx — or would that be too confusing?
		blobInfoCache: blobinfocache.DefaultCache(options.DestinationCtx),
	}

	unparsedToplevel := image.UnparsedInstance(rawSource, nil)
	multiImage, err := isMultiImage(ctx, unparsedToplevel)
	if err != nil {
		return nil, errors.Wrapf(err, "Error determining manifest MIME type for %s", transports.ImageName(srcRef))
	}

	if !multiImage {
		// The simple case: Just copy a single image.
		if manifest, err = c.copyOneImage(ctx, policyContext, options, unparsedToplevel); err != nil {
			return nil, err
		}
	} else {
		// This is a manifest list. Choose a single image and copy it.
		// FIXME: Copy to destinations which support manifest lists, one image at a time.
		instanceDigest, err := image.ChooseManifestInstanceFromManifestList(ctx, options.SourceCtx, unparsedToplevel)
		if err != nil {
			return nil, errors.Wrapf(err, "Error choosing an image from manifest list %s", transports.ImageName(srcRef))
		}
		logrus.Debugf("Source is a manifest list; copying (only) instance %s", instanceDigest)
		unparsedInstance := image.UnparsedInstance(rawSource, &instanceDigest)

		if manifest, err = c.copyOneImage(ctx, policyContext, options, unparsedInstance); err != nil {
			return nil, err
		}
	}

	if err := c.dest.Commit(ctx); err != nil {
		return nil, errors.Wrap(err, "Error committing the finished image")
	}

	return manifest, nil
}
func Image ( ctx context . Context , policyContext * signature . PolicyContext , destRef , srcRef types . ImageReference , options * Options ) ( manifest [ ] byte , retErr error ) { // NOTE this function uses an output parameter for the error return value. // Setting this and returning is the ideal way to return an error. // // the defers in this routine will wrap the error return with its own errors // which can be valuable context in the middle of a multi-streamed copy. if options == nil { options = & Options { } } reportWriter := ioutil . Discard if options . ReportWriter != nil { reportWriter = options . ReportWriter } dest , err := destRef . NewImageDestination ( ctx , options . DestinationCtx ) if err != nil { return nil , errors . Wrapf ( err , " " , transports . ImageName ( destRef ) ) } defer func ( ) { if err := dest . Close ( ) ; err != nil { retErr = errors . Wrapf ( retErr , " " , err ) } } ( ) rawSource , err := srcRef . NewImageSource ( ctx , options . SourceCtx ) if err != nil { return nil , errors . Wrapf ( err , " " , transports . ImageName ( srcRef ) ) } defer func ( ) { if err := rawSource . Close ( ) ; err != nil { retErr = errors . Wrapf ( retErr , " " , err ) } } ( ) // If reportWriter is not a TTY (e.g., when piping to a file), do not // print the progress bars to avoid long and hard to parse output. // createProgressBar() will print a single line instead. progressOutput := reportWriter if ! isTTY ( reportWriter ) { progressOutput = ioutil . Discard } copyInParallel := dest . HasThreadSafePutBlob ( ) && rawSource . HasThreadSafeGetBlob ( ) c := & copier { dest : dest , rawSource : rawSource , reportWriter : reportWriter , progressOutput : progressOutput , progressInterval : options . ProgressInterval , progress : options . Progress , copyInParallel : copyInParallel , // FIXME? The cache is used for sources and destinations equally, but we only have a SourceCtx and DestinationCtx. // For now, use DestinationCtx (because blob reuse changes the behavior of the destination side more); eventually // we might want to add a separate CommonCtx — or would that be too confusing? blobInfoCache : blobinfocache . DefaultCache ( options . DestinationCtx ) , } unparsedToplevel := image . UnparsedInstance ( rawSource , nil ) multiImage , err := isMultiImage ( ctx , unparsedToplevel ) if err != nil { return nil , errors . Wrapf ( err , " " , transports . ImageName ( srcRef ) ) } if ! multiImage { // The simple case: Just copy a single image. if manifest , err = c . copyOneImage ( ctx , policyContext , options , unparsedToplevel ) ; err != nil { return nil , err } } else { // This is a manifest list. Choose a single image and copy it. // FIXME: Copy to destinations which support manifest lists, one image at a time. instanceDigest , err := image . ChooseManifestInstanceFromManifestList ( ctx , options . SourceCtx , unparsedToplevel ) if err != nil { return nil , errors . Wrapf ( err , " " , transports . ImageName ( srcRef ) ) } logrus . Debugf ( " " , instanceDigest ) unparsedInstance := image . UnparsedInstance ( rawSource , & instanceDigest ) if manifest , err = c . copyOneImage ( ctx , policyContext , options , unparsedInstance ) ; err != nil { return nil , err } } if err := c . dest . Commit ( ctx ) ; err != nil { return nil , errors . Wrap ( err , " " ) } return manifest , nil }
// Image copies image from srcRef to destRef, using policyContext to validate
// source image admissibility.  It returns the manifest which was written to
// the new copy of the image.
Image copies image from srcRef to destRef using policyContext to validate source image admissibility . It returns the manifest which was written to the new copy of the image .