Skip to content

Commit

Permalink
allow multiple images pull (#975)
Browse files Browse the repository at this point in the history
* allow multiple images pull

* run hack/update-codegen.sh

* implement MultiWriteXXX

* add doc for MultiWrite api and rework MultiSaveOCI
  • Loading branch information
michelpromonet committed Mar 30, 2021
1 parent a11b12f commit 3259211
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 35 deletions.
30 changes: 18 additions & 12 deletions cmd/crane/cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"log"

"github.com/google/go-containerregistry/pkg/crane"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/cache"
"github.com/spf13/cobra"
)
Expand All @@ -29,29 +30,34 @@ func NewCmdPull(options *[]crane.Option) *cobra.Command {

cmd := &cobra.Command{
Use: "pull IMAGE TARBALL",
Short: "Pull a remote image by reference and store its contents in a tarball",
Args: cobra.ExactArgs(2),
Short: "Pull remote images by reference and store their contents in a tarball",
Args: cobra.MinimumNArgs(2),
Run: func(_ *cobra.Command, args []string) {
src, path := args[0], args[1]
img, err := crane.Pull(src, *options...)
if err != nil {
log.Fatal(err)
}
if cachePath != "" {
img = cache.Image(img, cache.NewFilesystemCache(cachePath))
imageMap := map[string]v1.Image{}
srcList, path := args[:len(args)-1], args[len(args)-1]
for _, src := range srcList {
img, err := crane.Pull(src, *options...)
if err != nil {
log.Fatal(err)
}
if cachePath != "" {
img = cache.Image(img, cache.NewFilesystemCache(cachePath))
}

imageMap[src] = img
}

switch format {
case "tarball":
if err := crane.Save(img, src, path); err != nil {
if err := crane.MultiSave(imageMap, path); err != nil {
log.Fatalf("saving tarball %s: %v", path, err)
}
case "legacy":
if err := crane.SaveLegacy(img, src, path); err != nil {
if err := crane.MultiSaveLegacy(imageMap, path); err != nil {
log.Fatalf("saving legacy tarball %s: %v", path, err)
}
case "oci":
if err := crane.SaveOCI(img, path); err != nil {
if err := crane.MultiSaveOCI(imageMap, path); err != nil {
log.Fatalf("saving oci image layout %s: %v", path, err)
}
default:
Expand Down
2 changes: 1 addition & 1 deletion cmd/crane/doc/crane.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cmd/crane/doc/crane_pull.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 53 additions & 20 deletions pkg/crane/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,36 @@ func Pull(src string, opt ...Option) (v1.Image, error) {

// Save writes the v1.Image img as a tarball at path with tag src.
func Save(img v1.Image, src, path string) error {
ref, err := name.ParseReference(src)
if err != nil {
return fmt.Errorf("parsing ref %q: %v", src, err)
}
imgMap := map[string]v1.Image{src: img}
return MultiSave(imgMap, path)
}

// MultiSave writes collection of v1.Image img with tag as a tarball.
func MultiSave(imgMap map[string]v1.Image, path string) error {
tagToImage := map[name.Tag]v1.Image{}

for src, img := range imgMap {
ref, err := name.ParseReference(src)
if err != nil {
return fmt.Errorf("parsing ref %q: %v", src, err)
}

// WriteToFile wants a tag to write to the tarball, but we might have
// been given a digest.
// If the original ref was a tag, use that. Otherwise, if it was a
// digest, tag the image with :i-was-a-digest instead.
tag, ok := ref.(name.Tag)
if !ok {
d, ok := ref.(name.Digest)
// WriteToFile wants a tag to write to the tarball, but we might have
// been given a digest.
// If the original ref was a tag, use that. Otherwise, if it was a
// digest, tag the image with :i-was-a-digest instead.
tag, ok := ref.(name.Tag)
if !ok {
return fmt.Errorf("ref wasn't a tag or digest")
d, ok := ref.(name.Digest)
if !ok {
return fmt.Errorf("ref wasn't a tag or digest")
}
tag = d.Repository.Tag(iWasADigestTag)
}
tag = d.Repository.Tag(iWasADigestTag)
tagToImage[tag] = img
}

// no progress channel (for now)
return tarball.WriteToFile(path, tag, img)
return tarball.MultiWriteToFile(path, tagToImage)
}

// PullLayer returns the given layer from a registry.
Expand All @@ -80,9 +90,20 @@ func PullLayer(ref string, opt ...Option) (v1.Layer, error) {

// SaveLegacy writes the v1.Image img as a legacy tarball at path with tag src.
func SaveLegacy(img v1.Image, src, path string) error {
ref, err := name.ParseReference(src)
if err != nil {
return fmt.Errorf("parsing ref %q: %v", src, err)
imgMap := map[string]v1.Image{src: img}
return MultiSave(imgMap, path)
}

// MultiSaveLegacy writes collection of v1.Image img with tag as a legacy tarball.
func MultiSaveLegacy(imgMap map[string]v1.Image, path string) error {
refToImage := map[name.Reference]v1.Image{}

for src, img := range imgMap {
ref, err := name.ParseReference(src)
if err != nil {
return fmt.Errorf("parsing ref %q: %v", src, err)
}
refToImage[ref] = img
}

w, err := os.Create(path)
Expand All @@ -91,18 +112,30 @@ func SaveLegacy(img v1.Image, src, path string) error {
}
defer w.Close()

return legacy.Write(ref, img, w)
return legacy.MultiWrite(refToImage, w)
}

// SaveOCI writes the v1.Image img as an OCI Image Layout at path. If a layout
// already exists at that path, it will add the image to the index.
func SaveOCI(img v1.Image, path string) error {
imgMap := map[string]v1.Image{"": img}
return MultiSaveOCI(imgMap, path)
}

// MultiSaveOCI writes collection of v1.Image img as an OCI Image Layout at path. If a layout
// already exists at that path, it will add the image to the index.
func MultiSaveOCI(imgMap map[string]v1.Image, path string) error {
p, err := layout.FromPath(path)
if err != nil {
p, err = layout.Write(path, empty.Index)
if err != nil {
return err
}
}
return p.AppendImage(img)
for _, img := range imgMap {
if err = p.AppendImage(img); err != nil {
return err
}
}
return nil
}

0 comments on commit 3259211

Please sign in to comment.