Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

merged / tweaked

  • Loading branch information...
commit 6ccb63972e67d1a2aa52b8e42408dd28078770bc 2 parents ba74d56 + 4788f70
@tj authored
Showing with 70 additions and 23 deletions.
  1. +5 −0 examples/deploy
  2. +52 −21 lib/commander.js
  3. +13 −2 test/test.options.commands.js
View
5 examples/deploy
@@ -28,6 +28,11 @@ program
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
+ }).on('--help', function() {
+ console.log(' Examples:');
+ console.log('');
+ console.log(' $ deploy exec sequential');
+ console.log(' $ deploy exec async');
});
program
View
73 lib/commander.js
@@ -201,11 +201,16 @@ Command.prototype.action = function(fn){
var self = this;
this.parent.on(this.name, function(args, unknown){
// Parse any so-far unknown options
+ unknown = unknown || [];
var parsed = self.parseOptions(unknown);
+ // Output help if necessary
+ outputHelpIfNecessary(self, parsed.unknown);
+
// If there are still any unknown options, then we simply
- // die.
- if (parsed.unknown.length > 0) {
+ // die, unless someone asked for help, in which case we give it
+ // to them, and then we die.
+ if (parsed.unknown.length > 0) {
self.unknownOption(parsed.unknown[0]);
}
@@ -218,7 +223,11 @@ Command.prototype.action = function(fn){
// Always append ourselves to the end of the arguments,
// to make sure we match the number of arguments the user
// expects
- args[self.args.length] = self;
+ if (self.args.length) {
+ args[self.args.length] = self;
+ } else {
+ args.push(self);
+ }
fn.apply(this, args);
});
@@ -388,14 +397,15 @@ Command.prototype.parseArgs = function(args, unknown){
name = args[0];
if (this.listeners(name).length) {
this.emit(args.shift(), args, unknown);
- } else {
+ } else {
this.emit('*', args);
}
- }
- else {
+ } else {
+ outputHelpIfNecessary(this, unknown);
+
// If there were no args and we have unknown options,
// then they are extraneous and we need to error.
- if (unknown.length > 0) {
+ if (unknown.length > 0) {
this.unknownOption(unknown[0]);
}
}
@@ -486,7 +496,7 @@ Command.prototype.parseOptions = function(argv){
// If the next argument looks like it might be
// an argument for this option, we pass it on.
// If it isn't, then it'll simply be ignored
- if (argv[i+1] && !(argv[i+1][0] === '-')) {
+ if (argv[i+1] && '-' != argv[i+1][0]) {
unknownOptions.push(argv[++i]);
}
continue;
@@ -593,9 +603,15 @@ Command.prototype.description = function(str){
*/
Command.prototype.usage = function(str){
+ var args = this.args.map(function(arg){
+ return arg.required
+ ? '<' + arg.name + '>'
+ : '[' + arg.name + ']';
+ });
var usage = '[options'
+ (this.commands.length ? '] [command' : '')
- + ']';
+ + ']'
+ + (this.args.length ? ' ' + args : '');
if (0 == arguments.length) return this._usage || usage;
this._usage = str;
return this;
@@ -623,10 +639,14 @@ Command.prototype.largestOptionLength = function(){
Command.prototype.optionHelp = function(){
var width = this.largestOptionLength();
- return this.options.map(function(option){
- return pad(option.flags, width)
- + ' ' + option.description;
- }).join('\n');
+
+ // Prepend the help information
+ return [pad('-h, --help', width) + ' ' + 'output usage information']
+ .concat(this.options.map(function(option){
+ return pad(option.flags, width)
+ + ' ' + option.description;
+ }))
+ .join('\n');
};
/**
@@ -648,7 +668,10 @@ Command.prototype.commandHelp = function(){
? '<' + arg.name + '>'
: '[' + arg.name + ']';
}).join(' ');
- return cmd.name + ' ' + args
+ return cmd.name
+ + (cmd.options.length
+ ? ' [options]'
+ : '') + ' ' + args
+ (cmd.description()
? '\n' + cmd.description()
: '');
@@ -945,12 +968,20 @@ function pad(str, width) {
}
/**
- * Default -h, --help option.
+ * Output help information if necessary
+ *
+ * @param {Command} command to output help for
+ * @param {Array} array of options to search for -h or --help
+ * @api private
*/
-exports.option('-h, --help', 'output usage information');
-exports.on('help', function(){
- process.stdout.write(this.helpInformation());
- exports.emit('--help');
- process.exit(0);
-});
+function outputHelpIfNecessary(cmd, options) {
+ options = options || [];
+ for (var i = 0; i < options.length; i++) {
+ if (options[i] == '--help' || options[i] == '-h') {
+ cmd.emit('--help');
+ process.stdout.write(cmd.helpInformation());
+ process.exit(0);
+ }
+ }
+}
View
15 test/test.options.commands.js
@@ -13,6 +13,7 @@ program
var envValue = "";
var cmdValue = "";
+var customHelp = false;
program
.command('setup [env]')
@@ -33,6 +34,8 @@ program
.option("-t, --target [target]", "Target to use")
.action(function(cmd, options){
cmdValue = cmd;
+ }).on("--help", function(){
+ customHelp = true;
});
program
@@ -85,7 +88,15 @@ cmdValue.should.equal("exec3");
// Make sure we still catch errors with required values for options
var exceptionOccurred = false;
var oldProcessExit = process.exit;
+var oldConsoleError = console.error;
process.exit = function() { exceptionOccurred = true; throw new Error(); };
+console.error = function() {};
+
+try {
+ program.parse(['node', 'test', '--config', 'conf6', 'exec', '--help']);
+} catch(ex) {
+ program.config.should.equal("conf6");
+}
try {
program.parse(['node', 'test', '--config', 'conf', 'exec', '-t', 'target1', 'exec1', '-e']);
@@ -93,6 +104,6 @@ try {
catch(ex) {
}
+process.exit = oldProcessExit;
exceptionOccurred.should.be.true;
-
-process.exit = oldProcessExit;
+customHelp.should.be.true;
Please sign in to comment.
Something went wrong with that request. Please try again.