Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: lib/args/args.dart

Issue 10377023: Using arg parsing lib for dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update with review feedback. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/compiler/implementation/dart2js.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 * This library lets you define parsers for parsing raw command-line arguments
7 * into a set of options and values using [GNU][] and [POSIX][] style options. 7 * into a set of options and values using [GNU][] and [POSIX][] style options.
8 * 8 *
9 * ## Defining options ## 9 * ## Defining options ##
10 * 10 *
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 167
168 /** 168 /**
169 * A class for taking a list of raw command line arguments and parsing out 169 * A class for taking a list of raw command line arguments and parsing out
170 * options and flags from them. 170 * options and flags from them.
171 */ 171 */
172 class ArgParser { 172 class ArgParser {
173 static final _SOLO_OPT = const RegExp(@'^-([a-z0-9])$'); 173 static final _SOLO_OPT = const RegExp(@'^-([a-z0-9])$');
174 static final _ABBR_OPT = const RegExp(@'^-([a-z0-9]+)(.*)$'); 174 static final _ABBR_OPT = const RegExp(@'^-([a-z0-9]+)(.*)$');
175 static final _LONG_OPT = const RegExp(@'^--([a-z\-_0-9]+)(=(.*))?$'); 175 static final _LONG_OPT = const RegExp(@'^--([a-z\-_0-9]+)(=(.*))?$');
176 176
177 final String _usage;
177 final Map<String, _Option> _options; 178 final Map<String, _Option> _options;
178 179
179 /** 180 /**
180 * The names of the options, in the order that they were added. This way we 181 * The names of the options, in the order that they were added. This way we
181 * can generate usage information in the same order. 182 * can generate usage information in the same order.
182 */ 183 */
183 // TODO(rnystrom): Use an ordered map type, if one appears. 184 // TODO(rnystrom): Use an ordered map type, if one appears.
184 final List<String> _optionNames; 185 final List<String> _optionNames;
185 186
186 /** The current argument list being parsed. Set by [parse()]. */ 187 /** The current argument list being parsed. Set by [parse()]. */
187 List<String> _args; 188 List<String> _args;
188 189
189 /** Index of the current argument being parsed in [_args]. */ 190 /** Index of the current argument being parsed in [_args]. */
190 int _current; 191 int _current;
191 192
192 /** Creates a new ArgParser. */ 193 /**
193 ArgParser() 194 * Creates a new ArgParser. If provided [usage] will be included when usage
194 : _options = <_Option>{}, 195 * information is displayed. It is typically the example command-line shown
195 _optionNames = <String>[]; 196 * at the top of help documentation like:
197 *
198 * myapp [options] <arg> <another>
199 *
200 * If [includeHelp] is `true` (or omitted), it will automatically add a
201 * `--help` flag.
202 */
203 ArgParser([String usage, bool includeHelp = true])
204 : _usage = usage,
205 _options = <_Option>{},
206 _optionNames = <String>[] {
207 if (includeHelp) {
208 addFlag('help', abbr: 'h', help: 'Display usage information');
209 }
210 }
196 211
197 /** 212 /**
198 * Defines a flag. Throws an [IllegalArgumentException] if: 213 * Defines a flag. Throws an [IllegalArgumentException] if:
199 * 214 *
200 * * There is already an option named [name]. 215 * * There is already an option named [name].
201 * * There is already an option using abbreviation [abbr]. 216 * * There is already an option using abbreviation [abbr].
202 */ 217 */
203 void addFlag(String name, [String abbr, String help, bool defaultsTo = false, 218 void addFlag(String name, [String abbr, String help, bool defaultsTo = false,
204 void callback(bool value)]) { 219 void callback(bool value)]) {
205 _addOption(name, abbr, help, null, null, defaultsTo, callback, 220 _addOption(name, abbr, help, null, null, defaultsTo, callback,
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 var option = _options[name]; 300 var option = _options[name];
286 if (option.callback != null) option.callback(results[name]); 301 if (option.callback != null) option.callback(results[name]);
287 } 302 }
288 303
289 // Add in the leftover arguments we didn't parse. 304 // Add in the leftover arguments we didn't parse.
290 return new ArgResults(results, 305 return new ArgResults(results,
291 _args.getRange(_current, _args.length - _current)); 306 _args.getRange(_current, _args.length - _current));
292 } 307 }
293 308
294 /** 309 /**
310 * Parses [args], a list of command-line arguments, matches them against the
311 * flags and options defined by this parser, and returns the result. If
312 * `--help` is specified, then it prints usage information to stdout and
313 * exits the process.
314 *
315 * If an error occurs (i.e. an [ArgFormatException] is thrown while parsing),
316 * it prints the error and the usage information and then exits the process
317 * with exit code 1.
318 *
319 * Otherwise, it will return the results of parsing.
320 */
321 ArgResults process(List<String> args) {
322 try {
323 var results = parse(args);
324
325 if (results['help']) {
326 print(getUsage());
327 exit(0);
328 }
329
330 return results;
331 } catch (ArgFormatException ex) {
332 print('${ex.message} Usage:\n\n${getUsage()}');
333 exit(1);
334 }
335 }
336
337 /**
295 * Generates a string displaying usage information for the defined options. 338 * Generates a string displaying usage information for the defined options.
296 * This is basically the help text shown on the command line. 339 * This is basically the help text shown on the command line.
297 */ 340 */
298 String getUsage() { 341 String getUsage() {
299 return new _Usage(this).generate(); 342 return new _Usage(this).generate();
300 } 343 }
301 344
302 /** 345 /**
303 * Called during parsing to validate the arguments. Throws an 346 * Called during parsing to validate the arguments. Throws an
304 * [ArgFormatException] if [condition] is `false`. 347 * [ArgFormatException] if [condition] is `false`.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 * Tries to parse the current argument as a "solo" option, which is a single 384 * Tries to parse the current argument as a "solo" option, which is a single
342 * hyphen followed by a single letter. We treat this differently than 385 * hyphen followed by a single letter. We treat this differently than
343 * collapsed abbreviations (like "-abc") to handle the possible value that 386 * collapsed abbreviations (like "-abc") to handle the possible value that
344 * may follow it. 387 * may follow it.
345 */ 388 */
346 bool _parseSoloOption(Map results) { 389 bool _parseSoloOption(Map results) {
347 var soloOpt = _SOLO_OPT.firstMatch(_args[_current]); 390 var soloOpt = _SOLO_OPT.firstMatch(_args[_current]);
348 if (soloOpt == null) return false; 391 if (soloOpt == null) return false;
349 392
350 var option = _findByAbbr(soloOpt[1]); 393 var option = _findByAbbr(soloOpt[1]);
351 _validate(option != null, 394 _validate(option != null, 'Unknown option "-${soloOpt[1]}".');
352 'Could not find an option or flag "-${soloOpt[1]}".');
353 395
354 if (option.isFlag) { 396 if (option.isFlag) {
355 _setOption(results, option, true); 397 _setOption(results, option, true);
356 } else { 398 } else {
357 _readNextArgAsValue(results, option); 399 _readNextArgAsValue(results, option);
358 } 400 }
359 401
360 return true; 402 return true;
361 } 403 }
362 404
363 /** 405 /**
364 * Tries to parse the current argument as a series of collapsed abbreviations 406 * Tries to parse the current argument as a series of collapsed abbreviations
365 * (like "-abc") or a single abbreviation with the value directly attached 407 * (like "-abc") or a single abbreviation with the value directly attached
366 * to it (like "-mrelease"). 408 * to it (like "-mrelease").
367 */ 409 */
368 bool _parseAbbreviation(Map results) { 410 bool _parseAbbreviation(Map results) {
369 var abbrOpt = _ABBR_OPT.firstMatch(_args[_current]); 411 var abbrOpt = _ABBR_OPT.firstMatch(_args[_current]);
370 if (abbrOpt == null) return false; 412 if (abbrOpt == null) return false;
371 413
372 // If the first character is the abbreviation for a non-flag option, then 414 // If the first character is the abbreviation for a non-flag option, then
373 // the rest is the value. 415 // the rest is the value.
374 var c = abbrOpt[1].substring(0, 1); 416 var c = abbrOpt[1].substring(0, 1);
375 var first = _findByAbbr(c); 417 var first = _findByAbbr(c);
376 if (first == null) { 418 if (first == null) {
377 _validate(false, 'Could not find an option with short name "-$c".'); 419 _validate(false, 'Unknown option "-$c".');
378 } else if (!first.isFlag) { 420 } else if (!first.isFlag) {
379 // The first character is a non-flag option, so the rest must be the 421 // The first character is a non-flag option, so the rest must be the
380 // value. 422 // value.
381 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}'; 423 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}';
382 _setOption(results, first, value); 424 _setOption(results, first, value);
383 } else { 425 } else {
384 // If we got some non-flag characters, then it must be a value, but 426 // If we got some non-flag characters, then it must be a value, but
385 // if we got here, it's a flag, which is wrong. 427 // if we got here, it's a flag, which is wrong.
386 _validate(abbrOpt[2] == '', 428 _validate(abbrOpt[2] == '',
387 'Option "-$c" is a flag and cannot handle value ' 429 'Option "-$c" is a flag and cannot handle value '
388 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".'); 430 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".');
389 431
390 // Not an option, so all characters should be flags. 432 // Not an option, so all characters should be flags.
391 for (var i = 0; i < abbrOpt[1].length; i++) { 433 for (var i = 0; i < abbrOpt[1].length; i++) {
392 var c = abbrOpt[1].substring(i, i + 1); 434 var c = abbrOpt[1].substring(i, i + 1);
393 var option = _findByAbbr(c); 435 var option = _findByAbbr(c);
394 _validate(option != null, 436 _validate(option != null,
395 'Could not find an option with short name "-$c".'); 437 'Unknown option "-$c".');
396 438
397 // In a list of short options, only the first can be a non-flag. If 439 // In a list of short options, only the first can be a non-flag. If
398 // we get here we've checked that already. 440 // we get here we've checked that already.
399 _validate(option.isFlag, 441 _validate(option.isFlag,
400 'Option "-$c" must be a flag to be in a collapsed "-".'); 442 'Option "-$c" must be a flag to be in a collapsed "-".');
401 443
402 _setOption(results, option, true); 444 _setOption(results, option, true);
403 } 445 }
404 } 446 }
405 447
(...skipping 20 matching lines...) Expand all
426 // We have a value like --foo=bar. 468 // We have a value like --foo=bar.
427 _setOption(results, option, longOpt[3]); 469 _setOption(results, option, longOpt[3]);
428 } else { 470 } else {
429 // Option like --foo, so look for the value as the next arg. 471 // Option like --foo, so look for the value as the next arg.
430 _readNextArgAsValue(results, option); 472 _readNextArgAsValue(results, option);
431 } 473 }
432 } else if (name.startsWith('no-')) { 474 } else if (name.startsWith('no-')) {
433 // See if it's a negated flag. 475 // See if it's a negated flag.
434 name = name.substring('no-'.length); 476 name = name.substring('no-'.length);
435 option = _options[name]; 477 option = _options[name];
436 _validate(option != null, 'Could not find an option named "$name".'); 478 _validate(option != null, 'Unknown option "$name".');
437 _validate(option.isFlag, 'Cannot negate non-flag option "$name.'); 479 _validate(option.isFlag, 'Cannot negate non-flag option "$name.');
438 480
439 _setOption(results, option, false); 481 _setOption(results, option, false);
440 } else { 482 } else {
441 _validate(option != null, 'Could not find an option named "$name".'); 483 _validate(option != null, 'Unknown option "$name".');
442 } 484 }
443 485
444 return true; 486 return true;
445 } 487 }
446 488
447 /** 489 /**
448 * Finds the option whose abbreviation is [abbr], or `null` if no option has 490 * Finds the option whose abbreviation is [abbr], or `null` if no option has
449 * that abbreviation. 491 * that abbreviation.
450 */ 492 */
451 _Option _findByAbbr(String abbr) { 493 _Option _findByAbbr(String abbr) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 599
558 _Usage(this.args); 600 _Usage(this.args);
559 601
560 /** 602 /**
561 * Generates a string displaying usage information for the defined options. 603 * Generates a string displaying usage information for the defined options.
562 * This is basically the help text shown on the command line. 604 * This is basically the help text shown on the command line.
563 */ 605 */
564 String generate() { 606 String generate() {
565 buffer = new StringBuffer(); 607 buffer = new StringBuffer();
566 608
609 if (args._usage != null) buffer.add('${args._usage}\n\n');
610
567 calculateColumnWidths(); 611 calculateColumnWidths();
568 612
569 for (var name in args._optionNames) { 613 for (var name in args._optionNames) {
570 var option = args._options[name]; 614 var option = args._options[name];
571 write(0, getAbbreviation(option)); 615 write(0, getAbbreviation(option));
572 write(1, getLongOption(option)); 616 write(1, getLongOption(option));
573 617
574 if (option.help != null) write(2, option.help); 618 if (option.help != null) write(2, option.help);
575 619
576 if (option.allowedHelp != null) { 620 if (option.allowedHelp != null) {
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
720 allowedBuffer.add(allowed); 764 allowedBuffer.add(allowed);
721 if (allowed == option.defaultValue) { 765 if (allowed == option.defaultValue) {
722 allowedBuffer.add(' (default)'); 766 allowedBuffer.add(' (default)');
723 } 767 }
724 first = false; 768 first = false;
725 } 769 }
726 allowedBuffer.add(']'); 770 allowedBuffer.add(']');
727 return allowedBuffer.toString(); 771 return allowedBuffer.toString();
728 } 772 }
729 } 773 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/dart2js.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698