OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * This library lets you define parsers for parsing raw command-line arguments | 6 * Parser support for transforming raw command-line arguments into a set |
7 * into a set of options and values using [GNU][] and [POSIX][] style options. | 7 * of options and values. |
8 * | 8 * |
9 * ## Installing ## | 9 * This library supports [GNU][] and [POSIX][] style options, and it works |
| 10 * in both server-side and client-side apps. |
10 * | 11 * |
11 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` | 12 * For information on installing this library, see the |
12 * file. | 13 * [args package on pub.dartlang.org](http://pub.dartlang.org/packages/args). |
| 14 * Here's an example of importing this library: |
13 * | 15 * |
14 * dependencies: | 16 * import 'package:args/args.dart'; |
15 * args: any | |
16 * | 17 * |
17 * Then run `pub install`. | 18 * ## Defining options |
18 * | 19 * |
19 * For more information, see the | 20 * To use this library, first create an [ArgParser]: |
20 * [args package on pub.dartlang.org](http://pub.dartlang.org/packages/args). | |
21 * | |
22 * ## Defining options ## | |
23 * | |
24 * To use this library, you create an [ArgParser] object which will contain | |
25 * the set of options you support: | |
26 * | 21 * |
27 * var parser = new ArgParser(); | 22 * var parser = new ArgParser(); |
28 * | 23 * |
29 * Then you define a set of options on that parser using [addOption()] and | 24 * Then define a set of options on that parser using [addOption()] and |
30 * [addFlag()]. The minimal way to create an option is: | 25 * [addFlag()]. Here's the minimal way to create an option named "name": |
31 * | 26 * |
32 * parser.addOption('name'); | 27 * parser.addOption('name'); |
33 * | 28 * |
34 * This creates an option named "name". Options must be given a value on the | 29 * When an option can only be set or unset (as opposed to taking a string |
35 * command line. If you have a simple on/off flag, you can instead use: | 30 * value), use a flag: |
36 * | 31 * |
37 * parser.addFlag('name'); | 32 * parser.addFlag('name'); |
38 * | 33 * |
39 * Flag options will, by default, accept a 'no-' prefix to negate the option. | 34 * Flag options, by default, accept a 'no-' prefix to negate the option. |
40 * This can be disabled like so: | 35 * You can disable the 'no-' prefix using the `negatable` parameter: |
41 * | 36 * |
42 * parser.addFlag('name', negatable: false); | 37 * parser.addFlag('name', negatable: false); |
43 * | 38 * |
44 * (From here on out "option" will refer to both "regular" options and flags. | 39 * **Terminology note:** |
45 * In cases where the distinction matters, we'll use "non-flag option".) | 40 * From here on out, the term _option_ refers to both regular options and |
| 41 * flags. In cases where the distinction matters, this documentation uses |
| 42 * the term _non-flag option._ |
46 * | 43 * |
47 * Options may have an optional single-character abbreviation: | 44 * Options can have an optional single-character abbreviation, specified |
| 45 * with the `abbr` parameter: |
48 * | 46 * |
49 * parser.addOption('mode', abbr: 'm'); | 47 * parser.addOption('mode', abbr: 'm'); |
50 * parser.addFlag('verbose', abbr: 'v'); | 48 * parser.addFlag('verbose', abbr: 'v'); |
51 * | 49 * |
52 * They may also specify a default value. The default value will be used if the | 50 * Options can also have a default value, specified with the `defaultsTo` |
53 * option isn't provided: | 51 * parameter. The default value is used when arguments don't specify the |
| 52 * option. |
54 * | 53 * |
55 * parser.addOption('mode', defaultsTo: 'debug'); | 54 * parser.addOption('mode', defaultsTo: 'debug'); |
56 * parser.addFlag('verbose', defaultsTo: false); | 55 * parser.addFlag('verbose', defaultsTo: false); |
57 * | 56 * |
58 * The default value for non-flag options can be any [String]. For flags, it | 57 * The default value for non-flag options can be any [String]. For flags, |
59 * must be a [bool]. | 58 * it must be a [bool]. |
60 * | 59 * |
61 * To validate non-flag options, you may provide an allowed set of values. When | 60 * To validate a non-flag option, you can use the `allowed` parameter to |
62 * you do, it will throw a [FormatException] when you parse the arguments if | 61 * provide an allowed set of values. When you do, the parser throws a |
63 * the value for an option is not in the allowed set: | 62 * [FormatException] if the value for an option is not in the allowed set. |
| 63 * Here's an example of specifying allowed values: |
64 * | 64 * |
65 * parser.addOption('mode', allowed: ['debug', 'release']); | 65 * parser.addOption('mode', allowed: ['debug', 'release']); |
66 * | 66 * |
67 * You can provide a callback when you define an option. When you later parse | 67 * You can use the `callback` parameter to associate a function with an |
68 * a set of arguments, the callback for that option will be invoked with the | 68 * option. Later, when parsing occurs, the callback function is invoked |
69 * value provided for it: | 69 * with the value of the option: |
70 * | 70 * |
71 * parser.addOption('mode', callback: (mode) => print('Got mode $mode)); | 71 * parser.addOption('mode', callback: (mode) => print('Got mode $mode)); |
72 * parser.addFlag('verbose', callback: (verbose) { | 72 * parser.addFlag('verbose', callback: (verbose) { |
73 * if (verbose) print('Verbose'); | 73 * if (verbose) print('Verbose'); |
74 * }); | 74 * }); |
75 * | 75 * |
76 * The callback for each option will *always* be called when you parse a set of | 76 * The callbacks for all options are called whenever a set of arguments |
77 * arguments. If the option isn't provided in the args, the callback will be | 77 * is parsed. If an option isn't provided in the args, its callback is |
78 * passed the default value, or `null` if there is none set. | 78 * passed the default value, or `null` if no default value is set. |
79 * | 79 * |
80 * ## Parsing arguments ## | 80 * ## Parsing arguments |
81 * | 81 * |
82 * Once you have an [ArgParser] set up with some options and flags, you use it | 82 * Once you have an [ArgParser] set up with some options and flags, you |
83 * by calling [ArgParser.parse()] with a set of arguments: | 83 * use it by calling [ArgParser.parse()] with a set of arguments: |
84 * | 84 * |
85 * var results = parser.parse(['some', 'command', 'line', 'args']); | 85 * var results = parser.parse(['some', 'command', 'line', 'args']); |
86 * | 86 * |
87 * These will usually come from `new Options().arguments`, but you can pass in | 87 * These arguments usually come from dart:io's Options class |
88 * any list of strings. It returns an instance of [ArgResults]. This is a | 88 * (`new Options().arguments`), but you can pass in any list of strings. |
89 * map-like object that will return the value of any parsed option. | 89 * The parse() method returns an instance of [ArgResults], a map-like |
| 90 * object that contains the values of the parsed options. |
90 * | 91 * |
91 * var parser = new ArgParser(); | 92 * var parser = new ArgParser(); |
92 * parser.addOption('mode'); | 93 * parser.addOption('mode'); |
93 * parser.addFlag('verbose', defaultsTo: true); | 94 * parser.addFlag('verbose', defaultsTo: true); |
94 * var results = parser.parse('['--mode', 'debug', 'something', 'else']); | 95 * var results = parser.parse(['--mode', 'debug', 'something', 'else']); |
95 * | 96 * |
96 * print(results['mode']); // debug | 97 * print(results['mode']); // debug |
97 * print(results['verbose']); // true | 98 * print(results['verbose']); // true |
98 * | 99 * |
99 * The [parse()] method will stop as soon as it reaches `--` or anything that | 100 * By default, the parse() method stops as soon as it reaches `--` by itself |
100 * it doesn't recognize as an option, flag, or option value. If there are still | 101 * or anything that the parser doesn't recognize as an option, flag, or |
101 * arguments left, they will be provided to you in | 102 * option value. If arguments still remain, they go into [ArgResults.rest]. |
102 * [ArgResults.rest]. | |
103 * | 103 * |
104 * print(results.rest); // ['something', 'else'] | 104 * print(results.rest); // ['something', 'else'] |
105 * | 105 * |
106 * ## Specifying options ## | 106 * To continue to parse options found after non-option arguments, call |
| 107 * parse() with `allowTrailingOptions: true`. |
107 * | 108 * |
108 * To actually pass in options and flags on the command line, use GNU or POSIX | 109 * ## Specifying options |
109 * style. If you define an option like: | 110 * |
| 111 * To actually pass in options and flags on the command line, use GNU or |
| 112 * POSIX style. Consider this option: |
110 * | 113 * |
111 * parser.addOption('name', abbr: 'n'); | 114 * parser.addOption('name', abbr: 'n'); |
112 * | 115 * |
113 * Then a value for it can be specified on the command line using any of: | 116 * You can specify its value on the command line using any of the following: |
114 * | 117 * |
115 * --name=somevalue | 118 * --name=somevalue |
116 * --name somevalue | 119 * --name somevalue |
117 * -nsomevalue | 120 * -nsomevalue |
118 * -n somevalue | 121 * -n somevalue |
119 * | 122 * |
120 * Given this flag: | 123 * Consider this flag: |
121 * | 124 * |
122 * parser.addFlag('name', abbr: 'n'); | 125 * parser.addFlag('name', abbr: 'n'); |
123 * | 126 * |
124 * You can set it on using one of: | 127 * You can set it to true using one of the following: |
125 * | 128 * |
126 * --name | 129 * --name |
127 * -n | 130 * -n |
128 * | 131 * |
129 * Or set it off using: | 132 * You can set it to false using the following: |
130 * | 133 * |
131 * --no-name | 134 * --no-name |
132 * | 135 * |
133 * Multiple flag abbreviation can also be collapsed into a single argument. If | 136 * Multiple flag abbreviations can be collapsed into a single argument. Say |
134 * you define: | 137 * you define these flags: |
135 * | 138 * |
136 * parser.addFlag('verbose', abbr: 'v'); | 139 * parser.addFlag('verbose', abbr: 'v'); |
137 * parser.addFlag('french', abbr: 'f'); | 140 * parser.addFlag('french', abbr: 'f'); |
138 * parser.addFlag('iambic-pentameter', abbr: 'i'); | 141 * parser.addFlag('iambic-pentameter', abbr: 'i'); |
139 * | 142 * |
140 * Then all three flags could be set using: | 143 * You can set all three flags at once: |
141 * | 144 * |
142 * -vfi | 145 * -vfi |
143 * | 146 * |
144 * By default, an option has only a single value, with later option values | 147 * By default, an option has only a single value, with later option values |
145 * overriding earlier ones; for example: | 148 * overriding earlier ones; for example: |
146 * | 149 * |
147 * var parser = new ArgParser(); | 150 * var parser = new ArgParser(); |
148 * parser.addOption('mode'); | 151 * parser.addOption('mode'); |
149 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); | 152 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); |
150 * print(results['mode']); // prints 'off' | 153 * print(results['mode']); // prints 'off' |
151 * | 154 * |
152 * If you need multiple values, set the [allowMultiple] flag. In that | 155 * If you need multiple values, set the `allowMultiple` parameter. In that |
153 * case the option can occur multiple times and when parsing arguments a | 156 * case the option can occur multiple times, and the parse() method returns |
154 * List of values will be returned: | 157 * a list of values: |
155 * | 158 * |
156 * var parser = new ArgParser(); | 159 * var parser = new ArgParser(); |
157 * parser.addOption('mode', allowMultiple: true); | 160 * parser.addOption('mode', allowMultiple: true); |
158 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); | 161 * var results = parser.parse(['--mode', 'on', '--mode', 'off']); |
159 * print(results['mode']); // prints '[on, off]' | 162 * print(results['mode']); // prints '[on, off]' |
160 * | 163 * |
161 * ## Defining commands ## | 164 * ## Defining commands ## |
162 * | 165 * |
163 * In addition to *options*, you can also define *commands*. A command is a | 166 * In addition to *options*, you can also define *commands*. A command is |
164 * named argument that has its own set of options. For example, when you run: | 167 * a named argument that has its own set of options. For example, consider |
| 168 * this shell command: |
165 * | 169 * |
166 * $ git commit -a | 170 * $ git commit -a |
167 * | 171 * |
168 * The executable is `git`, the command is `commit`, and the `-a` option is an | 172 * The executable is `git`, the command is `commit`, and the `-a` option is |
169 * option passed to the command. You can add a command like so: | 173 * an option passed to the command. You can add a command using the |
| 174 * [addCommand] method: |
170 * | 175 * |
171 * var parser = new ArgParser(); | 176 * var parser = new ArgParser(); |
172 * var command = parser.addCommand('commit'); | 177 * var command = parser.addCommand('commit'); |
173 * | 178 * |
174 * It returns another [ArgParser] which you can then use to define options | 179 * The addCommand() method returns another [ArgParser], which you can then |
175 * specific to that command. If you already have an [ArgParser] for the | 180 * use to define options specific to that command. If you already have an |
176 * command's options, you can pass it to [addCommand]: | 181 * [ArgParser] for the command's options, you can pass it to addCommand: |
177 * | 182 * |
178 * var parser = new ArgParser(); | 183 * var parser = new ArgParser(); |
179 * var command = new ArgParser(); | 184 * var command = new ArgParser(); |
180 * parser.addCommand('commit', command); | 185 * parser.addCommand('commit', command); |
181 * | 186 * |
182 * The [ArgParser] for a command can then define whatever options or flags: | 187 * The [ArgParser] for a command can then define options or flags: |
183 * | 188 * |
184 * command.addFlag('all', abbr: 'a'); | 189 * command.addFlag('all', abbr: 'a'); |
185 * | 190 * |
186 * You can add multiple commands to the same parser so that a user can select | 191 * You can add multiple commands to the same parser so that a user can select |
187 * one from a range of possible commands. When an argument list is parsed, | 192 * one from a range of possible commands. When parsing an argument list, |
188 * you can then determine which command was entered and what options were | 193 * you can then determine which command was entered and what options were |
189 * provided for it. | 194 * provided for it. |
190 * | 195 * |
191 * var results = parser.parse(['commit', '-a']); | 196 * var results = parser.parse(['commit', '-a']); |
192 * print(results.command.name); // "commit" | 197 * print(results.command.name); // "commit" |
193 * print(results.command['a']); // true | 198 * print(results.command['all']); // true |
194 * | 199 * |
195 * Options for a command must appear after the command in the argument list. | 200 * Options for a command must appear after the command in the argument list. |
196 * For example, given the above parser, "git -a commit" is *not* valid. The | 201 * For example, given the above parser, "git -a commit" is *not* valid. The |
197 * parser will try to find the right-most command that accepts an option. For | 202 * parser tries to find the right-most command that accepts an option. For |
198 * example: | 203 * example: |
199 * | 204 * |
200 * var parser = new ArgParser(); | 205 * var parser = new ArgParser(); |
201 * parser.addFlag('all', abbr: 'a'); | 206 * parser.addFlag('all', abbr: 'a'); |
202 * var command = new ArgParser().addCommand('commit'); | 207 * var command = parser.addCommand('commit'); |
203 * parser.addFlag('all', abbr: 'a'); | 208 * command.addFlag('all', abbr: 'a'); |
| 209 * |
204 * var results = parser.parse(['commit', '-a']); | 210 * var results = parser.parse(['commit', '-a']); |
205 * print(results.command['a']); // true | 211 * print(results.command['all']); // true |
206 * | 212 * |
207 * Here, both the top-level parser and the "commit" command can accept a "-a" | 213 * Here, both the top-level parser and the "commit" command can accept a |
208 * (which is probably a bad command line interface, admittedly). In that case, | 214 * "-a" (which is probably a bad command line interface, admittedly). In |
209 * when "-a" appears after "commit", it will be applied to that command. If it | 215 * that case, when "-a" appears after "commit", it is applied to that |
210 * appears to the left of "commit", it will be given to the top-level parser. | 216 * command. If it appears to the left of "commit", it is given to the |
| 217 * top-level parser. |
211 * | 218 * |
212 * ## Displaying usage ## | 219 * ## Displaying usage |
213 * | 220 * |
214 * This library can also be used to automatically generate nice usage help | 221 * You can automatically generate nice help text, suitable for use as the |
215 * text like you get when you run a program with `--help`. To use this, you | 222 * output of `--help`. To display good usage information, you should |
216 * will also want to provide some help text when you create your options. To | 223 * provide some help text when you create your options. |
217 * define help text for the entire option, do: | 224 * |
| 225 * To define help text for an entire option, use the `help` parameter: |
218 * | 226 * |
219 * parser.addOption('mode', help: 'The compiler configuration', | 227 * parser.addOption('mode', help: 'The compiler configuration', |
220 * allowed: ['debug', 'release']); | 228 * allowed: ['debug', 'release']); |
221 * parser.addFlag('verbose', help: 'Show additional diagnostic info'); | 229 * parser.addFlag('verbose', help: 'Show additional diagnostic info'); |
222 * | 230 * |
223 * For non-flag options, you can also provide detailed help for each expected | 231 * For non-flag options, you can also provide detailed help for each expected |
224 * value using a map: | 232 * value by using the `allowedHelp` parameter: |
225 * | 233 * |
226 * parser.addOption('arch', help: 'The architecture to compile for', | 234 * parser.addOption('arch', help: 'The architecture to compile for', |
227 * allowedHelp: { | 235 * allowedHelp: { |
228 * 'ia32': 'Intel x86', | 236 * 'ia32': 'Intel x86', |
229 * 'arm': 'ARM Holding 32-bit chip' | 237 * 'arm': 'ARM Holding 32-bit chip' |
230 * }); | 238 * }); |
231 * | 239 * |
232 * If you define a set of options like the above, then calling this: | 240 * To display the help, use the ArgParser getUsage() method: |
233 * | 241 * |
234 * print(parser.getUsage()); | 242 * print(parser.getUsage()); |
235 * | 243 * |
236 * Will display something like: | 244 * The resulting string looks something like this: |
237 * | 245 * |
238 * --mode The compiler configuration | 246 * --mode The compiler configuration |
239 * [debug, release] | 247 * [debug, release] |
240 * | 248 * |
241 * --[no-]verbose Show additional diagnostic info | 249 * --[no-]verbose Show additional diagnostic info |
242 * --arch The architecture to compile for | 250 * --arch The architecture to compile for |
243 * | 251 * |
244 * [arm] ARM Holding 32-bit chip | 252 * [arm] ARM Holding 32-bit chip |
245 * [ia32] Intel x86 | 253 * [ia32] Intel x86 |
246 * | 254 * |
247 * To assist the formatting of the usage help, single line help text will | 255 * To assist the formatting of the usage help, single-line help text is |
248 * be followed by a single new line. Options with multi-line help text | 256 * followed by a single new line. Options with multi-line help text are |
249 * will be followed by two new lines. This provides spatial diversity between | 257 * followed by two new lines. This provides spatial diversity between options. |
250 * options. | |
251 * | 258 * |
252 * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.h
tml#tag_12_02 | 259 * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.h
tml#tag_12_02 |
253 * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Inte
rfaces | 260 * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Inte
rfaces |
254 * [pub]: http://pub.dartlang.org | |
255 */ | 261 */ |
256 library args; | 262 library args; |
257 | 263 |
258 import 'package:unmodifiable_collection/unmodifiable_collection.dart'; | 264 import 'package:unmodifiable_collection/unmodifiable_collection.dart'; |
259 | 265 |
260 import 'src/parser.dart'; | 266 import 'src/parser.dart'; |
261 import 'src/usage.dart'; | 267 import 'src/usage.dart'; |
262 import 'src/options.dart'; | 268 import 'src/options.dart'; |
263 export 'src/options.dart'; | 269 export 'src/options.dart'; |
264 | 270 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 'Could not find an option named "$name".'); | 445 'Could not find an option named "$name".'); |
440 } | 446 } |
441 | 447 |
442 return _options[name]; | 448 return _options[name]; |
443 } | 449 } |
444 | 450 |
445 /** Get the names of the options as an [Iterable]. */ | 451 /** Get the names of the options as an [Iterable]. */ |
446 Iterable<String> get options => _options.keys; | 452 Iterable<String> get options => _options.keys; |
447 } | 453 } |
448 | 454 |
OLD | NEW |