commands/cli: Decomposed 'parseArgs'
Matt Bell committed
Nov 17, 2014 at 18:49 UTC
6681c5037114b99a4c122ef498c51e4be295df7d
1 file changed
+92
-56
commands/cli/parse.go
+92
-56
@@ -131,15 +131,10 @@ func parseOptions(input []string) (map[string]interface{}, []string, error) {
131
func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive bool) ([]string, []cmds.File, error) {
132
// check if stdin is coming from terminal or is being piped in
133
if stdin != nil {
134
- stat, err := stdin.Stat()
135
- if err != nil {
134
+ if term, err := isTerminal(stdin); err != nil {
135
return nil, nil, err
137
- }
138
-
139
- // if stdin isn't a CharDevice, set it to nil
140
- // (this means it is coming from terminal and we want to ignore it)
141
- if (stat.Mode() & os.ModeCharDevice) != 0 {
142
- stdin = nil
136
+ } else if term {
137
+ stdin = nil // set to nil so we ignore it
138
}
139
}
140
@@ -169,14 +164,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
164
165
argDefIndex := 0 // the index of the current argument definition
166
for i := 0; i < numInputs; i++ {
172
- // get the argument definiton (should be argDefs[argDefIndex],
173
- // but if argDefIndex > len(argDefs) we use the last argument definition)
174
- var argDef cmds.Argument
175
- if argDefIndex < len(argDefs) {
176
- argDef = argDefs[argDefIndex]
177
- } else if len(argDefs) > 0 {
178
- argDef = argDefs[len(argDefs)-1]
179
- }
167
+ argDef := getArgDef(argDefIndex, argDefs)
168
169
// skip optional argument definitions if there aren't sufficient remaining inputs
170
if numInputs-i <= numRequired && !argDef.Required {
@@ -185,64 +173,31 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
173
numRequired--
174
}
175
176
+ var err error
177
if argDef.Type == cmds.ArgString {
178
if stdin == nil {
179
// add string values
191
- stringArgs = append(stringArgs, inputs[0])
192
- inputs = inputs[1:]
180
+ stringArgs, inputs = appendString(stringArgs, inputs)
181
182
} else if argDef.SupportsStdin {
183
// if we have a stdin, read it in and use the data as a string value
196
- var buf bytes.Buffer
197
- _, err := buf.ReadFrom(stdin)
184
+ stringArgs, stdin, err = appendStdinAsString(stringArgs, stdin)
185
if err != nil {
186
return nil, nil, err
187
}
201
- stringArgs = append(stringArgs, buf.String())
202
- stdin = nil
188
}
189
190
} else if argDef.Type == cmds.ArgFile {
191
if stdin == nil {
192
// treat stringArg values as file paths
208
- path := inputs[0]
209
- inputs = inputs[1:]
210
-
211
- file, err := os.Open(path)
212
- if err != nil {
213
- return nil, nil, err
214
- }
215
-
216
- stat, err := file.Stat()
217
- if err != nil {
218
- return nil, nil, err
219
- }
220
-
221
- if stat.IsDir() {
222
- if !argDef.Recursive {
223
- err = fmt.Errorf("Invalid path '%s', argument '%s' does not support directories",
224
- path, argDef.Name)
225
- return nil, nil, err
226
- }
227
- if !recursive {
228
- err = fmt.Errorf("'%s' is a directory, use the '-%s' flag to specify directories",
229
- path, cmds.RecShort)
230
- return nil, nil, err
231
- }
232
- }
233
-
234
- fileArg, err := getFile(file, path)
193
+ fileArgs, inputs, err = appendFile(fileArgs, inputs, argDef, recursive)
194
if err != nil {
195
return nil, nil, err
196
}
197
239
- fileArgs = append(fileArgs, fileArg)
240
-
198
} else if argDef.SupportsStdin {
199
// if we have a stdin, create a file from it
243
- fileArg := &cmds.ReaderFile{"", stdin}
244
- fileArgs = append(fileArgs, fileArg)
245
- stdin = nil
200
+ fileArgs, stdin = appendStdinAsFile(fileArgs, stdin)
201
}
202
}
203
@@ -261,8 +216,76 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi
216
return stringArgs, fileArgs, nil
217
}
218
219
+func getArgDef(i int, argDefs []cmds.Argument) *cmds.Argument {
220
+ if i < len(argDefs) {
221
+ // get the argument definition (usually just argDefs[i])
222
+ return &argDefs[i]
223
+
224
+ } else if len(argDefs) > 0 {
225
+ // but if i > len(argDefs) we use the last argument definition)
226
+ return &argDefs[len(argDefs)-1]
227
+ }
228
+
229
+ // only happens if there aren't any definitions
230
+ return nil
231
+}
232
+
233
+func appendString(args, inputs []string) ([]string, []string) {
234
+ return append(args, inputs[0]), inputs[1:]
235
+}
236
+
237
+func appendStdinAsString(args []string, stdin *os.File) ([]string, *os.File, error) {
238
+ var buf bytes.Buffer
239
+
240
+ _, err := buf.ReadFrom(stdin)
241
+ if err != nil {
242
+ return nil, nil, err
243
+ }
244
+
245
+ return append(args, buf.String()), nil, nil
246
+}
247
+
248
+func appendFile(args []cmds.File, inputs []string, argDef *cmds.Argument, recursive bool) ([]cmds.File, []string, error) {
249
+ path := inputs[0]
250
+
251
+ file, err := os.Open(path)
252
+ if err != nil {
253
+ return nil, nil, err
254
+ }
255
+
256
+ stat, err := file.Stat()
257
+ if err != nil {
258
+ return nil, nil, err
259
+ }
260
+
261
+ if stat.IsDir() {
262
+ if !argDef.Recursive {
263
+ err = fmt.Errorf("Invalid path '%s', argument '%s' does not support directories",
264
+ path, argDef.Name)
265
+ return nil, nil, err
266
+ }
267
+ if !recursive {
268
+ err = fmt.Errorf("'%s' is a directory, use the '-%s' flag to specify directories",
269
+ path, cmds.RecShort)
270
+ return nil, nil, err
271
+ }
272
+ }
273
+
274
+ arg, err := openPath(file, path)
275
+ if err != nil {
276
+ return nil, nil, err
277
+ }
278
+
279
+ return append(args, arg), inputs[1:], nil
280
+}
281
+
282
+func appendStdinAsFile(args []cmds.File, stdin *os.File) ([]cmds.File, *os.File) {
283
+ arg := &cmds.ReaderFile{"", stdin}
284
+ return append(args, arg), nil
285
+}
286
+
287
// recursively get file or directory contents as a cmds.File
265
-func getFile(file *os.File, path string) (cmds.File, error) {
288
+func openPath(file *os.File, path string) (cmds.File, error) {
289
stat, err := file.Stat()
290
if err != nil {
291
return nil, err
@@ -288,7 +311,7 @@ func getFile(file *os.File, path string) (cmds.File, error) {
311
return nil, err
312
}
313
291
- f, err := getFile(childFile, childPath)
314
+ f, err := openPath(childFile, childPath)
315
if err != nil {
316
return nil, err
317
}
@@ -298,3 +321,16 @@ func getFile(file *os.File, path string) (cmds.File, error) {
321
322
return &cmds.SliceFile{path, files}, nil
323
}
324
+
325
+// isTerminal returns true if stdin is a Stdin pipe (e.g. `cat file | ipfs`),
326
+// and false otherwise (e.g. nothing is being piped in, so stdin is
327
+// coming from the terminal)
328
+func isTerminal(stdin *os.File) (bool, error) {
329
+ stat, err := stdin.Stat()
330
+ if err != nil {
331
+ return false, err
332
+ }
333
+
334
+ // if stdin is a CharDevice, return true
335
+ return ((stat.Mode() & os.ModeCharDevice) != 0), nil
336
+}