diff --git a/cmd/podman/load.go b/cmd/podman/load.go index 3d9c1c056cd6..51c00314de57 100644 --- a/cmd/podman/load.go +++ b/cmd/podman/load.go @@ -90,21 +90,20 @@ func loadCmd(c *cliconfig.LoadValues) error { c.Input = outFile.Name() } - names, err := runtime.LoadImage(getContext(), imageName, c) + images, err := runtime.LoadImages(getContext(), imageName, c) if err != nil { return err } if len(imageName) > 0 { - split := strings.Split(names, ",") // FIXME: This should just be an array - loadedImageName := split[0] - newImage, err := runtime.NewImageFromLocal(loadedImageName) // FIXME: How does it make sense to use the name for one iamge and ignore the others?... It doesn't really work anyway. - if err != nil { - return err - } + newImage := images[0] // FIXME: How does it make sense to use the name for one image and ignore the others?... It doesn't really work anyway. if err := newImage.TagImage(imageName); err != nil { - return errors.Wrapf(err, "error adding '%s' to image %q", imageName, loadedImageName) + return errors.Wrapf(err, "error adding '%s' to image %q", imageName, newImage.InputName) } } - fmt.Println("Loaded image(s): " + names) + names := []string{} + for _, i := range images { + names = append(names, i.InputName) + } + fmt.Println("Loaded image(s): " + strings.Join(names, ", ")) return nil } diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index bae1c1ed870f..248a11093b18 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -21,7 +21,7 @@ import ( "github.com/containers/image/v5/directory" dockerarchive "github.com/containers/image/v5/docker/archive" ociarchive "github.com/containers/image/v5/oci/archive" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" ) // Runtime API @@ -252,8 +252,9 @@ func DownloadFromFile(reader *os.File) (string, error) { return outFile.Name(), nil } -// LoadImage loads a container image into local storage -func (r *Runtime) LoadImage(ctx context.Context, name, inputFile string, writer io.Writer, signaturePolicy string) (string, error) { +// LoadImages loads one or more container images into local storage, and returns an array of image objects. +// WARNING: This is an UNSTABLE WIP interface +func (r *Runtime) LoadImages(ctx context.Context, name, inputFile string, writer io.Writer, signaturePolicy string) ([]*image.Image, error) { var newImages []*image.Image src, err := dockerarchive.ParseReference(inputFile) // FIXME? We should add dockerarchive.NewReference() if err == nil { @@ -271,14 +272,21 @@ func (r *Runtime) LoadImage(ctx context.Context, name, inputFile string, writer newImages, err = r.ImageRuntime().LoadFromArchiveReference(ctx, src, signaturePolicy, writer) } if err != nil { - return "", errors.Wrapf(err, "error pulling %q", name) + return nil, errors.Wrapf(err, "error pulling %q", name) } } } - return getImageNames(newImages), nil + return newImages, nil } -func getImageNames(images []*image.Image) string { +// LoadImage loads a container image into local storage +// +// Deprecated: Use LoadImages instead of handling a ", "-separated string (!!) +func (r *Runtime) LoadImage(ctx context.Context, name, inputFile string, writer io.Writer, signaturePolicy string) (string, error) { + images, err := r.LoadImages(ctx, name, inputFile, writer, signaturePolicy) + if err != nil { + return "", err + } var names string for i := range images { if i == 0 { @@ -287,5 +295,5 @@ func getImageNames(images []*image.Image) string { names += ", " + images[i].InputName } } - return names + return names, nil } diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 40089797dd6c..422d255c8222 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -353,15 +353,24 @@ func (r *LocalRuntime) SaveImage(ctx context.Context, c *cliconfig.SaveValues) e return newImage.Save(ctx, source, c.Format, c.Output, additionalTags, c.Quiet, c.Compress) } -// LoadImage is a wrapper function for libpod LoadImage -func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfig.LoadValues) (string, error) { +// LoadImages is a wrapper function for libpod LoadImages +func (r *LocalRuntime) LoadImages(ctx context.Context, name string, cli *cliconfig.LoadValues) ([]*ContainerImage, error) { var ( writer io.Writer ) if !cli.Quiet { writer = os.Stderr } - return r.Runtime.LoadImage(ctx, name, cli.Input, writer, cli.SignaturePolicy) + imgs, err := r.Runtime.LoadImages(ctx, name, cli.Input, writer, cli.SignaturePolicy) + if err != nil { + return nil, err + } + containerImages := []*ContainerImage{} + for _, i := range imgs { + ci := ContainerImage{i} + containerImages = append(containerImages, &ci) + } + return containerImages, nil } // IsImageNotFound checks if the error indicates that no image was found. diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index c908358ff288..82809bfc284a 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -862,8 +862,8 @@ func (r *LocalRuntime) SaveImage(ctx context.Context, c *cliconfig.SaveValues) e return nil } -// LoadImage loads a container image from a remote client's filesystem -func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfig.LoadValues) (string, error) { +// LoadImages loads a container image from a remote client's filesystem +func (r *LocalRuntime) LoadImages(ctx context.Context, name string, cli *cliconfig.LoadValues) ([]*ContainerImage, error) { var names string remoteTempFile, err := r.SendFileOverVarlink(cli.Input) if err != nil { @@ -892,7 +892,15 @@ func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfi break } } - return names, nil + images := []*ContainerImage{} + for _, name := range strings.Split(names, ", ") { + ci, err := r.NewImageFromLocal(iid) + if err != nil { + return nil, err + } + images = append(images, ci) + } + return images, nil } // IsImageNotFound checks if the error indicates that no image was found. diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go index c65db7575469..5a8e9ff5b77d 100644 --- a/pkg/api/handlers/generic/images.go +++ b/pkg/api/handlers/generic/images.go @@ -348,15 +348,19 @@ func LoadImages(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file")) return } - id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "") + images, err := runtime.LoadImages(r.Context(), "", f.Name(), writer, "") //id, err := runtime.Import(r.Context()) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image")) return } + names := []string{} + for _, i := range images { + names = append(names, i.InputName) + } utils.WriteResponse(w, http.StatusOK, struct { Stream string `json:"stream"` }{ - Stream: fmt.Sprintf("Loaded image: %s\n", id), + Stream: fmt.Sprintf("Loaded image: %s\n", strings.Join(names, ", ")), }) } diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 333595a96e59..d3b4581c0eae 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -903,7 +903,7 @@ func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageS // LoadImage ... func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error { var ( - names string + images []*image.Image writer io.Writer err error ) @@ -918,7 +918,7 @@ func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, c := make(chan error) go func() { - names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "") + images, err = i.Runtime.LoadImages(getContext(), name, inputFile, writer, "") c <- err close(c) }() @@ -957,9 +957,13 @@ func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, } call.Continues = false + names := []string{} + for _, i := range images { + names = append(names, i.InputName) + } br := iopodman.MoreResponse{ Logs: log, - Id: names, + Id: strings.Join(names, ", "), } if deleteInputFile { if err := os.Remove(inputFile); err != nil {