Skip to content

Commit

Permalink
Merge pull request #716 from mtrmac/compression-types
Browse files Browse the repository at this point in the history
Don’t drag in compression implementations into c/image/types
  • Loading branch information
rhatdan authored Oct 1, 2019
2 parents e8c1452 + f77dc7d commit df216d7
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 30 deletions.
44 changes: 16 additions & 28 deletions pkg/compression/compression.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,35 @@ 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"
"github.com/ulikunitz/xz"
)

// 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]
Expand All @@ -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) {
Expand All @@ -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 {
Expand All @@ -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.
Expand All @@ -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
}
}
Expand Down
57 changes: 57 additions & 0 deletions pkg/compression/internal/types.go
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 13 additions & 0 deletions pkg/compression/types/types.go
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down

0 comments on commit df216d7

Please sign in to comment.