@cryptotaxi247 / kubo / commits / 9d2ee4f1d

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 +}