From 8ca8d6ef71909d80aeb9771ca3790512cfe21482 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 21 Jan 2015 17:36:37 -0800 Subject: [PATCH] commands/files: Added PeekFile and StatFile interfaces squash! commands/files: Added PeekFile and StatFile interfaces commands/http: Updated test --- commands/cli/parse.go | 4 ++-- commands/files/file.go | 14 ++++++++++++++ commands/files/file_test.go | 10 +++++----- commands/files/readerfile.go | 24 ++++++++++++++++++------ commands/files/serialfile.go | 9 +++++++-- commands/files/slicefile.go | 25 +++++++++++++++++++------ commands/http/multifilereader_test.go | 14 +++++++------- 7 files changed, 72 insertions(+), 28 deletions(-) diff --git a/commands/cli/parse.go b/commands/cli/parse.go index ece7014fb..49817475e 100644 --- a/commands/cli/parse.go +++ b/commands/cli/parse.go @@ -64,7 +64,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c } req.SetArguments(stringArgs) - file := &files.SliceFile{"", fileArgs} + file := files.NewSliceFile("", fileArgs) req.SetFiles(file) err = cmd.CheckArguments(req) @@ -298,7 +298,7 @@ func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recur } func appendStdinAsFile(args []files.File, stdin *os.File) ([]files.File, *os.File) { - arg := &files.ReaderFile{"", stdin} + arg := files.NewReaderFile("", stdin, nil) return append(args, arg), nil } diff --git a/commands/files/file.go b/commands/files/file.go index 9e9b043a1..8f76ea71d 100644 --- a/commands/files/file.go +++ b/commands/files/file.go @@ -3,6 +3,7 @@ package files import ( "errors" "io" + "os" ) var ( @@ -29,3 +30,16 @@ type File interface { // If the file is a regular file (not a directory), NextFile will return a non-nil error. NextFile() (File, error) } + +type StatFile interface { + File + + Stat() os.FileInfo +} + +type PeekFile interface { + File + + Peek(n int) File + Length() int +} diff --git a/commands/files/file_test.go b/commands/files/file_test.go index a9499fb78..01b7a9d02 100644 --- a/commands/files/file_test.go +++ b/commands/files/file_test.go @@ -11,13 +11,13 @@ import ( func TestSliceFiles(t *testing.T) { name := "testname" files := []File{ - &ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n"))}, - &ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))}, - &ReaderFile{"boop.txt", ioutil.NopCloser(strings.NewReader("boop"))}, + NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil), + NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), + NewReaderFile("boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil), } buf := make([]byte, 20) - sf := &SliceFile{name, files} + sf := NewSliceFile(name, files) if !sf.IsDirectory() { t.Error("SliceFile should always be a directory") @@ -55,7 +55,7 @@ func TestSliceFiles(t *testing.T) { func TestReaderFiles(t *testing.T) { message := "beep boop" - rf := &ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(message))} + rf := NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(message)), nil) buf := make([]byte, len(message)) if rf.IsDirectory() { diff --git a/commands/files/readerfile.go b/commands/files/readerfile.go index af88562fd..38c28efe3 100644 --- a/commands/files/readerfile.go +++ b/commands/files/readerfile.go @@ -1,12 +1,20 @@ package files -import "io" +import ( + "io" + "os" +) // ReaderFile is a implementation of File created from an `io.Reader`. // ReaderFiles are never directories, and can be read from and closed. type ReaderFile struct { - Filename string - Reader io.ReadCloser + filename string + reader io.ReadCloser + stat os.FileInfo +} + +func NewReaderFile(filename string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile { + return &ReaderFile{filename, reader, stat} } func (f *ReaderFile) IsDirectory() bool { @@ -18,13 +26,17 @@ func (f *ReaderFile) NextFile() (File, error) { } func (f *ReaderFile) FileName() string { - return f.Filename + return f.filename } func (f *ReaderFile) Read(p []byte) (int, error) { - return f.Reader.Read(p) + return f.reader.Read(p) } func (f *ReaderFile) Close() error { - return f.Reader.Close() + return f.reader.Close() +} + +func (f *ReaderFile) Stat() os.FileInfo { + return f.stat } diff --git a/commands/files/serialfile.go b/commands/files/serialfile.go index 21f3a9bb9..9a81f8bd1 100644 --- a/commands/files/serialfile.go +++ b/commands/files/serialfile.go @@ -20,6 +20,7 @@ func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name() type serialFile struct { path string files []os.FileInfo + stat os.FileInfo current *os.File } @@ -35,7 +36,7 @@ func NewSerialFile(path string, file *os.File) (File, error) { func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) { // for non-directories, return a ReaderFile if !stat.IsDir() { - return &ReaderFile{path, file}, nil + return &ReaderFile{path, file, stat}, nil } // for directories, stat all of the contents first, so we know what files to @@ -55,7 +56,7 @@ func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) { // make sure contents are sorted so -- repeatably -- we get the same inputs. sort.Sort(sortFIByName(contents)) - return &serialFile{path, contents, nil}, nil + return &serialFile{path, contents, stat, nil}, nil } func (f *serialFile) IsDirectory() bool { @@ -113,3 +114,7 @@ func (f *serialFile) Close() error { return nil } + +func (f *serialFile) Stat() os.FileInfo { + return f.stat +} diff --git a/commands/files/slicefile.go b/commands/files/slicefile.go index e1035f2ce..fe0332d59 100644 --- a/commands/files/slicefile.go +++ b/commands/files/slicefile.go @@ -6,8 +6,13 @@ import "io" // It contains children files, and is created from a `[]File`. // SliceFiles are always directories, and can't be read from or closed. type SliceFile struct { - Filename string - Files []File + filename string + files []File + n int +} + +func NewSliceFile(filename string, files []File) *SliceFile { + return &SliceFile{filename, files, 0} } func (f *SliceFile) IsDirectory() bool { @@ -15,16 +20,16 @@ func (f *SliceFile) IsDirectory() bool { } func (f *SliceFile) NextFile() (File, error) { - if len(f.Files) == 0 { + if f.n >= len(f.files) { return nil, io.EOF } - file := f.Files[0] - f.Files = f.Files[1:] + file := f.files[f.n] + f.n++ return file, nil } func (f *SliceFile) FileName() string { - return f.Filename + return f.filename } func (f *SliceFile) Read(p []byte) (int, error) { @@ -34,3 +39,11 @@ func (f *SliceFile) Read(p []byte) (int, error) { func (f *SliceFile) Close() error { return ErrNotReader } + +func (f *SliceFile) Peek(n int) File { + return f.files[n] +} + +func (f *SliceFile) Length() int { + return len(f.files) +} diff --git a/commands/http/multifilereader_test.go b/commands/http/multifilereader_test.go index 8d832c9cc..8242e2777 100644 --- a/commands/http/multifilereader_test.go +++ b/commands/http/multifilereader_test.go @@ -13,14 +13,14 @@ import ( func TestOutput(t *testing.T) { text := "Some text! :)" fileset := []files.File{ - &files.ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(text))}, - &files.SliceFile{"boop", []files.File{ - &files.ReaderFile{"boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep"))}, - &files.ReaderFile{"boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop"))}, - }}, - &files.ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))}, + files.NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(text)), nil), + files.NewSliceFile("boop", []files.File{ + files.NewReaderFile("boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil), + files.NewReaderFile("boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil), + }), + files.NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), } - sf := &files.SliceFile{"", fileset} + sf := files.NewSliceFile("", fileset) buf := make([]byte, 20) // testing output by reading it with the go stdlib "mime/multipart" Reader