...

Source file src/github.com/google/go-containerregistry/pkg/crane/pull.go

Documentation: github.com/google/go-containerregistry/pkg/crane

     1  // Copyright 2018 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package crane
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  
    21  	legacy "github.com/google/go-containerregistry/pkg/legacy/tarball"
    22  	"github.com/google/go-containerregistry/pkg/name"
    23  	v1 "github.com/google/go-containerregistry/pkg/v1"
    24  	"github.com/google/go-containerregistry/pkg/v1/empty"
    25  	"github.com/google/go-containerregistry/pkg/v1/layout"
    26  	"github.com/google/go-containerregistry/pkg/v1/remote"
    27  	"github.com/google/go-containerregistry/pkg/v1/tarball"
    28  )
    29  
    30  // Tag applied to images that were pulled by digest. This denotes that the
    31  // image was (probably) never tagged with this, but lets us avoid applying the
    32  // ":latest" tag which might be misleading.
    33  const iWasADigestTag = "i-was-a-digest"
    34  
    35  // Pull returns a v1.Image of the remote image src.
    36  func Pull(src string, opt ...Option) (v1.Image, error) {
    37  	o := makeOptions(opt...)
    38  	ref, err := name.ParseReference(src, o.Name...)
    39  	if err != nil {
    40  		return nil, fmt.Errorf("parsing reference %q: %w", src, err)
    41  	}
    42  
    43  	return remote.Image(ref, o.Remote...)
    44  }
    45  
    46  // Save writes the v1.Image img as a tarball at path with tag src.
    47  func Save(img v1.Image, src, path string) error {
    48  	imgMap := map[string]v1.Image{src: img}
    49  	return MultiSave(imgMap, path)
    50  }
    51  
    52  // MultiSave writes collection of v1.Image img with tag as a tarball.
    53  func MultiSave(imgMap map[string]v1.Image, path string, opt ...Option) error {
    54  	o := makeOptions(opt...)
    55  	tagToImage := map[name.Tag]v1.Image{}
    56  
    57  	for src, img := range imgMap {
    58  		ref, err := name.ParseReference(src, o.Name...)
    59  		if err != nil {
    60  			return fmt.Errorf("parsing ref %q: %w", src, err)
    61  		}
    62  
    63  		// WriteToFile wants a tag to write to the tarball, but we might have
    64  		// been given a digest.
    65  		// If the original ref was a tag, use that. Otherwise, if it was a
    66  		// digest, tag the image with :i-was-a-digest instead.
    67  		tag, ok := ref.(name.Tag)
    68  		if !ok {
    69  			d, ok := ref.(name.Digest)
    70  			if !ok {
    71  				return fmt.Errorf("ref wasn't a tag or digest")
    72  			}
    73  			tag = d.Repository.Tag(iWasADigestTag)
    74  		}
    75  		tagToImage[tag] = img
    76  	}
    77  	// no progress channel (for now)
    78  	return tarball.MultiWriteToFile(path, tagToImage)
    79  }
    80  
    81  // PullLayer returns the given layer from a registry.
    82  func PullLayer(ref string, opt ...Option) (v1.Layer, error) {
    83  	o := makeOptions(opt...)
    84  	digest, err := name.NewDigest(ref, o.Name...)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	return remote.Layer(digest, o.Remote...)
    90  }
    91  
    92  // SaveLegacy writes the v1.Image img as a legacy tarball at path with tag src.
    93  func SaveLegacy(img v1.Image, src, path string) error {
    94  	imgMap := map[string]v1.Image{src: img}
    95  	return MultiSave(imgMap, path)
    96  }
    97  
    98  // MultiSaveLegacy writes collection of v1.Image img with tag as a legacy tarball.
    99  func MultiSaveLegacy(imgMap map[string]v1.Image, path string) error {
   100  	refToImage := map[name.Reference]v1.Image{}
   101  
   102  	for src, img := range imgMap {
   103  		ref, err := name.ParseReference(src)
   104  		if err != nil {
   105  			return fmt.Errorf("parsing ref %q: %w", src, err)
   106  		}
   107  		refToImage[ref] = img
   108  	}
   109  
   110  	w, err := os.Create(path)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	defer w.Close()
   115  
   116  	return legacy.MultiWrite(refToImage, w)
   117  }
   118  
   119  // SaveOCI writes the v1.Image img as an OCI Image Layout at path. If a layout
   120  // already exists at that path, it will add the image to the index.
   121  func SaveOCI(img v1.Image, path string) error {
   122  	imgMap := map[string]v1.Image{"": img}
   123  	return MultiSaveOCI(imgMap, path)
   124  }
   125  
   126  // MultiSaveOCI writes collection of v1.Image img as an OCI Image Layout at path. If a layout
   127  // already exists at that path, it will add the image to the index.
   128  func MultiSaveOCI(imgMap map[string]v1.Image, path string) error {
   129  	p, err := layout.FromPath(path)
   130  	if err != nil {
   131  		p, err = layout.Write(path, empty.Index)
   132  		if err != nil {
   133  			return err
   134  		}
   135  	}
   136  	for _, img := range imgMap {
   137  		if err = p.AppendImage(img); err != nil {
   138  			return err
   139  		}
   140  	}
   141  	return nil
   142  }
   143  

View as plain text