@cryptotaxi247 / kubo / commits / 8ca8d6ef7

commands/files: Added PeekFile and StatFile interfaces

squash! commands/files: Added PeekFile and StatFile interfaces commands/http: Updated test

Matt Bell committed Jan 21, 2015 at 17:36 UTC 8ca8d6ef71909d80aeb9771ca3790512cfe21482
7 files changed +73 -29
commands/cli/parse.go
+2 -2
@@ -64,7 +64,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
64 }
65 req.SetArguments(stringArgs)
66
67 - file := &files.SliceFile{"", fileArgs}
67 + file := files.NewSliceFile("", fileArgs)
68 req.SetFiles(file)
69
70 err = cmd.CheckArguments(req)
@@ -298,7 +298,7 @@ func appendFile(args []files.File, inputs []string, argDef *cmds.Argument, recur
298 }
299
300 func appendStdinAsFile(args []files.File, stdin *os.File) ([]files.File, *os.File) {
301 - arg := &files.ReaderFile{"", stdin}
301 + arg := files.NewReaderFile("", stdin, nil)
302 return append(args, arg), nil
303 }
304
commands/files/file.go
+14
@@ -3,6 +3,7 @@ package files
3 import (
4 "errors"
5 "io"
6 + "os"
7 )
8
9 var (
@@ -29,3 +30,16 @@ type File interface {
30 // If the file is a regular file (not a directory), NextFile will return a non-nil error.
31 NextFile() (File, error)
32 }
33 +
34 +type StatFile interface {
35 + File
36 +
37 + Stat() os.FileInfo
38 +}
39 +
40 +type PeekFile interface {
41 + File
42 +
43 + Peek(n int) File
44 + Length() int
45 +}
commands/files/file_test.go
+5 -5
@@ -11,13 +11,13 @@ import (
11 func TestSliceFiles(t *testing.T) {
12 name := "testname"
13 files := []File{
14 - &ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n"))},
15 - &ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))},
16 - &ReaderFile{"boop.txt", ioutil.NopCloser(strings.NewReader("boop"))},
14 + NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
15 + NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
16 + NewReaderFile("boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
17 }
18 buf := make([]byte, 20)
19
20 - sf := &SliceFile{name, files}
20 + sf := NewSliceFile(name, files)
21
22 if !sf.IsDirectory() {
23 t.Error("SliceFile should always be a directory")
@@ -55,7 +55,7 @@ func TestSliceFiles(t *testing.T) {
55
56 func TestReaderFiles(t *testing.T) {
57 message := "beep boop"
58 - rf := &ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(message))}
58 + rf := NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
59 buf := make([]byte, len(message))
60
61 if rf.IsDirectory() {
commands/files/readerfile.go
+18 -6
@@ -1,12 +1,20 @@
1 package files
2
3 -import "io"
3 +import (
4 + "io"
5 + "os"
6 +)
7
8 // ReaderFile is a implementation of File created from an `io.Reader`.
9 // ReaderFiles are never directories, and can be read from and closed.
10 type ReaderFile struct {
8 - Filename string
9 - Reader io.ReadCloser
11 + filename string
12 + reader io.ReadCloser
13 + stat os.FileInfo
14 +}
15 +
16 +func NewReaderFile(filename string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile {
17 + return &ReaderFile{filename, reader, stat}
18 }
19
20 func (f *ReaderFile) IsDirectory() bool {
@@ -18,13 +26,17 @@ func (f *ReaderFile) NextFile() (File, error) {
26 }
27
28 func (f *ReaderFile) FileName() string {
21 - return f.Filename
29 + return f.filename
30 }
31
32 func (f *ReaderFile) Read(p []byte) (int, error) {
25 - return f.Reader.Read(p)
33 + return f.reader.Read(p)
34 }
35
36 func (f *ReaderFile) Close() error {
29 - return f.Reader.Close()
37 + return f.reader.Close()
38 +}
39 +
40 +func (f *ReaderFile) Stat() os.FileInfo {
41 + return f.stat
42 }
commands/files/serialfile.go
+7 -2
@@ -20,6 +20,7 @@ func (es sortFIByName) Less(i, j int) bool { return es[i].Name() < es[j].Name()
20 type serialFile struct {
21 path string
22 files []os.FileInfo
23 + stat os.FileInfo
24 current *os.File
25 }
26
@@ -35,7 +36,7 @@ func NewSerialFile(path string, file *os.File) (File, error) {
36 func newSerialFile(path string, file *os.File, stat os.FileInfo) (File, error) {
37 // for non-directories, return a ReaderFile
38 if !stat.IsDir() {
38 - return &ReaderFile{path, file}, nil
39 + return &ReaderFile{path, file, stat}, nil
40 }
41
42 // 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) {
56 // make sure contents are sorted so -- repeatably -- we get the same inputs.
57 sort.Sort(sortFIByName(contents))
58
58 - return &serialFile{path, contents, nil}, nil
59 + return &serialFile{path, contents, stat, nil}, nil
60 }
61
62 func (f *serialFile) IsDirectory() bool {
@@ -113,3 +114,7 @@ func (f *serialFile) Close() error {
114
115 return nil
116 }
117 +
118 +func (f *serialFile) Stat() os.FileInfo {
119 + return f.stat
120 +}
commands/files/slicefile.go
+19 -6
@@ -6,8 +6,13 @@ import "io"
6 // It contains children files, and is created from a `[]File`.
7 // SliceFiles are always directories, and can't be read from or closed.
8 type SliceFile struct {
9 - Filename string
10 - Files []File
9 + filename string
10 + files []File
11 + n int
12 +}
13 +
14 +func NewSliceFile(filename string, files []File) *SliceFile {
15 + return &SliceFile{filename, files, 0}
16 }
17
18 func (f *SliceFile) IsDirectory() bool {
@@ -15,16 +20,16 @@ func (f *SliceFile) IsDirectory() bool {
20 }
21
22 func (f *SliceFile) NextFile() (File, error) {
18 - if len(f.Files) == 0 {
23 + if f.n >= len(f.files) {
24 return nil, io.EOF
25 }
21 - file := f.Files[0]
22 - f.Files = f.Files[1:]
26 + file := f.files[f.n]
27 + f.n++
28 return file, nil
29 }
30
31 func (f *SliceFile) FileName() string {
27 - return f.Filename
32 + return f.filename
33 }
34
35 func (f *SliceFile) Read(p []byte) (int, error) {
@@ -34,3 +39,11 @@ func (f *SliceFile) Read(p []byte) (int, error) {
39 func (f *SliceFile) Close() error {
40 return ErrNotReader
41 }
42 +
43 +func (f *SliceFile) Peek(n int) File {
44 + return f.files[n]
45 +}
46 +
47 +func (f *SliceFile) Length() int {
48 + return len(f.files)
49 +}
commands/http/multifilereader_test.go
+8 -8
@@ -13,14 +13,14 @@ import (
13 func TestOutput(t *testing.T) {
14 text := "Some text! :)"
15 fileset := []files.File{
16 - &files.ReaderFile{"file.txt", ioutil.NopCloser(strings.NewReader(text))},
17 - &files.SliceFile{"boop", []files.File{
18 - &files.ReaderFile{"boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep"))},
19 - &files.ReaderFile{"boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop"))},
20 - }},
21 - &files.ReaderFile{"beep.txt", ioutil.NopCloser(strings.NewReader("beep"))},
22 - }
23 - sf := &files.SliceFile{"", fileset}
16 + files.NewReaderFile("file.txt", ioutil.NopCloser(strings.NewReader(text)), nil),
17 + files.NewSliceFile("boop", []files.File{
18 + files.NewReaderFile("boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil),
19 + files.NewReaderFile("boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil),
20 + }),
21 + files.NewReaderFile("beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
22 + }
23 + sf := files.NewSliceFile("", fileset)
24 buf := make([]byte, 20)
25
26 // testing output by reading it with the go stdlib "mime/multipart" Reader