@@ -30,7 +30,6 @@ import (
3030 "github.com/containerd/containerd/namespaces"
3131 "github.com/containerd/containerd/platforms"
3232 "github.com/containerd/containerd/plugin"
33- "github.com/containerd/containerd/reference"
3433 "github.com/containerd/containerd/remotes"
3534 "github.com/containerd/containerd/remotes/docker"
3635 "github.com/containerd/containerd/remotes/docker/schema1"
@@ -503,95 +502,27 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
503502 }, nil
504503}
505504
506- type imageFormat string
507-
508- const (
509- ociImageFormat imageFormat = "oci"
510- )
511-
512505type importOpts struct {
513- format imageFormat
514- refObject string
515- labels map [string ]string
516506}
517507
518508// ImportOpt allows the caller to specify import specific options
519509type ImportOpt func (c * importOpts ) error
520510
521- // WithImportLabel sets a label to be associated with an imported image
522- func WithImportLabel (key , value string ) ImportOpt {
523- return func (opts * importOpts ) error {
524- if opts .labels == nil {
525- opts .labels = make (map [string ]string )
526- }
527-
528- opts .labels [key ] = value
529- return nil
530- }
531- }
532-
533- // WithImportLabels associates a set of labels to an imported image
534- func WithImportLabels (labels map [string ]string ) ImportOpt {
535- return func (opts * importOpts ) error {
536- if opts .labels == nil {
537- opts .labels = make (map [string ]string )
538- }
539-
540- for k , v := range labels {
541- opts .labels [k ] = v
542- }
543- return nil
544- }
545- }
546-
547- // WithOCIImportFormat sets the import format for an OCI image format
548- func WithOCIImportFormat () ImportOpt {
549- return func (c * importOpts ) error {
550- if c .format != "" {
551- return errors .New ("format already set" )
552- }
553- c .format = ociImageFormat
554- return nil
555- }
556- }
557-
558- // WithRefObject specifies the ref object to import.
559- // If refObject is empty, it is copied from the ref argument of Import().
560- func WithRefObject (refObject string ) ImportOpt {
561- return func (c * importOpts ) error {
562- c .refObject = refObject
563- return nil
564- }
565- }
566-
567- func resolveImportOpt (ref string , opts ... ImportOpt ) (importOpts , error ) {
511+ func resolveImportOpt (opts ... ImportOpt ) (importOpts , error ) {
568512 var iopts importOpts
569513 for _ , o := range opts {
570514 if err := o (& iopts ); err != nil {
571515 return iopts , err
572516 }
573517 }
574- // use OCI as the default format
575- if iopts .format == "" {
576- iopts .format = ociImageFormat
577- }
578- // if refObject is not explicitly specified, use the one specified in ref
579- if iopts .refObject == "" {
580- refSpec , err := reference .Parse (ref )
581- if err != nil {
582- return iopts , err
583- }
584- iopts .refObject = refSpec .Object
585- }
586518 return iopts , nil
587519}
588520
589521// Import imports an image from a Tar stream using reader.
590- // OCI format is assumed by default.
591- //
592- // Note that unreferenced blobs are imported to the content store as well.
593- func (c * Client ) Import (ctx context.Context , ref string , reader io.Reader , opts ... ImportOpt ) (Image , error ) {
594- iopts , err := resolveImportOpt (ref , opts ... )
522+ // Caller needs to specify importer. Future version may use oci.v1 as the default.
523+ // Note that unreferrenced blobs may be imported to the content store as well.
524+ func (c * Client ) Import (ctx context.Context , importer images.Importer , reader io.Reader , opts ... ImportOpt ) ([]Image , error ) {
525+ _ , err := resolveImportOpt (opts ... ) // unused now
595526 if err != nil {
596527 return nil , err
597528 }
@@ -602,58 +533,66 @@ func (c *Client) Import(ctx context.Context, ref string, reader io.Reader, opts
602533 }
603534 defer done ()
604535
605- switch iopts .format {
606- case ociImageFormat :
607- return c .importFromOCITar (ctx , ref , reader , iopts )
608- default :
609- return nil , errors .Errorf ("unsupported format: %s" , iopts .format )
536+ imgrecs , err := importer .Import (ctx , c .ContentStore (), reader )
537+ if err != nil {
538+ // is.Update() is not called on error
539+ return nil , err
540+ }
541+
542+ is := c .ImageService ()
543+ var images []Image
544+ for _ , imgrec := range imgrecs {
545+ if updated , err := is .Update (ctx , imgrec , "target" ); err != nil {
546+ if ! errdefs .IsNotFound (err ) {
547+ return nil , err
548+ }
549+
550+ created , err := is .Create (ctx , imgrec )
551+ if err != nil {
552+ return nil , err
553+ }
554+
555+ imgrec = created
556+ } else {
557+ imgrec = updated
558+ }
559+
560+ images = append (images , & image {
561+ client : c ,
562+ i : imgrec ,
563+ })
610564 }
565+ return images , nil
611566}
612567
613568type exportOpts struct {
614- format imageFormat
615569}
616570
617- // ExportOpt allows callers to set export options
571+ // ExportOpt allows the caller to specify export-specific options
618572type ExportOpt func (c * exportOpts ) error
619573
620- // WithOCIExportFormat sets the OCI image format as the export target
621- func WithOCIExportFormat () ExportOpt {
622- return func ( c * exportOpts ) error {
623- if c . format != "" {
624- return errors . New ( "format already set" )
574+ func resolveExportOpt ( opts ... ExportOpt ) ( exportOpts , error ) {
575+ var eopts exportOpts
576+ for _ , o := range opts {
577+ if err := o ( & eopts ); err != nil {
578+ return eopts , err
625579 }
626- c .format = ociImageFormat
627- return nil
628580 }
581+ return eopts , nil
629582}
630583
631- // TODO: add WithMediaTypeTranslation that transforms media types according to the format.
632- // e.g. application/vnd.docker.image.rootfs.diff.tar.gzip
633- // -> application/vnd.oci.image.layer.v1.tar+gzip
634-
635584// Export exports an image to a Tar stream.
636585// OCI format is used by default.
637586// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
638- func (c * Client ) Export (ctx context.Context , desc ocispec.Descriptor , opts ... ExportOpt ) (io.ReadCloser , error ) {
639- var eopts exportOpts
640- for _ , o := range opts {
641- if err := o (& eopts ); err != nil {
642- return nil , err
643- }
644- }
645- // use OCI as the default format
646- if eopts .format == "" {
647- eopts .format = ociImageFormat
587+ // TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
588+ func (c * Client ) Export (ctx context.Context , exporter images.Exporter , desc ocispec.Descriptor , opts ... ExportOpt ) (io.ReadCloser , error ) {
589+ _ , err := resolveExportOpt (opts ... ) // unused now
590+ if err != nil {
591+ return nil , err
648592 }
649593 pr , pw := io .Pipe ()
650- switch eopts .format {
651- case ociImageFormat :
652- go func () {
653- pw .CloseWithError (c .exportToOCITar (ctx , desc , pw , eopts ))
654- }()
655- default :
656- return nil , errors .Errorf ("unsupported format: %s" , eopts .format )
657- }
594+ go func () {
595+ pw .CloseWithError (exporter .Export (ctx , c .ContentStore (), desc , pw ))
596+ }()
658597 return pr , nil
659598}
0 commit comments