diff --git a/cmd/containers-storage/diff.go b/cmd/containers-storage/diff.go index 28cc38fe6..777465771 100644 --- a/cmd/containers-storage/diff.go +++ b/cmd/containers-storage/diff.go @@ -12,11 +12,12 @@ import ( ) var ( - applyDiffFile = "" - diffFile = "" - diffGzip = false - diffBzip2 = false - diffXz = false + applyDiffFile = "" + diffFile = "" + diffUncompressed = false + diffGzip = false + diffBzip2 = false + diffXz = false ) func changes(flags *mflag.FlagSet, action string, m storage.Store, args []string) int { @@ -71,28 +72,27 @@ func diff(flags *mflag.FlagSet, action string, m storage.Store, args []string) i diffStream = f defer f.Close() } - reader, err := m.Diff(from, to) + + options := storage.DiffOptions{} + if diffUncompressed || diffGzip || diffBzip2 || diffXz { + c := archive.Uncompressed + if diffGzip { + c = archive.Gzip + } + if diffBzip2 { + c = archive.Bzip2 + } + if diffXz { + c = archive.Xz + } + options.Compression = &c + } + + reader, err := m.Diff(from, to, &options) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return 1 } - if diffGzip || diffBzip2 || diffXz { - compression := archive.Uncompressed - if diffGzip { - compression = archive.Gzip - } else if diffBzip2 { - compression = archive.Bzip2 - } else if diffXz { - compression = archive.Xz - } - compressor, err := archive.CompressStream(diffStream, compression) - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return 1 - } - diffStream = compressor - defer compressor.Close() - } _, err = io.Copy(diffStream, reader) reader.Close() if err != nil { @@ -171,9 +171,10 @@ func init() { action: diff, addFlags: func(flags *mflag.FlagSet, cmd *command) { flags.StringVar(&diffFile, []string{"-file", "f"}, "", "Write to file instead of stdout") + flags.BoolVar(&diffUncompressed, []string{"-uncompressed", "u"}, diffUncompressed, "Use no compression") flags.BoolVar(&diffGzip, []string{"-gzip", "c"}, diffGzip, "Compress using gzip") - flags.BoolVar(&diffBzip2, []string{"-bzip2", "-bz2", "b"}, diffBzip2, "Compress using bzip2") - flags.BoolVar(&diffXz, []string{"-xz", "x"}, diffXz, "Compress using xz") + flags.BoolVar(&diffBzip2, []string{"-bzip2", "-bz2", "b"}, diffBzip2, "Compress using bzip2 (not currently supported)") + flags.BoolVar(&diffXz, []string{"-xz", "x"}, diffXz, "Compress using xz (not currently supported)") }, }) commands = append(commands, command{ diff --git a/docs/containers-storage-diff.md b/docs/containers-storage-diff.md index 120002178..6173eb151 100644 --- a/docs/containers-storage-diff.md +++ b/docs/containers-storage-diff.md @@ -19,9 +19,14 @@ Write the diff to the specified file instead of stdout. **-c | --gzip** -Compress the diff using gzip compression. If the layer was populated by a -layer diff, and that layer diff was compressed, this will be done -automatically. +Force the diff to be compressed using gzip compression. If the layer was +populated by a layer diff, and that layer diff was compressed, this will be +done automatically. + +**-u | --uncompressed** + +Force the diff to be uncompressed. If the layer was populated by a layer diff, +and that layer diff was compressed, it will be decompressed for output. ## EXAMPLE **oci-storage diff my-base-layer** diff --git a/layers.go b/layers.go index fa04acdd0..a207fa4a4 100644 --- a/layers.go +++ b/layers.go @@ -81,6 +81,12 @@ type layerMountPoint struct { MountCount int `json:"count"` } +// DiffOptions override the default behavior of Diff() methods. +type DiffOptions struct { + // Compression, if set overrides the default compressor when generating a diff. + Compression *archive.Compression +} + // ROLayerStore wraps a graph driver, adding the ability to refer to layers by // name, and keeping track of parent-child relationships, along with a list of // all known layers. @@ -107,8 +113,9 @@ type ROLayerStore interface { // Diff produces a tarstream which can be applied to a layer with the contents // of the first layer to produce a layer with the contents of the second layer. // By default, the parent of the second layer is used as the first - // layer, so it need not be specified. - Diff(from, to string) (io.ReadCloser, error) + // layer, so it need not be specified. Options can be used to override + // default behavior, but are also not required. + Diff(from, to string, options *DiffOptions) (io.ReadCloser, error) // DiffSize produces an estimate of the length of the tarstream which would be // produced by Diff. @@ -741,13 +748,15 @@ func (r *layerStore) newFileGetter(id string) (drivers.FileGetCloser, error) { }, nil } -func (r *layerStore) Diff(from, to string) (io.ReadCloser, error) { +func (r *layerStore) Diff(from, to string, options *DiffOptions) (io.ReadCloser, error) { var metadata storage.Unpacker from, to, toLayer, err := r.findParentAndLayer(from, to) if err != nil { return nil, ErrLayerUnknown } + // Default to applying the type of encryption that we noted was used + // for the layerdiff when it was applied. compression := archive.Uncompressed if cflag, ok := toLayer.Flags[compressionFlag]; ok { if ctype, ok := cflag.(float64); ok { @@ -756,6 +765,11 @@ func (r *layerStore) Diff(from, to string) (io.ReadCloser, error) { compression = archive.Compression(ctype) } } + // If a particular compression type (or no compression) was selected, + // use that instead. + if options != nil && options.Compression != nil { + compression = *options.Compression + } if from != toLayer.Parent { diff, err := r.driver.Diff(to, from) if err == nil && (compression != archive.Uncompressed) { diff --git a/store.go b/store.go index 7a2d29db9..d2b65ea57 100644 --- a/store.go +++ b/store.go @@ -298,8 +298,8 @@ type Store interface { DiffSize(from, to string) (int64, error) // Diff returns the tarstream which would specify the changes returned by - // Changes. - Diff(from, to string) (io.ReadCloser, error) + // Changes. If options are passed in, they can override default behaviors. + Diff(from, to string, options *DiffOptions) (io.ReadCloser, error) // ApplyDiff applies a tarstream to a layer. Information about the tarstream // is cached with the layer. Typically, a layer which is populated using a @@ -1747,7 +1747,7 @@ func (s *store) DiffSize(from, to string) (int64, error) { return -1, ErrLayerUnknown } -func (s *store) Diff(from, to string) (io.ReadCloser, error) { +func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, error) { rlstore, err := s.LayerStore() if err != nil { return nil, err @@ -1764,7 +1764,7 @@ func (s *store) Diff(from, to string) (io.ReadCloser, error) { rlstore.Load() } if rlstore.Exists(to) { - return rlstore.Diff(from, to) + return rlstore.Diff(from, to, options) } } return nil, ErrLayerUnknown