diff --git a/index.js b/index.js index 22c15adac..ac8abd78a 100644 --- a/index.js +++ b/index.js @@ -182,6 +182,7 @@ Command.prototype.command = function(name, desc, opts) { if (opts.isDefault) this.defaultExecutable = cmd._name; } cmd._noHelp = !!opts.noHelp; + cmd._specifySubcommand = opts.subcommand; this.commands.push(cmd); cmd.parseExpectedArgs(args); cmd.parent = this; @@ -484,7 +485,16 @@ Command.prototype.parse = function(argv) { })[0]; } - if (this._execs[name] && typeof this._execs[name] !== 'function') { + var specifySubcommand = null; + if (name) { + specifySubcommand = this.commands.filter(function(command) { + return command._name === name && command._specifySubcommand != null; + })[0]; + } + + if (specifySubcommand) { + return this.executeSubCommand(argv, args, parsed.unknown, specifySubcommand._specifySubcommand); + } else if (this._execs[name] && typeof this._execs[name] !== 'function') { return this.executeSubCommand(argv, args, parsed.unknown); } else if (aliasCommand) { // is alias of a subCommand @@ -505,10 +515,11 @@ Command.prototype.parse = function(argv) { * @param {Array} argv * @param {Array} args * @param {Array} unknown + * @param {String} specifySubcommand * @api private */ -Command.prototype.executeSubCommand = function(argv, args, unknown) { +Command.prototype.executeSubCommand = function(argv, args, unknown, specifySubcommand) { args = args.concat(unknown); if (!args.length) this.help(); @@ -524,6 +535,9 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) { var f = argv[1]; // name of the subcommand, link `pm-install` var bin = basename(f, path.extname(f)) + '-' + args[0]; + if (specifySubcommand != null) { + bin = specifySubcommand; + } // In case of globally installed, get the base dir where executable // subcommand file should be located at diff --git a/test/fixtures/pm b/test/fixtures/pm index d86822d9b..b0e7139d7 100755 --- a/test/fixtures/pm +++ b/test/fixtures/pm @@ -11,4 +11,6 @@ program .command('listen', 'listen for supported signal events').alias('l') .command('publish', 'publish or update package').alias('p') .command('default', 'default command', {noHelp: true, isDefault: true}) + .command('specifyInstall', 'specify install subcommand', {subcommand: 'pm-install'}) + .command('specifyPublish', 'specify publish subcommand', {subcommand: 'pm-publish'}) .parse(process.argv); diff --git a/test/test.command.executableSubcommandSpecifySubcommand.js b/test/test.command.executableSubcommandSpecifySubcommand.js new file mode 100644 index 000000000..26e20564b --- /dev/null +++ b/test/test.command.executableSubcommandSpecifySubcommand.js @@ -0,0 +1,44 @@ +var exec = require('child_process').exec + , path = require('path') + , should = require('should'); + + + +var bin = path.join(__dirname, './fixtures/pm') +// success case +exec(bin + ' specifyInstall', function(error, stdout, stderr) { + // Optionally specify `pm-install` + stdout.should.equal('install\n'); +}); +exec(bin + ' specifyPublish', function(error, stdout, stderr) { + // Optionally specify `pm-publish` + stdout.should.equal('publish\n'); +}); + +// not exist +exec(bin + ' list', function (error, stdout, stderr) { + //stderr.should.equal('\n pm-list(1) does not exist, try --help\n\n'); + should.notEqual(0, stderr.length); +}); + +// success case +exec(bin + ' install', function (error, stdout, stderr) { + stdout.should.equal('install\n'); +}); + +// subcommand bin file with explicit extension +exec(bin + ' publish', function (error, stdout, stderr) { + stdout.should.equal('publish\n'); +}); + +// spawn EACCES +exec(bin + ' search', function (error, stdout, stderr) { + should.notEqual(0, stderr.length); +}); + +// when `bin` is a symbol link for mocking global install +var bin = path.join(__dirname, './fixtures/pmlink') +// success case +exec(bin + ' install', function (error, stdout, stderr) { + stdout.should.equal('install\n'); +});