@cryptotaxi247 / kubo / commits / 7a579bbf7

commands: Moved files code into 'commands/files' subpackage

Matt Bell committed Jan 13, 2015 at 10:16 UTC 7a579bbf79c8cedfb063e35197982d85a2cf30d1
11 files changed +215 -201
commands/cli/parse.go
+12 -11
@@ -11,6 +11,7 @@ import (
11 "strings"
12
13 cmds "github.com/jbenet/go-ipfs/commands"
14 + cmdsFiles "github.com/jbenet/go-ipfs/commands/files"
15 u "github.com/jbenet/go-ipfs/util"
16 )
17
@@ -65,7 +66,7 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
66 }
67 req.SetArguments(stringArgs)
68
68 - file := &cmds.SliceFile{"", fileArgs}
69 + file := &cmdsFiles.SliceFile{"", fileArgs}
70 req.SetFiles(file)
71
72 err = cmd.CheckArguments(req)
@@ -139,7 +140,7 @@ func parseOptions(input []string) (map[string]interface{}, []string, error) {
140 return opts, args, nil
141 }
142
142 -func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive bool) ([]string, []cmds.File, error) {
143 +func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive bool) ([]string, []cmdsFiles.File, error) {
144 // ignore stdin on Windows
145 if runtime.GOOS == "windows" {
146 stdin = nil
@@ -176,7 +177,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
177 }
178
179 stringArgs := make([]string, 0, numInputs)
179 - fileArgs := make([]cmds.File, 0, numInputs)
180 + fileArgs := make([]cmdsFiles.File, 0, numInputs)
181
182 argDefIndex := 0 // the index of the current argument definition
183 for i := 0; i < numInputs; i++ {
@@ -263,7 +264,7 @@ func appendStdinAsString(args []string, stdin *os.File) ([]string, *os.File, err
264 return append(args, buf.String()), nil, nil
265 }
266
266 -func appendFile(args []cmds.File, inputs []string, argDef *cmds.Argument, recursive bool) ([]cmds.File, []string, error) {
267 +func appendFile(args []cmdsFiles.File, inputs []string, argDef *cmds.Argument, recursive bool) ([]cmdsFiles.File, []string, error) {
268 path := inputs[0]
269
270 file, err := os.Open(path)
@@ -297,13 +298,13 @@ func appendFile(args []cmds.File, inputs []string, argDef *cmds.Argument, recurs
298 return append(args, arg), inputs[1:], nil
299 }
300
300 -func appendStdinAsFile(args []cmds.File, stdin *os.File) ([]cmds.File, *os.File) {
301 - arg := &cmds.ReaderFile{"", stdin}
301 +func appendStdinAsFile(args []cmdsFiles.File, stdin *os.File) ([]cmdsFiles.File, *os.File) {
302 + arg := &cmdsFiles.ReaderFile{"", stdin}
303 return append(args, arg), nil
304 }
305
305 -// recursively get file or directory contents as a cmds.File
306 -func openPath(file *os.File, path string) (cmds.File, error) {
306 +// recursively get file or directory contents as a cmdsFiles.File
307 +func openPath(file *os.File, path string) (cmdsFiles.File, error) {
308 stat, err := file.Stat()
309 if err != nil {
310 return nil, err
@@ -311,7 +312,7 @@ func openPath(file *os.File, path string) (cmds.File, error) {
312
313 // for non-directories, return a ReaderFile
314 if !stat.IsDir() {
314 - return &cmds.ReaderFile{path, file}, nil
315 + return &cmdsFiles.ReaderFile{path, file}, nil
316 }
317
318 // for directories, recursively iterate though children then return as a SliceFile
@@ -323,7 +324,7 @@ func openPath(file *os.File, path string) (cmds.File, error) {
324 // make sure contents are sorted so -- repeatably -- we get the same inputs.
325 sort.Sort(sortFIByName(contents))
326
326 - files := make([]cmds.File, 0, len(contents))
327 + files := make([]cmdsFiles.File, 0, len(contents))
328 for _, child := range contents {
329 childPath := fp.Join(path, child.Name())
330 childFile, err := os.Open(childPath)
@@ -339,7 +340,7 @@ func openPath(file *os.File, path string) (cmds.File, error) {
340 files = append(files, f)
341 }
342
342 - return &cmds.SliceFile{path, files}, nil
343 + return &cmdsFiles.SliceFile{path, files}, nil
344 }
345
346 // isTerminal returns true if stdin is a Stdin pipe (e.g. `cat file | ipfs`),
commands/file.go deleted
-176
@@ -1,176 +0,0 @@
1 -package commands
2 -
3 -import (
4 - "errors"
5 - "io"
6 - "mime"
7 - "mime/multipart"
8 - "net/http"
9 -)
10 -
11 -const (
12 - multipartFormdataType = "multipart/form-data"
13 - multipartMixedType = "multipart/mixed"
14 -
15 - contentTypeHeader = "Content-Type"
16 -)
17 -
18 -var (
19 - ErrNotDirectory = errors.New("Couln't call NextFile(), this isn't a directory")
20 - ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
21 -)
22 -
23 -// File is an interface that provides functionality for handling files/directories
24 -// as values that can be supplied to commands. For directories, child files are
25 -// accessed serially by calling `NextFile()`.
26 -type File interface {
27 - // Files implement ReadCloser, but can only be read from or closed if they are not directories
28 - io.ReadCloser
29 -
30 - // FileName returns a full filename path associated with this file
31 - FileName() string
32 -
33 - // IsDirectory returns true if the File is a directory (and therefore supports calling `NextFile`)
34 - // and false if the File is a normal file (and therefor supports calling `Read` and `Close`)
35 - IsDirectory() bool
36 -
37 - // NextFile returns the next child file available (if the File is a directory).
38 - // It will return (nil, io.EOF) if no more files are available.
39 - // If the file is a regular file (not a directory), NextFile will return a non-nil error.
40 - NextFile() (File, error)
41 -}
42 -
43 -// MultipartFile implements File, and is created from a `multipart.Part`.
44 -// It can be either a directory or file (checked by calling `IsDirectory()`).
45 -type MultipartFile struct {
46 - File
47 -
48 - Part *multipart.Part
49 - Reader *multipart.Reader
50 - Mediatype string
51 -}
52 -
53 -func NewFileFromPart(part *multipart.Part) (File, error) {
54 - f := &MultipartFile{
55 - Part: part,
56 - }
57 -
58 - contentType := part.Header.Get(contentTypeHeader)
59 -
60 - var params map[string]string
61 - var err error
62 - f.Mediatype, params, err = mime.ParseMediaType(contentType)
63 - if err != nil {
64 - return nil, err
65 - }
66 -
67 - if f.IsDirectory() {
68 - boundary, found := params["boundary"]
69 - if !found {
70 - return nil, http.ErrMissingBoundary
71 - }
72 -
73 - f.Reader = multipart.NewReader(part, boundary)
74 - }
75 -
76 - return f, nil
77 -}
78 -
79 -func (f *MultipartFile) IsDirectory() bool {
80 - return f.Mediatype == multipartFormdataType || f.Mediatype == multipartMixedType
81 -}
82 -
83 -func (f *MultipartFile) NextFile() (File, error) {
84 - if !f.IsDirectory() {
85 - return nil, ErrNotDirectory
86 - }
87 -
88 - part, err := f.Reader.NextPart()
89 - if err != nil {
90 - return nil, err
91 - }
92 -
93 - return NewFileFromPart(part)
94 -}
95 -
96 -func (f *MultipartFile) FileName() string {
97 - return f.Part.FileName()
98 -}
99 -
100 -func (f *MultipartFile) Read(p []byte) (int, error) {
101 - if f.IsDirectory() {
102 - return 0, ErrNotReader
103 - }
104 - return f.Part.Read(p)
105 -}
106 -
107 -func (f *MultipartFile) Close() error {
108 - if f.IsDirectory() {
109 - return ErrNotReader
110 - }
111 - return f.Part.Close()
112 -}
113 -
114 -// SliceFile implements File, and provides simple directory handling.
115 -// It contains children files, and is created from a `[]File`.
116 -// SliceFiles are always directories, and can't be read from or closed.
117 -type SliceFile struct {
118 - Filename string
119 - Files []File
120 -}
121 -
122 -func (f *SliceFile) IsDirectory() bool {
123 - return true
124 -}
125 -
126 -func (f *SliceFile) NextFile() (File, error) {
127 - if len(f.Files) == 0 {
128 - return nil, io.EOF
129 - }
130 - file := f.Files[0]
131 - f.Files = f.Files[1:]
132 - return file, nil
133 -}
134 -
135 -func (f *SliceFile) FileName() string {
136 - return f.Filename
137 -}
138 -
139 -func (f *SliceFile) Read(p []byte) (int, error) {
140 - return 0, ErrNotReader
141 -}
142 -
143 -func (f *SliceFile) Close() error {
144 - return ErrNotReader
145 -}
146 -
147 -// ReaderFile is a implementation of File created from an `io.Reader`.
148 -// ReaderFiles are never directories, and can be read from and closed.
149 -type ReaderFile struct {
150 - Filename string
151 - Reader io.Reader
152 -}
153 -
154 -func (f *ReaderFile) IsDirectory() bool {
155 - return false
156 -}
157 -
158 -func (f *ReaderFile) NextFile() (File, error) {
159 - return nil, ErrNotDirectory
160 -}
161 -
162 -func (f *ReaderFile) FileName() string {
163 - return f.Filename
164 -}
165 -
166 -func (f *ReaderFile) Read(p []byte) (int, error) {
167 - return f.Reader.Read(p)
168 -}
169 -
170 -func (f *ReaderFile) Close() error {
171 - closer, ok := f.Reader.(io.Closer)
172 - if !ok {
173 - return nil
174 - }
175 - return closer.Close()
176 -}
commands/files/file.go new
+31
@@ -0,0 +1,31 @@
1 +package files
2 +
3 +import (
4 + "errors"
5 + "io"
6 +)
7 +
8 +var (
9 + ErrNotDirectory = errors.New("Couln't call NextFile(), this isn't a directory")
10 + ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
11 +)
12 +
13 +// File is an interface that provides functionality for handling files/directories
14 +// as values that can be supplied to commands. For directories, child files are
15 +// accessed serially by calling `NextFile()`.
16 +type File interface {
17 + // Files implement ReadCloser, but can only be read from or closed if they are not directories
18 + io.ReadCloser
19 +
20 + // FileName returns a full filename path associated with this file
21 + FileName() string
22 +
23 + // IsDirectory returns true if the File is a directory (and therefore supports calling `NextFile`)
24 + // and false if the File is a normal file (and therefor supports calling `Read` and `Close`)
25 + IsDirectory() bool
26 +
27 + // NextFile returns the next child file available (if the File is a directory).
28 + // It will return (nil, io.EOF) if no more files are available.
29 + // If the file is a regular file (not a directory), NextFile will return a non-nil error.
30 + NextFile() (File, error)
31 +}
commands/files/file_test.go renamed
+1 -1
@@ -1,4 +1,4 @@
1 -package commands
1 +package files
2
3 import (
4 "io"
commands/files/multipartfile.go new
+85
@@ -0,0 +1,85 @@
1 +package files
2 +
3 +import (
4 + "mime"
5 + "mime/multipart"
6 + "net/http"
7 +)
8 +
9 +const (
10 + multipartFormdataType = "multipart/form-data"
11 + multipartMixedType = "multipart/mixed"
12 +
13 + contentTypeHeader = "Content-Type"
14 +)
15 +
16 +// MultipartFile implements File, and is created from a `multipart.Part`.
17 +// It can be either a directory or file (checked by calling `IsDirectory()`).
18 +type MultipartFile struct {
19 + File
20 +
21 + Part *multipart.Part
22 + Reader *multipart.Reader
23 + Mediatype string
24 +}
25 +
26 +func NewFileFromPart(part *multipart.Part) (File, error) {
27 + f := &MultipartFile{
28 + Part: part,
29 + }
30 +
31 + contentType := part.Header.Get(contentTypeHeader)
32 +
33 + var params map[string]string
34 + var err error
35 + f.Mediatype, params, err = mime.ParseMediaType(contentType)
36 + if err != nil {
37 + return nil, err
38 + }
39 +
40 + if f.IsDirectory() {
41 + boundary, found := params["boundary"]
42 + if !found {
43 + return nil, http.ErrMissingBoundary
44 + }
45 +
46 + f.Reader = multipart.NewReader(part, boundary)
47 + }
48 +
49 + return f, nil
50 +}
51 +
52 +func (f *MultipartFile) IsDirectory() bool {
53 + return f.Mediatype == multipartFormdataType || f.Mediatype == multipartMixedType
54 +}
55 +
56 +func (f *MultipartFile) NextFile() (File, error) {
57 + if !f.IsDirectory() {
58 + return nil, ErrNotDirectory
59 + }
60 +
61 + part, err := f.Reader.NextPart()
62 + if err != nil {
63 + return nil, err
64 + }
65 +
66 + return NewFileFromPart(part)
67 +}
68 +
69 +func (f *MultipartFile) FileName() string {
70 + return f.Part.FileName()
71 +}
72 +
73 +func (f *MultipartFile) Read(p []byte) (int, error) {
74 + if f.IsDirectory() {
75 + return 0, ErrNotReader
76 + }
77 + return f.Part.Read(p)
78 +}
79 +
80 +func (f *MultipartFile) Close() error {
81 + if f.IsDirectory() {
82 + return ErrNotReader
83 + }
84 + return f.Part.Close()
85 +}
commands/files/readerfile.go new
+34
@@ -0,0 +1,34 @@
1 +package files
2 +
3 +import "io"
4 +
5 +// ReaderFile is a implementation of File created from an `io.Reader`.
6 +// ReaderFiles are never directories, and can be read from and closed.
7 +type ReaderFile struct {
8 + Filename string
9 + Reader io.Reader
10 +}
11 +
12 +func (f *ReaderFile) IsDirectory() bool {
13 + return false
14 +}
15 +
16 +func (f *ReaderFile) NextFile() (File, error) {
17 + return nil, ErrNotDirectory
18 +}
19 +
20 +func (f *ReaderFile) FileName() string {
21 + return f.Filename
22 +}
23 +
24 +func (f *ReaderFile) Read(p []byte) (int, error) {
25 + return f.Reader.Read(p)
26 +}
27 +
28 +func (f *ReaderFile) Close() error {
29 + closer, ok := f.Reader.(io.Closer)
30 + if !ok {
31 + return nil
32 + }
33 + return closer.Close()
34 +}
commands/files/slicefile.go new
+36
@@ -0,0 +1,36 @@
1 +package files
2 +
3 +import "io"
4 +
5 +// SliceFile implements File, and provides simple directory handling.
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
11 +}
12 +
13 +func (f *SliceFile) IsDirectory() bool {
14 + return true
15 +}
16 +
17 +func (f *SliceFile) NextFile() (File, error) {
18 + if len(f.Files) == 0 {
19 + return nil, io.EOF
20 + }
21 + file := f.Files[0]
22 + f.Files = f.Files[1:]
23 + return file, nil
24 +}
25 +
26 +func (f *SliceFile) FileName() string {
27 + return f.Filename
28 +}
29 +
30 +func (f *SliceFile) Read(p []byte) (int, error) {
31 + return 0, ErrNotReader
32 +}
33 +
34 +func (f *SliceFile) Close() error {
35 + return ErrNotReader
36 +}
commands/http/multifilereader.go
+3 -3
@@ -8,7 +8,7 @@ import (
8 "net/textproto"
9 "sync"
10
11 - cmds "github.com/jbenet/go-ipfs/commands"
11 + files "github.com/jbenet/go-ipfs/commands/files"
12 )
13
14 // MultiFileReader reads from a `commands.File` (which can be a directory of files
@@ -16,7 +16,7 @@ import (
16 type MultiFileReader struct {
17 io.Reader
18
19 - files cmds.File
19 + files files.File
20 currentFile io.Reader
21 buf bytes.Buffer
22 mpWriter *multipart.Writer
@@ -31,7 +31,7 @@ type MultiFileReader struct {
31 // NewMultiFileReader constructs a MultiFileReader. `file` can be any `commands.File`.
32 // If `form` is set to true, the multipart data will have a Content-Type of 'multipart/form-data',
33 // if `form` is false, the Content-Type will be 'multipart/mixed'.
34 -func NewMultiFileReader(file cmds.File, form bool) *MultiFileReader {
34 +func NewMultiFileReader(file files.File, form bool) *MultiFileReader {
35 mfr := &MultiFileReader{
36 files: file,
37 form: form,
commands/http/parse.go
+3 -2
@@ -8,6 +8,7 @@ import (
8 "strings"
9
10 cmds "github.com/jbenet/go-ipfs/commands"
11 + files "github.com/jbenet/go-ipfs/commands/files"
12 )
13
14 // Parse parses the data in a http.Request and returns a command Request object
@@ -94,9 +95,9 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) {
95 contentType := r.Header.Get(contentTypeHeader)
96 mediatype, _, _ := mime.ParseMediaType(contentType)
97
97 - var f *cmds.MultipartFile
98 + var f *files.MultipartFile
99 if mediatype == "multipart/form-data" {
99 - f = &cmds.MultipartFile{Mediatype: mediatype}
100 + f = &files.MultipartFile{Mediatype: mediatype}
101 f.Reader, err = r.MultipartReader()
102 if err != nil {
103 return nil, err
commands/request.go
+7 -6
@@ -8,6 +8,7 @@ import (
8
9 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10
11 + "github.com/jbenet/go-ipfs/commands/files"
12 "github.com/jbenet/go-ipfs/core"
13 "github.com/jbenet/go-ipfs/repo/config"
14 u "github.com/jbenet/go-ipfs/util"
@@ -71,8 +72,8 @@ type Request interface {
72 SetOptions(opts map[string]interface{}) error
73 Arguments() []string
74 SetArguments([]string)
74 - Files() File
75 - SetFiles(File)
75 + Files() files.File
76 + SetFiles(files.File)
77 Context() *Context
78 SetContext(Context)
79 Command() *Command
@@ -84,7 +85,7 @@ type request struct {
85 path []string
86 options optMap
87 arguments []string
87 - files File
88 + files files.File
89 cmd *Command
90 ctx Context
91 optionDefs map[string]Option
@@ -159,11 +160,11 @@ func (r *request) SetArguments(args []string) {
160 r.arguments = args
161 }
162
162 -func (r *request) Files() File {
163 +func (r *request) Files() files.File {
164 return r.files
165 }
166
166 -func (r *request) SetFiles(f File) {
167 +func (r *request) SetFiles(f files.File) {
168 r.files = f
169 }
170
@@ -259,7 +260,7 @@ func NewEmptyRequest() (Request, error) {
260
261 // NewRequest returns a request initialized with given arguments
262 // An non-nil error will be returned if the provided option values are invalid
262 -func NewRequest(path []string, opts optMap, args []string, file File, cmd *Command, optDefs map[string]Option) (Request, error) {
263 +func NewRequest(path []string, opts optMap, args []string, file files.File, cmd *Command, optDefs map[string]Option) (Request, error) {
264 if path == nil {
265 path = make([]string, 0)
266 }
core/commands/add.go
+3 -2
@@ -8,6 +8,7 @@ import (
8 "path"
9
10 cmds "github.com/jbenet/go-ipfs/commands"
11 + files "github.com/jbenet/go-ipfs/commands/files"
12 core "github.com/jbenet/go-ipfs/core"
13 importer "github.com/jbenet/go-ipfs/importer"
14 "github.com/jbenet/go-ipfs/importer/chunk"
@@ -138,7 +139,7 @@ func addNode(n *core.IpfsNode, node *dag.Node) error {
139 return nil
140 }
141
141 -func addFile(n *core.IpfsNode, file cmds.File, out chan interface{}) (*dag.Node, error) {
142 +func addFile(n *core.IpfsNode, file files.File, out chan interface{}) (*dag.Node, error) {
143 if file.IsDirectory() {
144 return addDir(n, file, out)
145 }
@@ -155,7 +156,7 @@ func addFile(n *core.IpfsNode, file cmds.File, out chan interface{}) (*dag.Node,
156 return dns[len(dns)-1], nil // last dag node is the file.
157 }
158
158 -func addDir(n *core.IpfsNode, dir cmds.File, out chan interface{}) (*dag.Node, error) {
159 +func addDir(n *core.IpfsNode, dir files.File, out chan interface{}) (*dag.Node, error) {
160 log.Infof("adding directory: %s", dir.FileName())
161
162 tree := &dag.Node{Data: ft.FolderPBData()}