From e2cf760c1214c7a4594dbd1ec49c4fabec2e54b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Mon, 24 May 2021 00:11:58 +0300 Subject: [PATCH] remove ByteCounter from rootfs --- internal/cmdrootfs/cmdrootfs.go | 13 +++++----- internal/cmdrootfs/cmdrootfs_test.go | 7 ++++-- rootfs/rootfs.go | 37 ++++++++++++---------------- rootfs/rootfs_test.go | 3 +-- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/internal/cmdrootfs/cmdrootfs.go b/internal/cmdrootfs/cmdrootfs.go index 15b2a7f..7c81eef 100644 --- a/internal/cmdrootfs/cmdrootfs.go +++ b/internal/cmdrootfs/cmdrootfs.go @@ -13,7 +13,11 @@ import ( ) type ( - rootfsFactory func(io.ReadSeeker) io.WriterTo + flattener interface { + Flatten(io.Writer) error + } + + rootfsFactory func(io.ReadSeeker) flattener // Command is "rootfs" command Command struct { @@ -55,10 +59,7 @@ func (c *Command) Execute(args []string) (err error) { out = outf } - if _, err := c.rootfsNew(rd).WriteTo(out); err != nil { - return err - } - return nil + return c.rootfsNew(rd).Flatten(out) } // init() initializes Command with the default options. @@ -67,7 +68,7 @@ func (c *Command) Execute(args []string) (err error) { // command will initialize itself. func (c *Command) init() { c.BaseCommand.Init() - c.rootfsNew = func(r io.ReadSeeker) io.WriterTo { + c.rootfsNew = func(r io.ReadSeeker) flattener { return rootfs.New(r) } } diff --git a/internal/cmdrootfs/cmdrootfs_test.go b/internal/cmdrootfs/cmdrootfs_test.go index 62bc743..5d207ae 100644 --- a/internal/cmdrootfs/cmdrootfs_test.go +++ b/internal/cmdrootfs/cmdrootfs_test.go @@ -67,7 +67,7 @@ func TestExecute(t *testing.T) { inf := filepath.Join(dir, tt.infile) c.PositionalArgs.Infile = goflags.Filename(inf) c.PositionalArgs.Outfile = tt.outfile - c.rootfsNew = func(r io.ReadSeeker) io.WriterTo { + c.rootfsNew = func(r io.ReadSeeker) flattener { return &passthrough{r} } @@ -92,4 +92,7 @@ func TestExecute(t *testing.T) { type passthrough struct{ r io.Reader } -func (p *passthrough) WriteTo(w io.Writer) (int64, error) { return io.Copy(w, p.r) } +func (p *passthrough) Flatten(w io.Writer) error { + _, err := io.Copy(w, p.r) + return err +} diff --git a/rootfs/rootfs.go b/rootfs/rootfs.go index 92ef9c0..c474980 100644 --- a/rootfs/rootfs.go +++ b/rootfs/rootfs.go @@ -12,7 +12,6 @@ import ( "path/filepath" "strings" - "github.com/motiejus/code/undocker/internal/bytecounter" "go.uber.org/multierr" ) @@ -48,8 +47,8 @@ func New(rd io.ReadSeeker) *RootFS { return &RootFS{rd: rd} } -// WriteTo writes a docker image to an open tarball. -func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { +// Flatten flattens a docker image to an open tarball. +func (r *RootFS) Flatten(w io.Writer) (err error) { tr := tar.NewReader(r.rd) var closer func() error @@ -72,19 +71,19 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { case filepath.Clean(hdr.Name) == _manifestJSON: dec := json.NewDecoder(tr) if err := dec.Decode(&manifest); err != nil { - return n, fmt.Errorf("decode %s: %w", _manifestJSON, err) + return fmt.Errorf("decode %s: %w", _manifestJSON, err) } case strings.HasSuffix(hdr.Name, _layerSuffix): here, err := r.rd.Seek(0, io.SeekCurrent) if err != nil { - return n, err + return err } layerOffsets[hdr.Name] = here } } if len(manifest) == 0 || len(layerOffsets) != len(manifest[0].Layers) { - return n, errBadManifest + return errBadManifest } // enumerate layers the way they would be laid down in the image @@ -109,7 +108,7 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { // iterate over all files, construct `file2layer`, `whreaddir`, `wh` for i, no := range layers { if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil { - return n, err + return err } tr, closer = openTargz(r.rd) for { @@ -118,7 +117,7 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { break } if err != nil { - return n, fmt.Errorf("decode %s: %w", no.name, err) + return fmt.Errorf("decode %s: %w", no.name, err) } if hdr.Typeflag == tar.TypeDir { continue @@ -142,23 +141,21 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { file2layer[hdr.Name] = i } if err := closer(); err != nil { - return n, err + return err } } // construct directories to whiteout, for each layer. whIgnore := whiteoutDirs(whreaddir, len(layers)) - wr := bytecounter.New(w) - tw := tar.NewWriter(wr) + tw := tar.NewWriter(w) defer func() { err = multierr.Append(err, tw.Close()) - n = wr.N }() // iterate through all layers, all files, and write files. for i, no := range layers { if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil { - return n, err + return err } tr, closer = openTargz(r.rd) for { @@ -167,7 +164,7 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { break } if err != nil { - return n, fmt.Errorf("decode %s: %w", no.name, err) + return fmt.Errorf("decode %s: %w", no.name, err) } if layer, ok := wh[hdr.Name]; ok && layer >= i { continue @@ -179,14 +176,14 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) { continue } if err := writeFile(tr, tw, hdr); err != nil { - return n, err + return err } } if err := closer(); err != nil { - return n, err + return err } } - return n, nil + return nil } func writeFile(tr *tar.Reader, tw *tar.Writer, hdr *tar.Header) error { @@ -238,10 +235,8 @@ func whiteoutDirs(whreaddir map[string]int, nlayers int) []*tree { // openTargz creates a tar reader from a targzip or tar. // -// We may be looking at magic values for tar and/or gzip, -// which would mean "cleaner" code (e.g. no proxyWriter), -// but that would mean re-implementing gzip.readHeader(), -// which is ... already in stdlib. +// It will try to open a gzip stream, and, if that fails, silently fall back to +// tar. I will accept a cleaner implementation looking at magic values. func openTargz(r io.Reader) (*tar.Reader, func() error) { hdrbuf := &bytes.Buffer{} hdrw := &proxyWriter{w: hdrbuf} diff --git a/rootfs/rootfs_test.go b/rootfs/rootfs_test.go index 3612dea..686e012 100644 --- a/rootfs/rootfs_test.go +++ b/rootfs/rootfs_test.go @@ -186,7 +186,7 @@ func TestRootFS(t *testing.T) { in := bytes.NewReader(tt.image.Buffer().Bytes()) out := bytes.Buffer{} - n, err := New(in).WriteTo(&out) + err := New(in).Flatten(&out) if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) return @@ -195,7 +195,6 @@ func TestRootFS(t *testing.T) { require.NoError(t, err) got := tartest.Extract(t, bytes.NewReader(outb)) assert.Equal(t, tt.want, got) - assert.Equal(t, int64(len(outb)), n) }) } }