remove ByteCounter from rootfs
This commit is contained in:
parent
e1555f31a8
commit
e2cf760c12
@ -13,7 +13,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
rootfsFactory func(io.ReadSeeker) io.WriterTo
|
flattener interface {
|
||||||
|
Flatten(io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
rootfsFactory func(io.ReadSeeker) flattener
|
||||||
|
|
||||||
// Command is "rootfs" command
|
// Command is "rootfs" command
|
||||||
Command struct {
|
Command struct {
|
||||||
@ -55,10 +59,7 @@ func (c *Command) Execute(args []string) (err error) {
|
|||||||
out = outf
|
out = outf
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.rootfsNew(rd).WriteTo(out); err != nil {
|
return c.rootfsNew(rd).Flatten(out)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// init() initializes Command with the default options.
|
// init() initializes Command with the default options.
|
||||||
@ -67,7 +68,7 @@ func (c *Command) Execute(args []string) (err error) {
|
|||||||
// command will initialize itself.
|
// command will initialize itself.
|
||||||
func (c *Command) init() {
|
func (c *Command) init() {
|
||||||
c.BaseCommand.Init()
|
c.BaseCommand.Init()
|
||||||
c.rootfsNew = func(r io.ReadSeeker) io.WriterTo {
|
c.rootfsNew = func(r io.ReadSeeker) flattener {
|
||||||
return rootfs.New(r)
|
return rootfs.New(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func TestExecute(t *testing.T) {
|
|||||||
inf := filepath.Join(dir, tt.infile)
|
inf := filepath.Join(dir, tt.infile)
|
||||||
c.PositionalArgs.Infile = goflags.Filename(inf)
|
c.PositionalArgs.Infile = goflags.Filename(inf)
|
||||||
c.PositionalArgs.Outfile = tt.outfile
|
c.PositionalArgs.Outfile = tt.outfile
|
||||||
c.rootfsNew = func(r io.ReadSeeker) io.WriterTo {
|
c.rootfsNew = func(r io.ReadSeeker) flattener {
|
||||||
return &passthrough{r}
|
return &passthrough{r}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,4 +92,7 @@ func TestExecute(t *testing.T) {
|
|||||||
|
|
||||||
type passthrough struct{ r io.Reader }
|
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
|
||||||
|
}
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/motiejus/code/undocker/internal/bytecounter"
|
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,8 +47,8 @@ func New(rd io.ReadSeeker) *RootFS {
|
|||||||
return &RootFS{rd: rd}
|
return &RootFS{rd: rd}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo writes a docker image to an open tarball.
|
// Flatten flattens a docker image to an open tarball.
|
||||||
func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) {
|
func (r *RootFS) Flatten(w io.Writer) (err error) {
|
||||||
tr := tar.NewReader(r.rd)
|
tr := tar.NewReader(r.rd)
|
||||||
var closer func() error
|
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:
|
case filepath.Clean(hdr.Name) == _manifestJSON:
|
||||||
dec := json.NewDecoder(tr)
|
dec := json.NewDecoder(tr)
|
||||||
if err := dec.Decode(&manifest); err != nil {
|
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):
|
case strings.HasSuffix(hdr.Name, _layerSuffix):
|
||||||
here, err := r.rd.Seek(0, io.SeekCurrent)
|
here, err := r.rd.Seek(0, io.SeekCurrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
layerOffsets[hdr.Name] = here
|
layerOffsets[hdr.Name] = here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(manifest) == 0 || len(layerOffsets) != len(manifest[0].Layers) {
|
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
|
// 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`
|
// iterate over all files, construct `file2layer`, `whreaddir`, `wh`
|
||||||
for i, no := range layers {
|
for i, no := range layers {
|
||||||
if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil {
|
if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
tr, closer = openTargz(r.rd)
|
tr, closer = openTargz(r.rd)
|
||||||
for {
|
for {
|
||||||
@ -118,7 +117,7 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
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 {
|
if hdr.Typeflag == tar.TypeDir {
|
||||||
continue
|
continue
|
||||||
@ -142,23 +141,21 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
file2layer[hdr.Name] = i
|
file2layer[hdr.Name] = i
|
||||||
}
|
}
|
||||||
if err := closer(); err != nil {
|
if err := closer(); err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct directories to whiteout, for each layer.
|
// construct directories to whiteout, for each layer.
|
||||||
whIgnore := whiteoutDirs(whreaddir, len(layers))
|
whIgnore := whiteoutDirs(whreaddir, len(layers))
|
||||||
|
|
||||||
wr := bytecounter.New(w)
|
tw := tar.NewWriter(w)
|
||||||
tw := tar.NewWriter(wr)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = multierr.Append(err, tw.Close())
|
err = multierr.Append(err, tw.Close())
|
||||||
n = wr.N
|
|
||||||
}()
|
}()
|
||||||
// iterate through all layers, all files, and write files.
|
// iterate through all layers, all files, and write files.
|
||||||
for i, no := range layers {
|
for i, no := range layers {
|
||||||
if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil {
|
if _, err := r.rd.Seek(no.offset, io.SeekStart); err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
tr, closer = openTargz(r.rd)
|
tr, closer = openTargz(r.rd)
|
||||||
for {
|
for {
|
||||||
@ -167,7 +164,7 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
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 {
|
if layer, ok := wh[hdr.Name]; ok && layer >= i {
|
||||||
continue
|
continue
|
||||||
@ -179,14 +176,14 @@ func (r *RootFS) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := writeFile(tr, tw, hdr); err != nil {
|
if err := writeFile(tr, tw, hdr); err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := closer(); err != nil {
|
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 {
|
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.
|
// openTargz creates a tar reader from a targzip or tar.
|
||||||
//
|
//
|
||||||
// We may be looking at magic values for tar and/or gzip,
|
// It will try to open a gzip stream, and, if that fails, silently fall back to
|
||||||
// which would mean "cleaner" code (e.g. no proxyWriter),
|
// tar. I will accept a cleaner implementation looking at magic values.
|
||||||
// but that would mean re-implementing gzip.readHeader(),
|
|
||||||
// which is ... already in stdlib.
|
|
||||||
func openTargz(r io.Reader) (*tar.Reader, func() error) {
|
func openTargz(r io.Reader) (*tar.Reader, func() error) {
|
||||||
hdrbuf := &bytes.Buffer{}
|
hdrbuf := &bytes.Buffer{}
|
||||||
hdrw := &proxyWriter{w: hdrbuf}
|
hdrw := &proxyWriter{w: hdrbuf}
|
||||||
|
@ -186,7 +186,7 @@ func TestRootFS(t *testing.T) {
|
|||||||
in := bytes.NewReader(tt.image.Buffer().Bytes())
|
in := bytes.NewReader(tt.image.Buffer().Bytes())
|
||||||
out := bytes.Buffer{}
|
out := bytes.Buffer{}
|
||||||
|
|
||||||
n, err := New(in).WriteTo(&out)
|
err := New(in).Flatten(&out)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
assert.EqualError(t, err, tt.wantErr)
|
assert.EqualError(t, err, tt.wantErr)
|
||||||
return
|
return
|
||||||
@ -195,7 +195,6 @@ func TestRootFS(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
got := tartest.Extract(t, bytes.NewReader(outb))
|
got := tartest.Extract(t, bytes.NewReader(outb))
|
||||||
assert.Equal(t, tt.want, got)
|
assert.Equal(t, tt.want, got)
|
||||||
assert.Equal(t, int64(len(outb)), n)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user