diff --git a/pkg/compression/compression.go b/pkg/compression/compression.go index 267868c6..f0c4febb 100644 --- a/pkg/compression/compression.go +++ b/pkg/compression/compression.go @@ -7,6 +7,8 @@ import ( "io" "io/ioutil" + "github.com/containers/image/pkg/compression/internal" + "github.com/containers/image/pkg/compression/types" "github.com/klauspost/pgzip" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -14,36 +16,26 @@ import ( ) // Algorithm is a compression algorithm that can be used for CompressStream. -type Algorithm struct { - name string - prefix []byte - decompressor DecompressorFunc - compressor compressorFunc -} +type Algorithm = types.Algorithm var ( // Gzip compression. - Gzip = Algorithm{"gzip", []byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor} + Gzip = internal.NewAlgorithm("gzip", []byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor) // Bzip2 compression. - Bzip2 = Algorithm{"bzip2", []byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor} + Bzip2 = internal.NewAlgorithm("bzip2", []byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor) // Xz compression. - Xz = Algorithm{"Xz", []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor} + Xz = internal.NewAlgorithm("Xz", []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor) // Zstd compression. - Zstd = Algorithm{"zstd", []byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor} + Zstd = internal.NewAlgorithm("zstd", []byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor) compressionAlgorithms = map[string]Algorithm{ - Gzip.name: Gzip, - Bzip2.name: Bzip2, - Xz.name: Xz, - Zstd.name: Zstd, + Gzip.Name(): Gzip, + Bzip2.Name(): Bzip2, + Xz.Name(): Xz, + Zstd.Name(): Zstd, } ) -// Name returns the name for the compression algorithm. -func (c Algorithm) Name() string { - return c.name -} - // AlgorithmByName returns the compressor by its name func AlgorithmByName(name string) (Algorithm, error) { algorithm, ok := compressionAlgorithms[name] @@ -55,7 +47,7 @@ func AlgorithmByName(name string) (Algorithm, error) { // DecompressorFunc returns the decompressed stream, given a compressed stream. // The caller must call Close() on the decompressed stream (even if the compressed input stream does not need closing!). -type DecompressorFunc func(io.Reader) (io.ReadCloser, error) +type DecompressorFunc = internal.DecompressorFunc // GzipDecompressor is a DecompressorFunc for the gzip compression algorithm. func GzipDecompressor(r io.Reader) (io.ReadCloser, error) { @@ -76,10 +68,6 @@ func XzDecompressor(r io.Reader) (io.ReadCloser, error) { return ioutil.NopCloser(r), nil } -// compressorFunc writes the compressed stream to the given writer using the specified compression level. -// The caller must call Close() on the stream (even if the input stream does not need closing!). -type compressorFunc func(io.Writer, *int) (io.WriteCloser, error) - // gzipCompressor is a CompressorFunc for the gzip compression algorithm. func gzipCompressor(r io.Writer, level *int) (io.WriteCloser, error) { if level != nil { @@ -100,7 +88,7 @@ func xzCompressor(r io.Writer, level *int) (io.WriteCloser, error) { // CompressStream returns the compressor by its name func CompressStream(dest io.Writer, algo Algorithm, level *int) (io.WriteCloser, error) { - return algo.compressor(dest, level) + return internal.AlgorithmCompressor(algo)(dest, level) } // DetectCompressionFormat returns a DecompressorFunc if the input is recognized as a compressed format, nil otherwise. @@ -118,10 +106,10 @@ func DetectCompressionFormat(input io.Reader) (Algorithm, DecompressorFunc, io.R var retAlgo Algorithm var decompressor DecompressorFunc for _, algo := range compressionAlgorithms { - if bytes.HasPrefix(buffer[:n], algo.prefix) { - logrus.Debugf("Detected compression format %s", algo.name) + if bytes.HasPrefix(buffer[:n], internal.AlgorithmPrefix(algo)) { + logrus.Debugf("Detected compression format %s", algo.Name()) retAlgo = algo - decompressor = algo.decompressor + decompressor = internal.AlgorithmDecompressor(algo) break } } diff --git a/pkg/compression/internal/types.go b/pkg/compression/internal/types.go new file mode 100644 index 00000000..6092a951 --- /dev/null +++ b/pkg/compression/internal/types.go @@ -0,0 +1,57 @@ +package internal + +import "io" + +// CompressorFunc writes the compressed stream to the given writer using the specified compression level. +// The caller must call Close() on the stream (even if the input stream does not need closing!). +type CompressorFunc func(io.Writer, *int) (io.WriteCloser, error) + +// DecompressorFunc returns the decompressed stream, given a compressed stream. +// The caller must call Close() on the decompressed stream (even if the compressed input stream does not need closing!). +type DecompressorFunc func(io.Reader) (io.ReadCloser, error) + +// Algorithm is a compression algorithm that can be used for CompressStream. +type Algorithm struct { + name string + prefix []byte + decompressor DecompressorFunc + compressor CompressorFunc +} + +// NewAlgorithm creates an Algorithm instance. +// This function exists so that Algorithm instances can only be created by code that +// is allowed to import this internal subpackage. +func NewAlgorithm(name string, prefix []byte, decompressor DecompressorFunc, compressor CompressorFunc) Algorithm { + return Algorithm{ + name: name, + prefix: prefix, + decompressor: decompressor, + compressor: compressor, + } +} + +// Name returns the name for the compression algorithm. +func (c Algorithm) Name() string { + return c.name +} + +// AlgorithmCompressor returns the compressor field of algo. +// This is a function instead of a public method so that it is only callable from by code +// that is allowed to import this internal subpackage. +func AlgorithmCompressor(algo Algorithm) CompressorFunc { + return algo.compressor +} + +// AlgorithmDecompressor returns the decompressor field of algo. +// This is a function instead of a public method so that it is only callable from by code +// that is allowed to import this internal subpackage. +func AlgorithmDecompressor(algo Algorithm) DecompressorFunc { + return algo.decompressor +} + +// AlgorithmPrefix returns the prefix field of algo. +// This is a function instead of a public method so that it is only callable from by code +// that is allowed to import this internal subpackage. +func AlgorithmPrefix(algo Algorithm) []byte { + return algo.prefix +} diff --git a/pkg/compression/types/types.go b/pkg/compression/types/types.go new file mode 100644 index 00000000..613342b4 --- /dev/null +++ b/pkg/compression/types/types.go @@ -0,0 +1,13 @@ +package types + +import ( + "github.com/containers/image/pkg/compression/internal" +) + +// DecompressorFunc returns the decompressed stream, given a compressed stream. +// The caller must call Close() on the decompressed stream (even if the compressed input stream does not need closing!). +type DecompressorFunc = internal.DecompressorFunc + +// Algorithm is a compression algorithm provided and supported by pkg/compression. +// It can’t be supplied from the outside. +type Algorithm = internal.Algorithm diff --git a/types/types.go b/types/types.go index 0d2fb7d8..d9486d5c 100644 --- a/types/types.go +++ b/types/types.go @@ -6,8 +6,8 @@ import ( "time" "github.com/containers/image/docker/reference" - "github.com/containers/image/pkg/compression" - "github.com/opencontainers/go-digest" + compression "github.com/containers/image/pkg/compression/types" + digest "github.com/opencontainers/go-digest" v1 "github.com/opencontainers/image-spec/specs-go/v1" )