Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Print command help for "bin --help command" #55

Merged
merged 2 commits into from
Nov 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.13.6+1

* When a `CommandRunner` is passed `--help` before any commands, it now prints
the usage of the chosen command.

## 0.13.6

* `ArgParser.parse()` now throws an `ArgParserException`, which implements
Expand Down
99 changes: 51 additions & 48 deletions lib/command_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,56 +132,59 @@ Run "$executableName help <command>" for more information about a command.''';
/// It's useful to override this to handle global flags and/or wrap the entire
/// command in a block. For example, you might handle the `--verbose` flag
/// here to enable verbose logging before running the command.
Future runCommand(ArgResults topLevelResults) {
return new Future.sync(() {
var argResults = topLevelResults;
var commands = _commands;
Command command;
var commandString = executableName;

while (commands.isNotEmpty) {
if (argResults.command == null) {
if (argResults.rest.isEmpty) {
if (command == null) {
// No top-level command was chosen.
printUsage();
return new Future.value();
}

command.usageException('Missing subcommand for "$commandString".');
} else {
if (command == null) {
usageException(
'Could not find a command named "${argResults.rest[0]}".');
}

command.usageException('Could not find a subcommand named '
'"${argResults.rest[0]}" for "$commandString".');
Future runCommand(ArgResults topLevelResults) async {
var argResults = topLevelResults;
var commands = _commands;
Command command;
var commandString = executableName;

while (commands.isNotEmpty) {
if (argResults.command == null) {
if (argResults.rest.isEmpty) {
if (command == null) {
// No top-level command was chosen.
printUsage();
return;
}

command.usageException('Missing subcommand for "$commandString".');
} else {
if (command == null) {
usageException(
'Could not find a command named "${argResults.rest[0]}".');
}
}

// Step into the command.
argResults = argResults.command;
command = commands[argResults.name];
command._globalResults = topLevelResults;
command._argResults = argResults;
commands = command._subcommands;
commandString += " ${argResults.name}";

if (argResults['help']) {
command.printUsage();
return new Future.value();
command.usageException('Could not find a subcommand named '
'"${argResults.rest[0]}" for "$commandString".');
}
}

// Make sure there aren't unexpected arguments.
if (!command.takesArguments && argResults.rest.isNotEmpty) {
command.usageException(
'Command "${argResults.name}" does not take any arguments.');
// Step into the command.
argResults = argResults.command;
command = commands[argResults.name];
command._globalResults = topLevelResults;
command._argResults = argResults;
commands = command._subcommands;
commandString += " ${argResults.name}";

if (argResults['help']) {
command.printUsage();
return;
}
}

return command.run();
});
if (topLevelResults['help']) {
command.printUsage();
return;
}

// Make sure there aren't unexpected arguments.
if (!command.takesArguments && argResults.rest.isNotEmpty) {
command.usageException(
'Command "${argResults.name}" does not take any arguments.');
}

await command.run();
Copy link

@Hixie Hixie Nov 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change -- it means the command's exit code is no longer propagated.
See https://github.com/dart-lang/args/issues/58

}
}

Expand Down Expand Up @@ -274,8 +277,8 @@ abstract class Command {
/// Returns [usage] with [description] removed from the beginning.
String get _usageWithoutDescription {
var buffer = new StringBuffer()
..writeln('Usage: $invocation')
..writeln(argParser.usage);
..writeln('Usage: $invocation')
..writeln(argParser.usage);

if (_subcommands.isNotEmpty) {
buffer.writeln();
Expand Down Expand Up @@ -361,7 +364,7 @@ abstract class Command {

/// Throws a [UsageException] with [message].
void usageException(String message) =>
throw new UsageException(message, _usageWithoutDescription);
throw new UsageException(message, _usageWithoutDescription);
}

/// Returns a string representation of [commands] fit for use in a usage string.
Expand All @@ -372,7 +375,7 @@ String _getCommandUsage(Map<String, Command> commands,
{bool isSubcommand: false}) {
// Don't include aliases.
var names =
commands.keys.where((name) => !commands[name].aliases.contains(name));
commands.keys.where((name) => !commands[name].aliases.contains(name));

// Filter out hidden ones, unless they are all hidden.
var visible = names.where((name) => !commands[name].hidden);
Expand All @@ -383,7 +386,7 @@ String _getCommandUsage(Map<String, Command> commands,
var length = names.map((name) => name.length).reduce(math.max);

var buffer =
new StringBuffer('Available ${isSubcommand ? "sub" : ""}commands:');
new StringBuffer('Available ${isSubcommand ? "sub" : ""}commands:');
for (var name in names) {
var lines = commands[name].summary.split("\n");
buffer.writeln();
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: args
version: 0.13.6
version: 0.13.6+1
author: "Dart Team <[email protected]>"
homepage: https://github.com/dart-lang/args
description: >
Expand Down
16 changes: 15 additions & 1 deletion test/command_runner_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ $_DEFAULT_USAGE
"""));
});

test("with a command prints the usage for that command", () {
test("with a preceding command prints the usage for that command", () {
var command = new FooCommand();
runner.addCommand(command);

Expand All @@ -207,6 +207,20 @@ Set a value.
Usage: test foo [arguments]
-h, --help Print this usage information.

Run "test help" to see global options.
"""));
});

test("with a following command prints the usage for that command", () {
var command = new FooCommand();
runner.addCommand(command);

expect(() => runner.run(["--help", "foo"]), prints("""
Set a value.

Usage: test foo [arguments]
-h, --help Print this usage information.

Run "test help" to see global options.
"""));
});
Expand Down