simplify flattener api
This commit is contained in:
parent
e2cf760c12
commit
9ca0d8019c
@ -13,11 +13,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
flattener interface {
|
|
||||||
Flatten(io.Writer) error
|
|
||||||
}
|
|
||||||
|
|
||||||
rootfsFactory func(io.ReadSeeker) flattener
|
|
||||||
|
|
||||||
// Command is "rootfs" command
|
// Command is "rootfs" command
|
||||||
Command struct {
|
Command struct {
|
||||||
@ -28,7 +23,7 @@ type (
|
|||||||
Outfile string `long:"outfile" description:"Output path, stdout is '-'"`
|
Outfile string `long:"outfile" description:"Output path, stdout is '-'"`
|
||||||
} `positional-args:"yes" required:"yes"`
|
} `positional-args:"yes" required:"yes"`
|
||||||
|
|
||||||
rootfsNew rootfsFactory
|
flattener func(io.ReadSeeker, io.Writer) error
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,7 +32,7 @@ func (c *Command) Execute(args []string) (err error) {
|
|||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return errors.New("too many args")
|
return errors.New("too many args")
|
||||||
}
|
}
|
||||||
if c.rootfsNew == nil {
|
if c.flattener == nil {
|
||||||
c.init()
|
c.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +54,7 @@ func (c *Command) Execute(args []string) (err error) {
|
|||||||
out = outf
|
out = outf
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.rootfsNew(rd).Flatten(out)
|
return c.flattener(rd, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init() initializes Command with the default options.
|
// init() initializes Command with the default options.
|
||||||
@ -68,7 +63,5 @@ 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) flattener {
|
c.flattener = rootfs.Flatten
|
||||||
return rootfs.New(r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -67,9 +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) flattener {
|
c.flattener = flattenPassthrough
|
||||||
return &passthrough{r}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.Execute(nil)
|
err := c.Execute(nil)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
@ -90,9 +88,7 @@ func TestExecute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type passthrough struct{ r io.Reader }
|
func flattenPassthrough(r io.ReadSeeker, w io.Writer) error {
|
||||||
|
_, err := io.Copy(w, r)
|
||||||
func (p *passthrough) Flatten(w io.Writer) error {
|
|
||||||
_, err := io.Copy(w, p.r)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestLXCConfig(t *testing.T) {
|
func TestLXCConfig(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
docker dockerConfig
|
docker dockerConfig
|
||||||
|
@ -27,11 +27,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// RootFS accepts a docker layer tarball and flattens it.
|
|
||||||
RootFS struct {
|
|
||||||
rd io.ReadSeeker
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerManifestJSON []struct {
|
dockerManifestJSON []struct {
|
||||||
Layers []string `json:"Layers"`
|
Layers []string `json:"Layers"`
|
||||||
}
|
}
|
||||||
@ -42,14 +37,11 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates a new RootFS'er.
|
// Flatten flattens a docker image to a tarball. The underlying io.Writer
|
||||||
func New(rd io.ReadSeeker) *RootFS {
|
// should be an open file handle, which the caller is responsible for closing
|
||||||
return &RootFS{rd: rd}
|
// themselves
|
||||||
}
|
func Flatten(rd io.ReadSeeker, w io.Writer) (err error) {
|
||||||
|
tr := tar.NewReader(rd)
|
||||||
// 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
|
var closer func() error
|
||||||
|
|
||||||
// layerOffsets maps a layer name (a9b123c0daa/layer.tar) to it's offset
|
// layerOffsets maps a layer name (a9b123c0daa/layer.tar) to it's offset
|
||||||
@ -74,7 +66,7 @@ func (r *RootFS) Flatten(w io.Writer) (err error) {
|
|||||||
return 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 := rd.Seek(0, io.SeekCurrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -107,10 +99,10 @@ func (r *RootFS) Flatten(w io.Writer) (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 := rd.Seek(no.offset, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tr, closer = openTargz(r.rd)
|
tr, closer = openTargz(rd)
|
||||||
for {
|
for {
|
||||||
hdr, err := tr.Next()
|
hdr, err := tr.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -154,10 +146,10 @@ func (r *RootFS) Flatten(w io.Writer) (err error) {
|
|||||||
}()
|
}()
|
||||||
// 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 := rd.Seek(no.offset, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tr, closer = openTargz(r.rd)
|
tr, closer = openTargz(rd)
|
||||||
for {
|
for {
|
||||||
hdr, err := tr.Next()
|
hdr, err := tr.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
|
@ -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{}
|
||||||
|
|
||||||
err := New(in).Flatten(&out)
|
err := Flatten(in, &out)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
assert.EqualError(t, err, tt.wantErr)
|
assert.EqualError(t, err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user