Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 | 8 |
| 9 import 'src/arg_parser.dart'; | 9 import 'src/arg_parser.dart'; |
| 10 import 'src/arg_results.dart'; | 10 import 'src/arg_results.dart'; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 33 /// Generates a string displaying usage information for the executable. | 33 /// Generates a string displaying usage information for the executable. |
| 34 /// | 34 /// |
| 35 /// This includes usage for the global arguments as well as a list of | 35 /// This includes usage for the global arguments as well as a list of |
| 36 /// top-level commands. | 36 /// top-level commands. |
| 37 String get usage => "$description\n\n$_usageWithoutDescription"; | 37 String get usage => "$description\n\n$_usageWithoutDescription"; |
| 38 | 38 |
| 39 /// An optional footer for [usage]. | 39 /// An optional footer for [usage]. |
| 40 /// | 40 /// |
| 41 /// If a subclass overrides this to return a string, it will automatically be | 41 /// If a subclass overrides this to return a string, it will automatically be |
| 42 /// added to the end of [usage]. | 42 /// added to the end of [usage]. |
| 43 final String usageFooter = null; | 43 String get usageFooter => null; |
|
nweiz
2016/03/02 23:58:54
I thought we agreed to stop arguing about finals v
Bob Nystrom
2016/03/03 00:19:08
This is being overridden in subclasses, so making
| |
| 44 | 44 |
| 45 /// Returns [usage] with [description] removed from the beginning. | 45 /// Returns [usage] with [description] removed from the beginning. |
| 46 String get _usageWithoutDescription { | 46 String get _usageWithoutDescription { |
| 47 var usage = ''' | 47 var usage = ''' |
| 48 Usage: $invocation | 48 Usage: $invocation |
| 49 | 49 |
| 50 Global options: | 50 Global options: |
| 51 ${argParser.usage} | 51 ${argParser.usage} |
| 52 | 52 |
| 53 ${_getCommandUsage(_commands)} | 53 ${_getCommandUsage(_commands)} |
| 54 | 54 |
| 55 Run "$executableName help <command>" for more information about a command.'''; | 55 Run "$executableName help <command>" for more information about a command.'''; |
| 56 | 56 |
| 57 if (usageFooter != null) usage += "\n$usageFooter"; | 57 if (usageFooter != null) usage += "\n$usageFooter"; |
| 58 return usage; | 58 return usage; |
| 59 } | 59 } |
| 60 | 60 |
| 61 /// An unmodifiable view of all top-level commands defined for this runner. | 61 /// An unmodifiable view of all top-level commands defined for this runner. |
| 62 Map<String, Command> get commands => new UnmodifiableMapView(_commands); | 62 Map<String, Command> get commands => new UnmodifiableMapView(_commands); |
| 63 final _commands = new Map<String, Command>(); | 63 final _commands = <String, Command>{}; |
| 64 | 64 |
| 65 /// The top-level argument parser. | 65 /// The top-level argument parser. |
| 66 /// | 66 /// |
| 67 /// Global options should be registered with this parser; they'll end up | 67 /// Global options should be registered with this parser; they'll end up |
| 68 /// available via [Command.globalResults]. Commands should be registered with | 68 /// available via [Command.globalResults]. Commands should be registered with |
| 69 /// [addCommand] rather than directly on the parser. | 69 /// [addCommand] rather than directly on the parser. |
| 70 final argParser = new ArgParser(); | 70 final argParser = new ArgParser(); |
| 71 | 71 |
| 72 CommandRunner(this.executableName, this.description) { | 72 CommandRunner(this.executableName, this.description) { |
| 73 argParser.addFlag('help', | 73 argParser.addFlag('help', |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 /// This is notionally a protected method. It may be overridden or called from | 122 /// This is notionally a protected method. It may be overridden or called from |
| 123 /// subclasses, but it shouldn't be called externally. | 123 /// subclasses, but it shouldn't be called externally. |
| 124 /// | 124 /// |
| 125 /// It's useful to override this to handle global flags and/or wrap the entire | 125 /// It's useful to override this to handle global flags and/or wrap the entire |
| 126 /// command in a block. For example, you might handle the `--verbose` flag | 126 /// command in a block. For example, you might handle the `--verbose` flag |
| 127 /// here to enable verbose logging before running the command. | 127 /// here to enable verbose logging before running the command. |
| 128 Future runCommand(ArgResults topLevelResults) { | 128 Future runCommand(ArgResults topLevelResults) { |
| 129 return new Future.sync(() { | 129 return new Future.sync(() { |
| 130 var argResults = topLevelResults; | 130 var argResults = topLevelResults; |
| 131 var commands = _commands; | 131 var commands = _commands; |
| 132 var command; | 132 Command command; |
| 133 var commandString = executableName; | 133 var commandString = executableName; |
| 134 | 134 |
| 135 while (commands.isNotEmpty) { | 135 while (commands.isNotEmpty) { |
| 136 if (argResults.command == null) { | 136 if (argResults.command == null) { |
| 137 if (argResults.rest.isEmpty) { | 137 if (argResults.rest.isEmpty) { |
| 138 if (command == null) { | 138 if (command == null) { |
| 139 // No top-level command was chosen. | 139 // No top-level command was chosen. |
| 140 printUsage(); | 140 printUsage(); |
| 141 return new Future.value(); | 141 return new Future.value(); |
| 142 } | 142 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 /// Generates a string displaying usage information for this command. | 248 /// Generates a string displaying usage information for this command. |
| 249 /// | 249 /// |
| 250 /// This includes usage for the command's arguments as well as a list of | 250 /// This includes usage for the command's arguments as well as a list of |
| 251 /// subcommands, if there are any. | 251 /// subcommands, if there are any. |
| 252 String get usage => "$description\n\n$_usageWithoutDescription"; | 252 String get usage => "$description\n\n$_usageWithoutDescription"; |
| 253 | 253 |
| 254 /// An optional footer for [usage]. | 254 /// An optional footer for [usage]. |
| 255 /// | 255 /// |
| 256 /// If a subclass overrides this to return a string, it will automatically be | 256 /// If a subclass overrides this to return a string, it will automatically be |
| 257 /// added to the end of [usage]. | 257 /// added to the end of [usage]. |
| 258 final String usageFooter = null; | 258 String get usageFooter => null; |
| 259 | 259 |
| 260 /// Returns [usage] with [description] removed from the beginning. | 260 /// Returns [usage] with [description] removed from the beginning. |
| 261 String get _usageWithoutDescription { | 261 String get _usageWithoutDescription { |
| 262 var buffer = new StringBuffer() | 262 var buffer = new StringBuffer() |
| 263 ..writeln('Usage: $invocation') | 263 ..writeln('Usage: $invocation') |
| 264 ..writeln(argParser.usage); | 264 ..writeln(argParser.usage); |
| 265 | 265 |
| 266 if (_subcommands.isNotEmpty) { | 266 if (_subcommands.isNotEmpty) { |
| 267 buffer.writeln(); | 267 buffer.writeln(); |
| 268 buffer.writeln(_getCommandUsage(_subcommands, isSubcommand: true)); | 268 buffer.writeln(_getCommandUsage(_subcommands, isSubcommand: true)); |
| 269 } | 269 } |
| 270 | 270 |
| 271 buffer.writeln(); | 271 buffer.writeln(); |
| 272 buffer.write('Run "${runner.executableName} help" to see global options.'); | 272 buffer.write('Run "${runner.executableName} help" to see global options.'); |
| 273 | 273 |
| 274 if (usageFooter != null) { | 274 if (usageFooter != null) { |
| 275 buffer.writeln(); | 275 buffer.writeln(); |
| 276 buffer.write(usageFooter); | 276 buffer.write(usageFooter); |
| 277 } | 277 } |
| 278 | 278 |
| 279 return buffer.toString(); | 279 return buffer.toString(); |
| 280 } | 280 } |
| 281 | 281 |
| 282 /// An unmodifiable view of all sublevel commands of this command. | 282 /// An unmodifiable view of all sublevel commands of this command. |
| 283 Map<String, Command> get subcommands => new UnmodifiableMapView(_subcommands); | 283 Map<String, Command> get subcommands => new UnmodifiableMapView(_subcommands); |
| 284 final _subcommands = new Map<String, Command>(); | 284 final _subcommands = <String, Command>{}; |
| 285 | 285 |
| 286 /// Whether or not this command should be hidden from help listings. | 286 /// Whether or not this command should be hidden from help listings. |
| 287 /// | 287 /// |
| 288 /// This is intended to be overridden by commands that want to mark themselves | 288 /// This is intended to be overridden by commands that want to mark themselves |
| 289 /// hidden. | 289 /// hidden. |
| 290 /// | 290 /// |
| 291 /// By default, leaf commands are always visible. Branch commands are visible | 291 /// By default, leaf commands are always visible. Branch commands are visible |
| 292 /// as long as any of their leaf commands are visible. | 292 /// as long as any of their leaf commands are visible. |
| 293 bool get hidden { | 293 bool get hidden { |
| 294 // Leaf commands are visible by default. | 294 // Leaf commands are visible by default. |
| 295 if (_subcommands.isEmpty) return false; | 295 if (_subcommands.isEmpty) return false; |
| 296 | 296 |
| 297 // Otherwise, a command is hidden if all of its subcommands are. | 297 // Otherwise, a command is hidden if all of its subcommands are. |
| 298 return _subcommands.values.every((subcommand) => subcommand.hidden); | 298 return _subcommands.values.every((subcommand) => subcommand.hidden); |
| 299 } | 299 } |
| 300 | 300 |
| 301 /// Whether or not this command takes positional arguments in addition to | 301 /// Whether or not this command takes positional arguments in addition to |
| 302 /// options. | 302 /// options. |
| 303 /// | 303 /// |
| 304 /// If false, [CommandRunner.run] will throw a [UsageException] if arguments | 304 /// If false, [CommandRunner.run] will throw a [UsageException] if arguments |
| 305 /// are provided. Defaults to true. | 305 /// are provided. Defaults to true. |
| 306 /// | 306 /// |
| 307 /// This is intended to be overridden by commands that don't want to receive | 307 /// This is intended to be overridden by commands that don't want to receive |
| 308 /// arguments. It has no effect for branch commands. | 308 /// arguments. It has no effect for branch commands. |
| 309 final takesArguments = true; | 309 bool get takesArguments => true; |
| 310 | 310 |
| 311 /// Alternate names for this command. | 311 /// Alternate names for this command. |
| 312 /// | 312 /// |
| 313 /// These names won't be used in the documentation, but they will work when | 313 /// These names won't be used in the documentation, but they will work when |
| 314 /// invoked on the command line. | 314 /// invoked on the command line. |
| 315 /// | 315 /// |
| 316 /// This is intended to be overridden. | 316 /// This is intended to be overridden. |
| 317 final aliases = const <String>[]; | 317 List<String> get aliases => const []; |
| 318 | 318 |
| 319 Command() { | 319 Command() { |
| 320 argParser.addFlag('help', | 320 argParser.addFlag('help', |
| 321 abbr: 'h', negatable: false, help: 'Print this usage information.'); | 321 abbr: 'h', negatable: false, help: 'Print this usage information.'); |
| 322 } | 322 } |
| 323 | 323 |
| 324 /// Runs this command. | 324 /// Runs this command. |
| 325 /// | 325 /// |
| 326 /// If this returns a [Future], [CommandRunner.run] won't complete until the | 326 /// If this returns a [Future], [CommandRunner.run] won't complete until the |
| 327 /// returned [Future] does. Otherwise, the return value is ignored. | 327 /// returned [Future] does. Otherwise, the return value is ignored. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 | 377 |
| 378 for (var line in lines.skip(1)) { | 378 for (var line in lines.skip(1)) { |
| 379 buffer.writeln(); | 379 buffer.writeln(); |
| 380 buffer.write(' ' * (length + 5)); | 380 buffer.write(' ' * (length + 5)); |
| 381 buffer.write(line); | 381 buffer.write(line); |
| 382 } | 382 } |
| 383 } | 383 } |
| 384 | 384 |
| 385 return buffer.toString(); | 385 return buffer.toString(); |
| 386 } | 386 } |
| OLD | NEW |