...

Source file src/github.com/google/go-containerregistry/pkg/v1/cache/cache.go

Documentation: github.com/google/go-containerregistry/pkg/v1/cache

     1  // Copyright 2021 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 cache provides methods to cache layers.
    16  package cache
    17  
    18  import (
    19  	"errors"
    20  	"io"
    21  
    22  	"github.com/google/go-containerregistry/pkg/logs"
    23  	v1 "github.com/google/go-containerregistry/pkg/v1"
    24  	"github.com/google/go-containerregistry/pkg/v1/types"
    25  )
    26  
    27  // Cache encapsulates methods to interact with cached layers.
    28  type Cache interface {
    29  	// Put writes the Layer to the Cache.
    30  	//
    31  	// The returned Layer should be used for future operations, since lazy
    32  	// cachers might only populate the cache when the layer is actually
    33  	// consumed.
    34  	//
    35  	// The returned layer can be consumed, and the cache entry populated,
    36  	// by calling either Compressed or Uncompressed and consuming the
    37  	// returned io.ReadCloser.
    38  	Put(v1.Layer) (v1.Layer, error)
    39  
    40  	// Get returns the Layer cached by the given Hash, or ErrNotFound if no
    41  	// such layer was found.
    42  	Get(v1.Hash) (v1.Layer, error)
    43  
    44  	// Delete removes the Layer with the given Hash from the Cache.
    45  	Delete(v1.Hash) error
    46  }
    47  
    48  // ErrNotFound is returned by Get when no layer with the given Hash is found.
    49  var ErrNotFound = errors.New("layer was not found")
    50  
    51  // Image returns a new Image which wraps the given Image, whose layers will be
    52  // pulled from the Cache if they are found, and written to the Cache as they
    53  // are read from the underlying Image.
    54  func Image(i v1.Image, c Cache) v1.Image {
    55  	return &image{
    56  		Image: i,
    57  		c:     c,
    58  	}
    59  }
    60  
    61  type image struct {
    62  	v1.Image
    63  	c Cache
    64  }
    65  
    66  func (i *image) Layers() ([]v1.Layer, error) {
    67  	ls, err := i.Image.Layers()
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	out := make([]v1.Layer, len(ls))
    73  	for idx, l := range ls {
    74  		out[idx] = &lazyLayer{inner: l, c: i.c}
    75  	}
    76  	return out, nil
    77  }
    78  
    79  type lazyLayer struct {
    80  	inner v1.Layer
    81  	c     Cache
    82  }
    83  
    84  func (l *lazyLayer) Compressed() (io.ReadCloser, error) {
    85  	digest, err := l.inner.Digest()
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	if cl, err := l.c.Get(digest); err == nil {
    91  		// Layer found in the cache.
    92  		logs.Progress.Printf("Layer %s found (compressed) in cache", digest)
    93  		return cl.Compressed()
    94  	} else if !errors.Is(err, ErrNotFound) {
    95  		return nil, err
    96  	}
    97  
    98  	// Not cached, pull and return the real layer.
    99  	logs.Progress.Printf("Layer %s not found (compressed) in cache, getting", digest)
   100  	rl, err := l.c.Put(l.inner)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return rl.Compressed()
   105  }
   106  
   107  func (l *lazyLayer) Uncompressed() (io.ReadCloser, error) {
   108  	diffID, err := l.inner.DiffID()
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	if cl, err := l.c.Get(diffID); err == nil {
   113  		// Layer found in the cache.
   114  		logs.Progress.Printf("Layer %s found (uncompressed) in cache", diffID)
   115  		return cl.Uncompressed()
   116  	} else if !errors.Is(err, ErrNotFound) {
   117  		return nil, err
   118  	}
   119  
   120  	// Not cached, pull and return the real layer.
   121  	logs.Progress.Printf("Layer %s not found (uncompressed) in cache, getting", diffID)
   122  	rl, err := l.c.Put(l.inner)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	return rl.Uncompressed()
   127  }
   128  
   129  func (l *lazyLayer) Size() (int64, error)                { return l.inner.Size() }
   130  func (l *lazyLayer) DiffID() (v1.Hash, error)            { return l.inner.DiffID() }
   131  func (l *lazyLayer) Digest() (v1.Hash, error)            { return l.inner.Digest() }
   132  func (l *lazyLayer) MediaType() (types.MediaType, error) { return l.inner.MediaType() }
   133  
   134  func (i *image) LayerByDigest(h v1.Hash) (v1.Layer, error) {
   135  	l, err := i.c.Get(h)
   136  	if errors.Is(err, ErrNotFound) {
   137  		// Not cached, get it and write it.
   138  		l, err := i.Image.LayerByDigest(h)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		return i.c.Put(l)
   143  	}
   144  	return l, err
   145  }
   146  
   147  func (i *image) LayerByDiffID(h v1.Hash) (v1.Layer, error) {
   148  	l, err := i.c.Get(h)
   149  	if errors.Is(err, ErrNotFound) {
   150  		// Not cached, get it and write it.
   151  		l, err := i.Image.LayerByDiffID(h)
   152  		if err != nil {
   153  			return nil, err
   154  		}
   155  		return i.c.Put(l)
   156  	}
   157  	return l, err
   158  }
   159  
   160  // ImageIndex returns a new ImageIndex which wraps the given ImageIndex's
   161  // children with either Image(child, c) or ImageIndex(child, c) depending on type.
   162  func ImageIndex(ii v1.ImageIndex, c Cache) v1.ImageIndex {
   163  	return &imageIndex{
   164  		inner: ii,
   165  		c:     c,
   166  	}
   167  }
   168  
   169  type imageIndex struct {
   170  	inner v1.ImageIndex
   171  	c     Cache
   172  }
   173  
   174  func (ii *imageIndex) MediaType() (types.MediaType, error)       { return ii.inner.MediaType() }
   175  func (ii *imageIndex) Digest() (v1.Hash, error)                  { return ii.inner.Digest() }
   176  func (ii *imageIndex) Size() (int64, error)                      { return ii.inner.Size() }
   177  func (ii *imageIndex) IndexManifest() (*v1.IndexManifest, error) { return ii.inner.IndexManifest() }
   178  func (ii *imageIndex) RawManifest() ([]byte, error)              { return ii.inner.RawManifest() }
   179  
   180  func (ii *imageIndex) Image(h v1.Hash) (v1.Image, error) {
   181  	i, err := ii.inner.Image(h)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	return Image(i, ii.c), nil
   186  }
   187  
   188  func (ii *imageIndex) ImageIndex(h v1.Hash) (v1.ImageIndex, error) {
   189  	idx, err := ii.inner.ImageIndex(h)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return ImageIndex(idx, ii.c), nil
   194  }
   195  

View as plain text