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 |