From fb0b0e7cfe21c80ae3970ecedcdf9190cbf82727 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 15 Jun 2017 18:40:55 -0400 Subject: [PATCH] Make Diff() methods take an optional *DiffOptions Add an optional *DiffOptions parameter to Diff() methods (which can be nil), to allow overriding of default behaviors. At this time, that's just what type of compression is applied, if we want something other than what was recorded when the diff was applied, but we can add more later if needed. Signed-off-by: Nalin Dahyabhai --- cmd/containers-storage/diff.go | 51 +++++++++++++++++---------------- docs/containers-storage-diff.md | 11 +++++-- layers.go | 20 +++++++++++-- store.go | 8 +++--- 4 files changed, 55 insertions(+), 35 deletions(-) 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 691d84f6d..57ac6bc9b 100644 --- a/layers.go +++ b/layers.go @@ -75,6 +75,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. @@ -101,8 +107,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. @@ -726,13 +733,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 { @@ -741,6 +750,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