...

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

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

     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 partial
    16  
    17  import (
    18  	"io"
    19  
    20  	"github.com/google/go-containerregistry/internal/and"
    21  	"github.com/google/go-containerregistry/internal/compression"
    22  	"github.com/google/go-containerregistry/internal/gzip"
    23  	"github.com/google/go-containerregistry/internal/zstd"
    24  	comp "github.com/google/go-containerregistry/pkg/compression"
    25  	v1 "github.com/google/go-containerregistry/pkg/v1"
    26  	"github.com/google/go-containerregistry/pkg/v1/types"
    27  )
    28  
    29  // CompressedLayer represents the bare minimum interface a natively
    30  // compressed layer must implement for us to produce a v1.Layer
    31  type CompressedLayer interface {
    32  	// Digest returns the Hash of the compressed layer.
    33  	Digest() (v1.Hash, error)
    34  
    35  	// Compressed returns an io.ReadCloser for the compressed layer contents.
    36  	Compressed() (io.ReadCloser, error)
    37  
    38  	// Size returns the compressed size of the Layer.
    39  	Size() (int64, error)
    40  
    41  	// Returns the mediaType for the compressed Layer
    42  	MediaType() (types.MediaType, error)
    43  }
    44  
    45  // compressedLayerExtender implements v1.Image using the compressed base properties.
    46  type compressedLayerExtender struct {
    47  	CompressedLayer
    48  }
    49  
    50  // Uncompressed implements v1.Layer
    51  func (cle *compressedLayerExtender) Uncompressed() (io.ReadCloser, error) {
    52  	rc, err := cle.Compressed()
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	// Often, the "compressed" bytes are not actually-compressed.
    58  	// Peek at the first two bytes to determine whether it's correct to
    59  	// wrap this with gzip.UnzipReadCloser or zstd.UnzipReadCloser.
    60  	cp, pr, err := compression.PeekCompression(rc)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	prc := &and.ReadCloser{
    66  		Reader:    pr,
    67  		CloseFunc: rc.Close,
    68  	}
    69  
    70  	switch cp {
    71  	case comp.GZip:
    72  		return gzip.UnzipReadCloser(prc)
    73  	case comp.ZStd:
    74  		return zstd.UnzipReadCloser(prc)
    75  	default:
    76  		return prc, nil
    77  	}
    78  }
    79  
    80  // DiffID implements v1.Layer
    81  func (cle *compressedLayerExtender) DiffID() (v1.Hash, error) {
    82  	// If our nested CompressedLayer implements DiffID,
    83  	// then delegate to it instead.
    84  	if wdi, ok := cle.CompressedLayer.(WithDiffID); ok {
    85  		return wdi.DiffID()
    86  	}
    87  	r, err := cle.Uncompressed()
    88  	if err != nil {
    89  		return v1.Hash{}, err
    90  	}
    91  	defer r.Close()
    92  	h, _, err := v1.SHA256(r)
    93  	return h, err
    94  }
    95  
    96  // CompressedToLayer fills in the missing methods from a CompressedLayer so that it implements v1.Layer
    97  func CompressedToLayer(ul CompressedLayer) (v1.Layer, error) {
    98  	return &compressedLayerExtender{ul}, nil
    99  }
   100  
   101  // CompressedImageCore represents the base minimum interface a natively
   102  // compressed image must implement for us to produce a v1.Image.
   103  type CompressedImageCore interface {
   104  	ImageCore
   105  
   106  	// RawManifest returns the serialized bytes of the manifest.
   107  	RawManifest() ([]byte, error)
   108  
   109  	// LayerByDigest is a variation on the v1.Image method, which returns
   110  	// a CompressedLayer instead.
   111  	LayerByDigest(v1.Hash) (CompressedLayer, error)
   112  }
   113  
   114  // compressedImageExtender implements v1.Image by extending CompressedImageCore with the
   115  // appropriate methods computed from the minimal core.
   116  type compressedImageExtender struct {
   117  	CompressedImageCore
   118  }
   119  
   120  // Assert that our extender type completes the v1.Image interface
   121  var _ v1.Image = (*compressedImageExtender)(nil)
   122  
   123  // Digest implements v1.Image
   124  func (i *compressedImageExtender) Digest() (v1.Hash, error) {
   125  	return Digest(i)
   126  }
   127  
   128  // ConfigName implements v1.Image
   129  func (i *compressedImageExtender) ConfigName() (v1.Hash, error) {
   130  	return ConfigName(i)
   131  }
   132  
   133  // Layers implements v1.Image
   134  func (i *compressedImageExtender) Layers() ([]v1.Layer, error) {
   135  	hs, err := FSLayers(i)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	ls := make([]v1.Layer, 0, len(hs))
   140  	for _, h := range hs {
   141  		l, err := i.LayerByDigest(h)
   142  		if err != nil {
   143  			return nil, err
   144  		}
   145  		ls = append(ls, l)
   146  	}
   147  	return ls, nil
   148  }
   149  
   150  // LayerByDigest implements v1.Image
   151  func (i *compressedImageExtender) LayerByDigest(h v1.Hash) (v1.Layer, error) {
   152  	cl, err := i.CompressedImageCore.LayerByDigest(h)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	return CompressedToLayer(cl)
   157  }
   158  
   159  // LayerByDiffID implements v1.Image
   160  func (i *compressedImageExtender) LayerByDiffID(h v1.Hash) (v1.Layer, error) {
   161  	h, err := DiffIDToBlob(i, h)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	return i.LayerByDigest(h)
   166  }
   167  
   168  // ConfigFile implements v1.Image
   169  func (i *compressedImageExtender) ConfigFile() (*v1.ConfigFile, error) {
   170  	return ConfigFile(i)
   171  }
   172  
   173  // Manifest implements v1.Image
   174  func (i *compressedImageExtender) Manifest() (*v1.Manifest, error) {
   175  	return Manifest(i)
   176  }
   177  
   178  // Size implements v1.Image
   179  func (i *compressedImageExtender) Size() (int64, error) {
   180  	return Size(i)
   181  }
   182  
   183  // CompressedToImage fills in the missing methods from a CompressedImageCore so that it implements v1.Image
   184  func CompressedToImage(cic CompressedImageCore) (v1.Image, error) {
   185  	return &compressedImageExtender{
   186  		CompressedImageCore: cic,
   187  	}, nil
   188  }
   189  

View as plain text