diff options
Diffstat (limited to 'node_modules/commander')
-rw-r--r-- | node_modules/commander/History.md | 261 | ||||
-rw-r--r-- | node_modules/commander/LICENSE | 22 | ||||
-rw-r--r-- | node_modules/commander/Readme.md | 257 | ||||
-rw-r--r-- | node_modules/commander/index.js | 462 | ||||
-rw-r--r-- | node_modules/commander/package.json | 42 |
5 files changed, 862 insertions, 182 deletions
diff --git a/node_modules/commander/History.md b/node_modules/commander/History.md new file mode 100644 index 000000000..1b47439cb --- /dev/null +++ b/node_modules/commander/History.md @@ -0,0 +1,261 @@ + +2.9.0 / 2015-10-13 +================== + + * Add option `isDefault` to set default subcommand #415 @Qix- + * Add callback to allow filtering or post-processing of help text #434 @djulien + * Fix `undefined` text in help information close #414 #416 @zhiyelee + +2.8.1 / 2015-04-22 +================== + + * Back out `support multiline description` Close #396 #397 + +2.8.0 / 2015-04-07 +================== + + * Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee + * Fix bug in Git-style sub-commands #372 @zhiyelee + * Allow commands to be hidden from help #383 @tonylukasavage + * When git-style sub-commands are in use, yet none are called, display help #382 @claylo + * Add ability to specify arguments syntax for top-level command #258 @rrthomas + * Support multiline descriptions #208 @zxqfox + +2.7.1 / 2015-03-11 +================== + + * Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367. + +2.7.0 / 2015-03-09 +================== + + * Fix git-style bug when installed globally. Close #335 #349 @zhiyelee + * Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage + * Add support for camelCase on `opts()`. Close #353 @nkzawa + * Add node.js 0.12 and io.js to travis.yml + * Allow RegEx options. #337 @palanik + * Fixes exit code when sub-command failing. Close #260 #332 @pirelenito + * git-style `bin` files in $PATH make sense. Close #196 #327 @zhiyelee + +2.6.0 / 2014-12-30 +================== + + * added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee + * Add application description to the help msg. Close #112 @dalssoft + +2.5.1 / 2014-12-15 +================== + + * fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee + +2.5.0 / 2014-10-24 +================== + + * add support for variadic arguments. Closes #277 @whitlockjc + +2.4.0 / 2014-10-17 +================== + + * fixed a bug on executing the coercion function of subcommands option. Closes #270 + * added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage + * added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage + * fixed a bug on subcommand name. Closes #248 @jonathandelgado + * fixed function normalize doesn’t honor option terminator. Closes #216 @abbr + +2.3.0 / 2014-07-16 +================== + + * add command alias'. Closes PR #210 + * fix: Typos. Closes #99 + * fix: Unused fs module. Closes #217 + +2.2.0 / 2014-03-29 +================== + + * add passing of previous option value + * fix: support subcommands on windows. Closes #142 + * Now the defaultValue passed as the second argument of the coercion function. + +2.1.0 / 2013-11-21 +================== + + * add: allow cflag style option params, unit test, fixes #174 + +2.0.0 / 2013-07-18 +================== + + * remove input methods (.prompt, .confirm, etc) + +1.3.2 / 2013-07-18 +================== + + * add support for sub-commands to co-exist with the original command + +1.3.1 / 2013-07-18 +================== + + * add quick .runningCommand hack so you can opt-out of other logic when running a sub command + +1.3.0 / 2013-07-09 +================== + + * add EACCES error handling + * fix sub-command --help + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/commander/LICENSE b/node_modules/commander/LICENSE new file mode 100644 index 000000000..10f997ab1 --- /dev/null +++ b/node_modules/commander/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/commander/Readme.md b/node_modules/commander/Readme.md index 7bb60b2c6..08b9e4cb9 100644 --- a/node_modules/commander/Readme.md +++ b/node_modules/commander/Readme.md @@ -1,8 +1,14 @@ # Commander.js - The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). - [![Build Status](https://api.travis-ci.org/visionmedia/commander.js.svg)](http://travis-ci.org/visionmedia/commander.js) +[![Build Status](https://api.travis-ci.org/tj/commander.js.svg)](http://travis-ci.org/tj/commander.js) +[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander) +[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://www.npmjs.org/package/commander) +[![Join the chat at https://gitter.im/tj/commander.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tj/commander.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/tj/commander). + [API documentation](http://tj.github.com/commander.js/) + ## Installation @@ -25,38 +31,19 @@ program .version('0.0.1') .option('-p, --peppers', 'Add peppers') .option('-P, --pineapple', 'Add pineapple') - .option('-b, --bbq', 'Add bbq sauce') + .option('-b, --bbq-sauce', 'Add bbq sauce') .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') .parse(process.argv); console.log('you ordered a pizza with:'); if (program.peppers) console.log(' - peppers'); if (program.pineapple) console.log(' - pineapple'); -if (program.bbq) console.log(' - bbq'); +if (program.bbqSauce) console.log(' - bbq'); console.log(' - %s cheese', program.cheese); ``` Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. -## Automated --help - - The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: - -``` - $ ./examples/pizza --help - - Usage: pizza [options] - - Options: - - -V, --version output the version number - -p, --peppers Add peppers - -P, --pineapple Add pineapple - -b, --bbq Add bbq sauce - -c, --cheese <type> Add the specified type of cheese [marble] - -h, --help output usage information - -``` ## Coercion @@ -101,6 +88,125 @@ console.log(' verbosity: %j', program.verbose); console.log(' args: %j', program.args); ``` +## Regular Expression +```js +program + .version('0.0.1') + .option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium') + .option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i) + .parse(process.argv); + +console.log(' size: %j', program.size); +console.log(' drink: %j', program.drink); +``` + +## Variadic arguments + + The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to + append `...` to the argument name. Here is an example: + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .command('rmdir <dir> [otherDirs...]') + .action(function (dir, otherDirs) { + console.log('rmdir %s', dir); + if (otherDirs) { + otherDirs.forEach(function (oDir) { + console.log('rmdir %s', oDir); + }); + } + }); + +program.parse(process.argv); +``` + + An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed + to your action as demonstrated above. + +## Specify the argument syntax + +```js +#!/usr/bin/env node + +var program = require('../'); + +program + .version('0.0.1') + .arguments('<cmd> [env]') + .action(function (cmd, env) { + cmdValue = cmd; + envValue = env; + }); + +program.parse(process.argv); + +if (typeof cmdValue === 'undefined') { + console.error('no command given!'); + process.exit(1); +} +console.log('command:', cmdValue); +console.log('environment:', envValue || "no environment given"); +``` + +## Git-style sub-commands + +```js +// file: ./examples/pm +var program = require('..'); + +program + .version('0.0.1') + .command('install [name]', 'install one or more packages') + .command('search [query]', 'search with optional query') + .command('list', 'list packages installed', {isDefault: true}) + .parse(process.argv); +``` + +When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools. +The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`. + +Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the option from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified. + +If the program is designed to be installed globally, make sure the executables have proper modes, like `755`. + +### `--harmony` + +You can enable `--harmony` option in two ways: +* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version don’t support this pattern. +* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + An application for pizzas ordering + + Options: + + -h, --help output usage information + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineapple + -b, --bbq Add bbq sauce + -c, --cheese <type> Add the specified type of cheese [marble] + -C, --no-cheese You do not want any cheese + +``` + ## Custom help You can display arbitrary `-h, --help` information @@ -117,11 +223,7 @@ console.log(' args: %j', program.args); * Module dependencies. */ -var program = require('../'); - -function list(val) { - return val.split(',').map(Number); -} +var program = require('commander'); program .version('0.0.1') @@ -145,7 +247,7 @@ program.parse(process.argv); console.log('stuff'); ``` -yielding the following help output: +Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run: ``` @@ -166,43 +268,84 @@ Examples: ``` -## .outputHelp() +## .outputHelp(cb) + +Output help information without exiting. +Optional callback cb allows post-processing of help text before it is displayed. + +If you want to display help by default (e.g. if no command was provided), you can use something like: + +```js +var program = require('commander'); +var colors = require('colors'); + +program + .version('0.0.1') + .command('getstream [url]', 'get stream URL') + .parse(process.argv); + + if (!process.argv.slice(2).length) { + program.outputHelp(make_red); + } - Output help information without exiting. +function make_red(txt) { + return colors.red(txt); //display the help text in red on the console +} +``` -## .help() +## .help(cb) Output help information and exit immediately. + Optional callback cb allows post-processing of help text before it is displayed. -## Links +## Examples - - [API documentation](http://visionmedia.github.com/commander.js/) - - [ascii tables](https://github.com/LearnBoost/cli-table) - - [progress bars](https://github.com/visionmedia/node-progress) - - [more progress bars](https://github.com/substack/node-multimeter) - - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) +```js +var program = require('commander'); -## License +program + .version('0.0.1') + .option('-C, --chdir <path>', 'change the working directory') + .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf') + .option('-T, --no-tests', 'ignore test hook') -(The MIT License) +program + .command('setup [env]') + .description('run setup commands for all envs') + .option("-s, --setup_mode [mode]", "Which setup mode to use") + .action(function(env, options){ + var mode = options.setup_mode || "normal"; + env = env || 'all'; + console.log('setup for %s env(s) with %s mode', env, mode); + }); + +program + .command('exec <cmd>') + .alias('ex') + .description('execute the given remote cmd') + .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'); + console.log(); + }); + +program + .command('*') + .action(function(env){ + console.log('deploying "%s"', env); + }); + +program.parse(process.argv); +``` -Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> +More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory. -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +## License -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +MIT -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/commander/index.js b/node_modules/commander/index.js index 8378d19a2..a19c05d2e 100644 --- a/node_modules/commander/index.js +++ b/node_modules/commander/index.js @@ -1,19 +1,20 @@ - /** * Module dependencies. */ var EventEmitter = require('events').EventEmitter; var spawn = require('child_process').spawn; +var readlink = require('graceful-readlink').readlinkSync; var path = require('path'); var dirname = path.dirname; var basename = path.basename; +var fs = require('fs'); /** * Expose the root command. */ -exports = module.exports = new Command; +exports = module.exports = new Command(); /** * Expose `Command`. @@ -53,7 +54,7 @@ function Option(flags, description) { * @api private */ -Option.prototype.name = function(){ +Option.prototype.name = function() { return this.long .replace('--', '') .replace('no-', ''); @@ -67,9 +68,8 @@ Option.prototype.name = function(){ * @api private */ -Option.prototype.is = function(arg){ - return arg == this.short - || arg == this.long; +Option.prototype.is = function(arg) { + return arg == this.short || arg == this.long; }; /** @@ -82,9 +82,10 @@ Option.prototype.is = function(arg){ function Command(name) { this.commands = []; this.options = []; - this._execs = []; + this._execs = {}; + this._allowUnknownOption = false; this._args = []; - this._name = name; + this._name = name || ''; } /** @@ -116,46 +117,76 @@ Command.prototype.__proto__ = EventEmitter.prototype; * program * .command('setup') * .description('run remote setup commands') - * .action(function(){ + * .action(function() { * console.log('setup'); * }); * * program * .command('exec <cmd>') * .description('run the given remote command') - * .action(function(cmd){ + * .action(function(cmd) { * console.log('exec "%s"', cmd); * }); * * program + * .command('teardown <dir> [otherDirs...]') + * .description('run teardown commands') + * .action(function(dir, otherDirs) { + * console.log('dir "%s"', dir); + * if (otherDirs) { + * otherDirs.forEach(function (oDir) { + * console.log('dir "%s"', oDir); + * }); + * } + * }); + * + * program * .command('*') * .description('deploy the given env') - * .action(function(env){ + * .action(function(env) { * console.log('deploying "%s"', env); * }); * * program.parse(process.argv); * * @param {String} name - * @param {String} [desc] + * @param {String} [desc] for git-style sub-commands * @return {Command} the new command * @api public */ -Command.prototype.command = function(name, desc) { +Command.prototype.command = function(name, desc, opts) { + opts = opts || {}; var args = name.split(/ +/); var cmd = new Command(args.shift()); - if (desc) cmd.description(desc); - if (desc) this.executables = true; - if (desc) this._execs[cmd._name] = true; + + if (desc) { + cmd.description(desc); + this.executables = true; + this._execs[cmd._name] = true; + if (opts.isDefault) this.defaultExecutable = cmd._name; + } + + cmd._noHelp = !!opts.noHelp; this.commands.push(cmd); cmd.parseExpectedArgs(args); cmd.parent = this; + if (desc) return this; return cmd; }; /** + * Define argument syntax for the top-level command. + * + * @api public + */ + +Command.prototype.arguments = function (desc) { + return this.parseExpectedArgs(desc.split(/ +/)); +}; + +/** * Add an implicit `help [cmd]` subcommand * which invokes `--help` for the given command. * @@ -176,18 +207,33 @@ Command.prototype.addImplicitHelpCommand = function() { * @api public */ -Command.prototype.parseExpectedArgs = function(args){ +Command.prototype.parseExpectedArgs = function(args) { if (!args.length) return; var self = this; - args.forEach(function(arg){ + args.forEach(function(arg) { + var argDetails = { + required: false, + name: '', + variadic: false + }; + switch (arg[0]) { case '<': - self._args.push({ required: true, name: arg.slice(1, -1) }); + argDetails.required = true; + argDetails.name = arg.slice(1, -1); break; case '[': - self._args.push({ required: false, name: arg.slice(1, -1) }); + argDetails.name = arg.slice(1, -1); break; } + + if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') { + argDetails.variadic = true; + argDetails.name = argDetails.name.slice(0, -3); + } + if (argDetails.name) { + self._args.push(argDetails); + } }); return this; }; @@ -200,7 +246,7 @@ Command.prototype.parseExpectedArgs = function(args){ * program * .command('help') * .description('display verbose help') - * .action(function(){ + * .action(function() { * // output help here * }); * @@ -209,9 +255,9 @@ Command.prototype.parseExpectedArgs = function(args){ * @api public */ -Command.prototype.action = function(fn){ +Command.prototype.action = function(fn) { var self = this; - var listener = function(args, unknown){ + var listener = function(args, unknown) { // Parse any so-far unknown options args = args || []; unknown = unknown || []; @@ -231,9 +277,15 @@ Command.prototype.action = function(fn){ // Leftover arguments need to be pushed back. Fixes issue #56 if (parsed.args.length) args = parsed.args.concat(args); - self._args.forEach(function(arg, i){ + self._args.forEach(function(arg, i) { if (arg.required && null == args[i]) { self.missingArgument(arg.name); + } else if (arg.variadic) { + if (i !== self._args.length - 1) { + self.variadicArgNotLast(arg.name); + } + + args[i] = args.splice(i); } }); @@ -246,10 +298,12 @@ Command.prototype.action = function(fn){ args.push(self); } - fn.apply(this, args); + fn.apply(self, args); }; - this.parent.on(this._name, listener); - if (this._alias) this.parent.on(this._alias, listener); + var parent = this.parent || this; + var name = parent === this ? '*' : this._name; + parent.on(name, listener); + if (this._alias) parent.on(this._alias, listener); return this; }; @@ -302,14 +356,26 @@ Command.prototype.action = function(fn){ * @api public */ -Command.prototype.option = function(flags, description, fn, defaultValue){ +Command.prototype.option = function(flags, description, fn, defaultValue) { var self = this , option = new Option(flags, description) , oname = option.name() , name = camelcase(oname); // default as 3rd arg - if ('function' != typeof fn) defaultValue = fn, fn = null; + if (typeof fn != 'function') { + if (fn instanceof RegExp) { + var regex = fn; + fn = function(val, def) { + var m = regex.exec(val); + return m ? m[0] : def; + } + } + else { + defaultValue = fn; + fn = null; + } + } // preassign default value only for --no-*, [optional], or <required> if (false == option.bool || option.optional || option.required) { @@ -324,9 +390,11 @@ Command.prototype.option = function(flags, description, fn, defaultValue){ // when it's passed assign the value // and conditionally invoke the callback - this.on(oname, function(val){ + this.on(oname, function(val) { // coercion - if (null !== val && fn) val = fn(val, undefined === self[name] ? defaultValue : self[name]); + if (null !== val && fn) val = fn(val, undefined === self[name] + ? defaultValue + : self[name]); // unassigned or bool if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { @@ -348,6 +416,18 @@ Command.prototype.option = function(flags, description, fn, defaultValue){ }; /** + * Allow unknown options on the command line. + * + * @param {Boolean} arg if `true` or omitted, no error will be thrown + * for unknown options. + * @api public + */ +Command.prototype.allowUnknownOption = function(arg) { + this._allowUnknownOption = arguments.length === 0 || arg; + return this; +}; + +/** * Parse `argv`, settings options and invoking commands when defined. * * @param {Array} argv @@ -355,7 +435,7 @@ Command.prototype.option = function(flags, description, fn, defaultValue){ * @api public */ -Command.prototype.parse = function(argv){ +Command.prototype.parse = function(argv) { // implicit help if (this.executables) this.addImplicitHelpCommand(); @@ -365,6 +445,12 @@ Command.prototype.parse = function(argv){ // guess name this._name = this._name || basename(argv[1], '.js'); + // github-style sub-commands with no sub-command + if (this.executables && argv.length < 3 && !this.defaultExecutable) { + // this user needs help + argv.push('--help'); + } + // process argv var parsed = this.parseOptions(this.normalize(argv.slice(2))); var args = this.args = parsed.args; @@ -373,7 +459,13 @@ Command.prototype.parse = function(argv){ // executable sub-commands var name = result.args[0]; - if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); + if (this._execs[name] && typeof this._execs[name] != "function") { + return this.executeSubCommand(argv, args, parsed.unknown); + } else if (this.defaultExecutable) { + // use the default subcommand + args.unshift(name = this.defaultExecutable); + return this.executeSubCommand(argv, args, parsed.unknown); + } return result; }; @@ -400,24 +492,63 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) { } // executable - var dir = dirname(argv[1]); - var bin = basename(argv[1], '.js') + '-' + args[0]; + var f = argv[1]; + // name of the subcommand, link `pm-install` + var bin = basename(f, '.js') + '-' + args[0]; - // check for ./<bin> first - var local = path.join(dir, bin); - // run it + // In case of globally installed, get the base dir where executable + // subcommand file should be located at + var baseDir + , link = readlink(f); + + // when symbolink is relative path + if (link !== f && link.charAt(0) !== '/') { + link = path.join(dirname(f), link) + } + baseDir = dirname(link); + + // prefer local `./<bin>` to bin in the $PATH + var localBin = path.join(baseDir, bin); + + // whether bin file is a js script with explicit `.js` extension + var isExplicitJS = false; + if (exists(localBin + '.js')) { + bin = localBin + '.js'; + isExplicitJS = true; + } else if (exists(localBin)) { + bin = localBin; + } + args = args.slice(1); - args.unshift(local); - var proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] }); - proc.on('error', function(err){ + + var proc; + if (process.platform !== 'win32') { + if (isExplicitJS) { + args.unshift(localBin); + // add executable arguments to spawn + args = (process.execArgv || []).concat(args); + + proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] }); + } else { + proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + } + } else { + args.unshift(localBin); + proc = spawn(process.execPath, args, { stdio: 'inherit'}); + } + + proc.on('close', process.exit.bind(process)); + proc.on('error', function(err) { if (err.code == "ENOENT") { console.error('\n %s(1) does not exist, try --help\n', bin); } else if (err.code == "EACCES") { console.error('\n %s(1) not executable. try chmod or run with root\n', bin); } + process.exit(1); }); + // Store the reference to the child process this.runningCommand = proc; }; @@ -431,7 +562,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) { * @api private */ -Command.prototype.normalize = function(args){ +Command.prototype.normalize = function(args) { var ret = [] , arg , lastOpt @@ -439,12 +570,18 @@ Command.prototype.normalize = function(args){ for (var i = 0, len = args.length; i < len; ++i) { arg = args[i]; - i > 0 && (lastOpt = this.optionFor(args[i-1])); + if (i > 0) { + lastOpt = this.optionFor(args[i-1]); + } - if (lastOpt && lastOpt.required) { - ret.push(arg); + if (arg === '--') { + // Honor option terminator + ret = ret.concat(args.slice(i)); + break; + } else if (lastOpt && lastOpt.required) { + ret.push(arg); } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { - arg.slice(1).split('').forEach(function(c){ + arg.slice(1).split('').forEach(function(c) { ret.push('-' + c); }); } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { @@ -469,10 +606,8 @@ Command.prototype.normalize = function(args){ * @api private */ -Command.prototype.parseArgs = function(args, unknown){ - var cmds = this.commands - , len = cmds.length - , name; +Command.prototype.parseArgs = function(args, unknown) { + var name; if (args.length) { name = args[0]; @@ -502,7 +637,7 @@ Command.prototype.parseArgs = function(args, unknown){ * @api private */ -Command.prototype.optionFor = function(arg){ +Command.prototype.optionFor = function(arg) { for (var i = 0, len = this.options.length; i < len; ++i) { if (this.options[i].is(arg)) { return this.options[i]; @@ -519,7 +654,7 @@ Command.prototype.optionFor = function(arg){ * @api public */ -Command.prototype.parseOptions = function(argv){ +Command.prototype.parseOptions = function(argv) { var args = [] , len = argv.length , literal @@ -590,13 +725,30 @@ Command.prototype.parseOptions = function(argv){ }; /** + * Return an object containing options as key-value pairs + * + * @return {Object} + * @api public + */ +Command.prototype.opts = function() { + var result = {} + , len = this.options.length; + + for (var i = 0 ; i < len; i++) { + var key = camelcase(this.options[i].name()); + result[key] = key === 'version' ? this._version : this[key]; + } + return result; +}; + +/** * Argument `name` is missing. * * @param {String} name * @api private */ -Command.prototype.missingArgument = function(name){ +Command.prototype.missingArgument = function(name) { console.error(); console.error(" error: missing required argument `%s'", name); console.error(); @@ -611,7 +763,7 @@ Command.prototype.missingArgument = function(name){ * @api private */ -Command.prototype.optionMissingArgument = function(option, flag){ +Command.prototype.optionMissingArgument = function(option, flag) { console.error(); if (flag) { console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); @@ -629,13 +781,27 @@ Command.prototype.optionMissingArgument = function(option, flag){ * @api private */ -Command.prototype.unknownOption = function(flag){ +Command.prototype.unknownOption = function(flag) { + if (this._allowUnknownOption) return; console.error(); console.error(" error: unknown option `%s'", flag); console.error(); process.exit(1); }; +/** + * Variadic argument with `name` is not the last argument as required. + * + * @param {String} name + * @api private + */ + +Command.prototype.variadicArgNotLast = function(name) { + console.error(); + console.error(" error: variadic arguments must be last `%s'", name); + console.error(); + process.exit(1); +}; /** * Set the program version to `str`. @@ -649,28 +815,28 @@ Command.prototype.unknownOption = function(flag){ * @api public */ -Command.prototype.version = function(str, flags){ +Command.prototype.version = function(str, flags) { if (0 == arguments.length) return this._version; this._version = str; flags = flags || '-V, --version'; this.option(flags, 'output the version number'); - this.on('version', function(){ - console.log(str); + this.on('version', function() { + process.stdout.write(str + '\n'); process.exit(0); }); return this; }; /** - * Set the description `str`. + * Set the description to `str`. * * @param {String} str * @return {String|Command} * @api public */ -Command.prototype.description = function(str){ - if (0 == arguments.length) return this._description; +Command.prototype.description = function(str) { + if (0 === arguments.length) return this._description; this._description = str; return this; }; @@ -683,7 +849,7 @@ Command.prototype.description = function(str){ * @api public */ -Command.prototype.alias = function(alias){ +Command.prototype.alias = function(alias) { if (0 == arguments.length) return this._alias; this._alias = alias; return this; @@ -697,17 +863,14 @@ Command.prototype.alias = function(alias){ * @api public */ -Command.prototype.usage = function(str){ - var args = this._args.map(function(arg){ - return arg.required - ? '<' + arg.name + '>' - : '[' + arg.name + ']'; +Command.prototype.usage = function(str) { + var args = this._args.map(function(arg) { + return humanReadableArgName(arg); }); - var usage = '[options' - + (this.commands.length ? '] [command' : '') - + ']' - + (this._args.length ? ' ' + args : ''); + var usage = '[options]' + + (this.commands.length ? ' [command]' : '') + + (this._args.length ? ' ' + args.join(' ') : ''); if (0 == arguments.length) return this._usage || usage; this._usage = str; @@ -716,14 +879,26 @@ Command.prototype.usage = function(str){ }; /** + * Get the name of the command + * + * @param {String} name + * @return {String|Command} + * @api public + */ + +Command.prototype.name = function() { + return this._name; +}; + +/** * Return the largest option length. * * @return {Number} * @api private */ -Command.prototype.largestOptionLength = function(){ - return this.options.reduce(function(max, option){ +Command.prototype.largestOptionLength = function() { + return this.options.reduce(function(max, option) { return Math.max(max, option.flags.length); }, 0); }; @@ -735,16 +910,15 @@ Command.prototype.largestOptionLength = function(){ * @api private */ -Command.prototype.optionHelp = function(){ +Command.prototype.optionHelp = function() { var width = this.largestOptionLength(); // 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; + .concat(this.options.map(function(option) { + return pad(option.flags, width) + ' ' + option.description; })) - .join('\n'); + .join('\n'); }; /** @@ -754,30 +928,36 @@ Command.prototype.optionHelp = function(){ * @api private */ -Command.prototype.commandHelp = function(){ +Command.prototype.commandHelp = function() { if (!this.commands.length) return ''; + + var commands = this.commands.filter(function(cmd) { + return !cmd._noHelp; + }).map(function(cmd) { + var args = cmd._args.map(function(arg) { + return humanReadableArgName(arg); + }).join(' '); + + return [ + cmd._name + + (cmd._alias ? '|' + cmd._alias : '') + + (cmd.options.length ? ' [options]' : '') + + ' ' + args + , cmd.description() + ]; + }); + + var width = commands.reduce(function(max, command) { + return Math.max(max, command[0].length); + }, 0); + return [ - '' + '' , ' Commands:' , '' - , this.commands.map(function(cmd){ - var args = cmd._args.map(function(arg){ - return arg.required - ? '<' + arg.name + '>' - : '[' + arg.name + ']'; - }).join(' '); - - return cmd._name - + (cmd._alias - ? '|' + cmd._alias - : '') - + (cmd.options.length - ? ' [options]' - : '') + ' ' + args - + (cmd.description() - ? '\n ' + cmd.description() - : '') - + '\n'; + , commands.map(function(cmd) { + var desc = cmd[1] ? ' ' + cmd[1] : ''; + return pad(cmd[0], width) + desc; }).join('\n').replace(/^/gm, ' ') , '' ].join('\n'); @@ -790,21 +970,42 @@ Command.prototype.commandHelp = function(){ * @api private */ -Command.prototype.helpInformation = function(){ - return [ - '' - , ' Usage: ' + this._name - + (this._alias - ? '|' + this._alias - : '') - + ' ' + this.usage() - , '' + this.commandHelp() - , ' Options:' +Command.prototype.helpInformation = function() { + var desc = []; + if (this._description) { + desc = [ + ' ' + this._description + , '' + ]; + } + + var cmdName = this._name; + if (this._alias) { + cmdName = cmdName + '|' + this._alias; + } + var usage = [ + '' + ,' Usage: ' + cmdName + ' ' + this.usage() + , '' + ]; + + var cmds = []; + var commandHelp = this.commandHelp(); + if (commandHelp) cmds = [commandHelp]; + + var options = [ + ' Options:' , '' , '' + this.optionHelp().replace(/^/gm, ' ') , '' , '' - ].join('\n'); + ]; + + return usage + .concat(cmds) + .concat(desc) + .concat(options) + .join('\n'); }; /** @@ -813,8 +1014,13 @@ Command.prototype.helpInformation = function(){ * @api public */ -Command.prototype.outputHelp = function(){ - process.stdout.write(this.helpInformation()); +Command.prototype.outputHelp = function(cb) { + if (!cb) { + cb = function(passthru) { + return passthru; + } + } + process.stdout.write(cb(this.helpInformation())); this.emit('--help'); }; @@ -824,8 +1030,8 @@ Command.prototype.outputHelp = function(){ * @api public */ -Command.prototype.help = function(){ - this.outputHelp(); +Command.prototype.help = function(cb) { + this.outputHelp(cb); process.exit(); }; @@ -838,7 +1044,7 @@ Command.prototype.help = function(){ */ function camelcase(flag) { - return flag.split('-').reduce(function(str, word){ + return flag.split('-').reduce(function(str, word) { return str + word[0].toUpperCase() + word.slice(1); }); } @@ -874,3 +1080,31 @@ function outputHelpIfNecessary(cmd, options) { } } } + +/** + * Takes an argument an returns its human readable equivalent for help usage. + * + * @param {Object} arg + * @return {String} + * @api private + */ + +function humanReadableArgName(arg) { + var nameOutput = arg.name + (arg.variadic === true ? '...' : ''); + + return arg.required + ? '<' + nameOutput + '>' + : '[' + nameOutput + ']' +} + +// for versions before node v0.8 when there weren't `fs.existsSync` +function exists(file) { + try { + if (fs.statSync(file).isFile()) { + return true; + } + } catch (e) { + return false; + } +} + diff --git a/node_modules/commander/package.json b/node_modules/commander/package.json index b6033c80f..77311492d 100644 --- a/node_modules/commander/package.json +++ b/node_modules/commander/package.json @@ -1,13 +1,33 @@ { - "name": "commander" - , "version": "2.3.0" - , "description": "the complete solution for node.js command-line programs" - , "keywords": ["command", "option", "parser", "prompt", "stdin"] - , "author": "TJ Holowaychuk <tj@vision-media.ca>" - , "repository": { "type": "git", "url": "https://github.com/visionmedia/commander.js.git" } - , "devDependencies": { "should": ">= 0.0.1" } - , "scripts": { "test": "make test" } - , "main": "index" - , "engines": { "node": ">= 0.6.x" } - , "files": ["index.js"] + "name": "commander", + "version": "2.9.0", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser" + ], + "author": "TJ Holowaychuk <tj@vision-media.ca>", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/tj/commander.js.git" + }, + "devDependencies": { + "should": ">= 0.0.1", + "sinon": ">=1.17.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.6.x" + }, + "files": [ + "index.js" + ], + "dependencies": { + "graceful-readlink": ">= 1.0.0" + } } |