commands/cli: Support directory argfile arguments in Parse
Matt Bell committed
Nov 16, 2014 at 22:05 UTC
9d2ee4f1d4a6e3af80172917bf97ce19e0aefad0
1 file changed
+77
-10
commands/cli/parse.go
+77
-10
@@ -8,6 +8,7 @@ import (
8
"strings"
9
10
cmds "github.com/jbenet/go-ipfs/commands"
11
+ u "github.com/jbenet/go-ipfs/util"
12
)
13
14
// ErrInvalidSubcmd signals when the parse error is not found
@@ -17,16 +18,11 @@ var ErrInvalidSubcmd = errors.New("subcommand not found")
18
// returns the corresponding command Request object.
19
func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *cmds.Command, []string, error) {
20
path, input, cmd := parsePath(input, root)
20
- opts, stringVals, err := parseOptions(input)
21
- if err != nil {
22
- return nil, cmd, path, err
23
- }
24
-
21
if len(path) == 0 {
22
return nil, nil, path, ErrInvalidSubcmd
23
}
24
29
- stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments)
25
+ opts, stringVals, err := parseOptions(input)
26
if err != nil {
27
return nil, cmd, path, err
28
}
@@ -44,12 +40,23 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
40
}
41
}
42
47
- file := &cmds.SliceFile{"", fileArgs}
43
+ req, err := cmds.NewRequest(path, opts, nil, nil, cmd, optDefs)
44
+ if err != nil {
45
+ return nil, cmd, path, err
46
+ }
47
49
- req, err := cmds.NewRequest(path, opts, stringArgs, file, cmd, optDefs)
48
+ recursive, _, err := req.Option(cmds.RecShort).Bool()
49
+ if err != nil {
50
+ return nil, nil, nil, u.ErrCast()
51
+ }
52
+ stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments, recursive)
53
if err != nil {
54
return nil, cmd, path, err
55
}
56
+ req.SetArguments(stringArgs)
57
+
58
+ file := &cmds.SliceFile{"", fileArgs}
59
+ req.SetFiles(file)
60
61
err = cmd.CheckArguments(req)
62
if err != nil {
@@ -120,7 +127,7 @@ func parseOptions(input []string) (map[string]interface{}, []string, error) {
127
return opts, args, nil
128
}
129
123
-func parseArgs(inputs []string, stdin *os.File, arguments []cmds.Argument) ([]interface{}, []cmds.File, error) {
130
+func parseArgs(inputs []string, stdin *os.File, arguments []cmds.Argument, recursive bool) ([]interface{}, []cmds.File, error) {
131
// check if stdin is coming from terminal or is being piped in
132
if stdin != nil {
133
stat, err := stdin.Stat()
@@ -198,7 +205,29 @@ func parseArgs(inputs []string, stdin *os.File, arguments []cmds.Argument) ([]in
205
return nil, nil, err
206
}
207
201
- fileArg := &cmds.ReaderFile{path, file}
208
+ stat, err := file.Stat()
209
+ if err != nil {
210
+ return nil, nil, err
211
+ }
212
+
213
+ if stat.IsDir() {
214
+ if !argDef.Recursive {
215
+ err = fmt.Errorf("Invalid path '%s', argument '%s' does not support directories",
216
+ input, argDef.Name)
217
+ return nil, nil, err
218
+ }
219
+ if !recursive {
220
+ err = fmt.Errorf("'%s' is a directory, use the '-%s' flag to specify directories",
221
+ input, cmds.RecShort)
222
+ return nil, nil, err
223
+ }
224
+ }
225
+
226
+ fileArg, err := getFile(file, input)
227
+ if err != nil {
228
+ return nil, nil, err
229
+ }
230
+
231
fileArgs = append(fileArgs, fileArg)
232
233
} else if argDef.SupportsStdin {
@@ -214,3 +243,41 @@ func parseArgs(inputs []string, stdin *os.File, arguments []cmds.Argument) ([]in
243
244
return stringArgs, fileArgs, nil
245
}
246
+
247
+// recursively get file or directory contents as a cmds.File
248
+func getFile(file *os.File, path string) (cmds.File, error) {
249
+ stat, err := file.Stat()
250
+ if err != nil {
251
+ return nil, err
252
+ }
253
+
254
+ // for non-directories, return a ReaderFile
255
+ if !stat.IsDir() {
256
+ return &cmds.ReaderFile{path, file}, nil
257
+ }
258
+
259
+ // for directories, recursively iterate though children then return as a SliceFile
260
+ contents, err := file.Readdir(0)
261
+ if err != nil {
262
+ return nil, err
263
+ }
264
+
265
+ files := make([]cmds.File, 0, len(contents))
266
+
267
+ for _, child := range contents {
268
+ childPath := fmt.Sprintf("%s/%s", path, child.Name())
269
+ childFile, err := os.Open(childPath)
270
+ if err != nil {
271
+ return nil, err
272
+ }
273
+
274
+ f, err := getFile(childFile, childPath)
275
+ if err != nil {
276
+ return nil, err
277
+ }
278
+
279
+ files = append(files, f)
280
+ }
281
+
282
+ return &cmds.SliceFile{path, files}, nil
283
+}