Skip to content

Commit

Permalink
Implement partial.UncompressedSize
Browse files Browse the repository at this point in the history
This allows access to an optional method that v1.Layers can implement to
cheaply get the size of the uncompressed contents of a layer. This is
useful in situations where you need to know the size of the contents
before writing them (e.g. pkg/legacy/tarball.Write).
  • Loading branch information
jonjohnsonjr committed Jan 14, 2020
1 parent f4fb41b commit 5dc7958
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions pkg/v1/partial/with.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,60 @@ type WithDiffID interface {
type withDescriptor interface {
Descriptor() (*v1.Descriptor, error)
}

type withUncompressedSize interface {
UncompressedSize() (int64, error)
}

func uncompressedSizer(l v1.Layer) (withUncompressedSize, bool) {
// If the layer implements UncompressedSize itself, return that.
if wus, ok := l.(withUncompressedSize); ok {
return wus, true
}

// Otherwise, try to unwrap any partial implementations to see
// if the wrapped struct implements CompressedSize.
if ule, ok := l.(*uncompressedLayerExtender); ok {
if wus, ok := ule.UncompressedLayer.(withUncompressedSize); ok {
return wus, true
}
}
if cle, ok := l.(*compressedLayerExtender); ok {
if wus, ok := cle.CompressedLayer.(withUncompressedSize); ok {
return wus, true
}
}
return nil, false
}

// HasUncompressedSize returns true if the layer or its underling partial
// implementation implements UncompressedSize. Calling UncompressedSize. If
// this returns true, calling UncompressedSize should be efficient.
func HasUncompressedSize(l v1.Layer) bool {
_, ok := uncompressedSizer(l)
return ok
}

// UncompressedSize returns the size of the Uncompressed layer. If the
// underlying implementation doesn't implement UncompressedSize directly,
// this will compute the uncompressedSize by reading everything returned
// by Compressed(). This is potentially expensive and may consume the contents
// for streaming layers. See HasUncompressedSize for when it is safe to call
// this function.
func UncompressedSize(l v1.Layer) (int64, error) {
if wus, ok := uncompressedSizer(l); ok {
return wus.UncompressedSize()
}

// The layer doens't implement CompressedSize, we need to compute it.
rc, err := l.Uncompressed()
if err != nil {
return -1, err
}
defer rc.Close()
n, err := io.Copy(ioutil.Discard, rc)
if err != nil {
return -1, err
}
return n, nil
}

0 comments on commit 5dc7958

Please sign in to comment.