Rootfs is now a struct

main
Motiejus Jakštys 2021-05-24 00:11:58 +03:00
parent d372a538ce
commit 98373a151d
3 changed files with 22 additions and 20 deletions

View File

@ -21,11 +21,11 @@ func (r *CmdRootFS) Execute(args []string) (err error) {
return errors.New("too many args") return errors.New("too many args")
} }
in, err := os.Open(string(r.PositionalArgs.Infile)) rd, err := os.Open(string(r.PositionalArgs.Infile))
if err != nil { if err != nil {
return err return err
} }
defer func() { err = multierr.Append(err, in.Close()) }() defer func() { err = multierr.Append(err, rd.Close()) }()
var out *os.File var out *os.File
outf := string(r.PositionalArgs.Outfile) outf := string(r.PositionalArgs.Outfile)
@ -39,5 +39,5 @@ func (r *CmdRootFS) Execute(args []string) (err error) {
} }
defer func() { err = multierr.Append(err, out.Close()) }() defer func() { err = multierr.Append(err, out.Close()) }()
return rootfs.RootFS(in, out) return rootfs.New(rd).WriteTo(out)
} }

View File

@ -27,17 +27,19 @@ type dockerManifestJSON []struct {
Layers []string `json:"Layers"` Layers []string `json:"Layers"`
} }
// RootFS accepts a docker layer tarball and writes it to outfile. // RootFS accepts a docker layer tarball and flattens it.
// 1. create map[string]io.ReadSeeker for each layer. type RootFS struct {
// 2. parse manifest.json and get the layer order. rd io.ReadSeeker
// 3. go through each layer in order and write: }
// a) to an ordered slice: the file name.
// b) to an FS map: where does the file come from? // New creates a new RootFS'er.
// I) layer name func New(rd io.ReadSeeker) *RootFS {
// II) offset (0 being the first file in the layer) return &RootFS{rd: rd}
// 4. go through }
func RootFS(in io.ReadSeeker, wr io.Writer) (err error) {
tr := tar.NewReader(in) // WriteTo writes a docker image to an open tarball.
func (r *RootFS) WriteTo(wr io.Writer) (err error) {
tr := tar.NewReader(r.rd)
tw := tar.NewWriter(wr) tw := tar.NewWriter(wr)
defer func() { err = multierr.Append(err, tw.Close()) }() defer func() { err = multierr.Append(err, tw.Close()) }()
@ -63,7 +65,7 @@ func RootFS(in io.ReadSeeker, wr 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 := in.Seek(0, io.SeekCurrent) here, err := r.rd.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return err return err
} }
@ -93,10 +95,10 @@ func RootFS(in io.ReadSeeker, wr io.Writer) (err error) {
// iterate over all files, construct `file2layer`, `whreaddir`, `wh` // iterate over all files, construct `file2layer`, `whreaddir`, `wh`
for i, offset := range layers { for i, offset := range layers {
if _, err := in.Seek(offset, io.SeekStart); err != nil { if _, err := r.rd.Seek(offset, io.SeekStart); err != nil {
return err return err
} }
tr = tar.NewReader(in) tr = tar.NewReader(r.rd)
for { for {
hdr, err := tr.Next() hdr, err := tr.Next()
if err == io.EOF { if err == io.EOF {
@ -134,10 +136,10 @@ func RootFS(in io.ReadSeeker, wr io.Writer) (err error) {
// iterate through all layers, all files, and write files. // iterate through all layers, all files, and write files.
for i, offset := range layers { for i, offset := range layers {
if _, err := in.Seek(offset, io.SeekStart); err != nil { if _, err := r.rd.Seek(offset, io.SeekStart); err != nil {
return err return err
} }
tr = tar.NewReader(in) tr = tar.NewReader(r.rd)
for { for {
hdr, err := tr.Next() hdr, err := tr.Next()
if err == io.EOF { if err == io.EOF {

View File

@ -177,7 +177,7 @@ func TestRootFS(t *testing.T) {
in := bytes.NewReader(tt.image.Bytes()) in := bytes.NewReader(tt.image.Bytes())
out := bytes.Buffer{} out := bytes.Buffer{}
err := RootFS(in, &out) err := New(in).WriteTo(&out)
if tt.wantErr != "" { if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr) assert.EqualError(t, err, tt.wantErr)
return return