Comparing version 2.1.0 to 2.2.0
838
index.js
@@ -0,19 +1,9 @@ | ||
var Option = require('./lib/option'); | ||
var Command = require('./lib/command'); | ||
/** | ||
* Module dependencies. | ||
*/ | ||
var EventEmitter = require('events').EventEmitter; | ||
var spawn = require('child_process').spawn; | ||
var fs = require('fs'); | ||
var exists = fs.existsSync; | ||
var path = require('path'); | ||
var dirname = path.dirname; | ||
var basename = path.basename; | ||
/** | ||
* Expose the root command. | ||
*/ | ||
exports = module.exports = new Command; | ||
exports = module.exports = new Command(); | ||
@@ -31,823 +21,1 @@ /** | ||
exports.Option = Option; | ||
/** | ||
* Initialize a new `Option` with the given `flags` and `description`. | ||
* | ||
* @param {String} flags | ||
* @param {String} description | ||
* @api public | ||
*/ | ||
function Option(flags, description) { | ||
this.flags = flags; | ||
this.required = ~flags.indexOf('<'); | ||
this.optional = ~flags.indexOf('['); | ||
this.bool = !~flags.indexOf('-no-'); | ||
flags = flags.split(/[ ,|]+/); | ||
if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); | ||
this.long = flags.shift(); | ||
this.description = description || ''; | ||
} | ||
/** | ||
* Return option name. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
Option.prototype.name = function(){ | ||
return this.long | ||
.replace('--', '') | ||
.replace('no-', ''); | ||
}; | ||
/** | ||
* Check if `arg` matches the short or long flag. | ||
* | ||
* @param {String} arg | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
Option.prototype.is = function(arg){ | ||
return arg == this.short | ||
|| arg == this.long; | ||
}; | ||
/** | ||
* Initialize a new `Command`. | ||
* | ||
* @param {String} name | ||
* @api public | ||
*/ | ||
function Command(name) { | ||
this.commands = []; | ||
this.options = []; | ||
this._execs = []; | ||
this._args = []; | ||
this._name = name; | ||
} | ||
/** | ||
* Inherit from `EventEmitter.prototype`. | ||
*/ | ||
Command.prototype.__proto__ = EventEmitter.prototype; | ||
/** | ||
* Add command `name`. | ||
* | ||
* The `.action()` callback is invoked when the | ||
* command `name` is specified via __ARGV__, | ||
* and the remaining arguments are applied to the | ||
* function for access. | ||
* | ||
* When the `name` is "*" an un-matched command | ||
* will be passed as the first arg, followed by | ||
* the rest of __ARGV__ remaining. | ||
* | ||
* Examples: | ||
* | ||
* 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') | ||
* | ||
* program | ||
* .command('setup') | ||
* .description('run remote setup commands') | ||
* .action(function(){ | ||
* console.log('setup'); | ||
* }); | ||
* | ||
* program | ||
* .command('exec <cmd>') | ||
* .description('run the given remote command') | ||
* .action(function(cmd){ | ||
* console.log('exec "%s"', cmd); | ||
* }); | ||
* | ||
* program | ||
* .command('*') | ||
* .description('deploy the given env') | ||
* .action(function(env){ | ||
* console.log('deploying "%s"', env); | ||
* }); | ||
* | ||
* program.parse(process.argv); | ||
* | ||
* @param {String} name | ||
* @param {String} [desc] | ||
* @return {Command} the new command | ||
* @api public | ||
*/ | ||
Command.prototype.command = function(name, desc){ | ||
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; | ||
this.commands.push(cmd); | ||
cmd.parseExpectedArgs(args); | ||
cmd.parent = this; | ||
if (desc) return this; | ||
return cmd; | ||
}; | ||
/** | ||
* Add an implicit `help [cmd]` subcommand | ||
* which invokes `--help` for the given command. | ||
* | ||
* @api private | ||
*/ | ||
Command.prototype.addImplicitHelpCommand = function() { | ||
this.command('help [cmd]', 'display help for [cmd]'); | ||
}; | ||
/** | ||
* Parse expected `args`. | ||
* | ||
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. | ||
* | ||
* @param {Array} args | ||
* @return {Command} for chaining | ||
* @api public | ||
*/ | ||
Command.prototype.parseExpectedArgs = function(args){ | ||
if (!args.length) return; | ||
var self = this; | ||
args.forEach(function(arg){ | ||
switch (arg[0]) { | ||
case '<': | ||
self._args.push({ required: true, name: arg.slice(1, -1) }); | ||
break; | ||
case '[': | ||
self._args.push({ required: false, name: arg.slice(1, -1) }); | ||
break; | ||
} | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Register callback `fn` for the command. | ||
* | ||
* Examples: | ||
* | ||
* program | ||
* .command('help') | ||
* .description('display verbose help') | ||
* .action(function(){ | ||
* // output help here | ||
* }); | ||
* | ||
* @param {Function} fn | ||
* @return {Command} for chaining | ||
* @api public | ||
*/ | ||
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, 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]); | ||
} | ||
// 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){ | ||
if (arg.required && null == args[i]) { | ||
self.missingArgument(arg.name); | ||
} | ||
}); | ||
// Always append ourselves to the end of the arguments, | ||
// to make sure we match the number of arguments the user | ||
// expects | ||
if (self._args.length) { | ||
args[self._args.length] = self; | ||
} else { | ||
args.push(self); | ||
} | ||
fn.apply(this, args); | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Define option with `flags`, `description` and optional | ||
* coercion `fn`. | ||
* | ||
* The `flags` string should contain both the short and long flags, | ||
* separated by comma, a pipe or space. The following are all valid | ||
* all will output this way when `--help` is used. | ||
* | ||
* "-p, --pepper" | ||
* "-p|--pepper" | ||
* "-p --pepper" | ||
* | ||
* Examples: | ||
* | ||
* // simple boolean defaulting to false | ||
* program.option('-p, --pepper', 'add pepper'); | ||
* | ||
* --pepper | ||
* program.pepper | ||
* // => Boolean | ||
* | ||
* // simple boolean defaulting to false | ||
* program.option('-C, --no-cheese', 'remove cheese'); | ||
* | ||
* program.cheese | ||
* // => true | ||
* | ||
* --no-cheese | ||
* program.cheese | ||
* // => true | ||
* | ||
* // required argument | ||
* program.option('-C, --chdir <path>', 'change the working directory'); | ||
* | ||
* --chdir /tmp | ||
* program.chdir | ||
* // => "/tmp" | ||
* | ||
* // optional argument | ||
* program.option('-c, --cheese [type]', 'add cheese [marble]'); | ||
* | ||
* @param {String} flags | ||
* @param {String} description | ||
* @param {Function|Mixed} fn or default | ||
* @param {Mixed} defaultValue | ||
* @return {Command} for chaining | ||
* @api public | ||
*/ | ||
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; | ||
// preassign default value only for --no-*, [optional], or <required> | ||
if (false == option.bool || option.optional || option.required) { | ||
// when --no-* we make sure default is true | ||
if (false == option.bool) defaultValue = true; | ||
// preassign only if we have a default | ||
if (undefined !== defaultValue) self[name] = defaultValue; | ||
} | ||
// register the option | ||
this.options.push(option); | ||
// when it's passed assign the value | ||
// and conditionally invoke the callback | ||
this.on(oname, function(val){ | ||
// coercion | ||
if (null != val && fn) val = fn(val); | ||
// unassigned or bool | ||
if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { | ||
// if no value, bool true, and we have a default, then use it! | ||
if (null == val) { | ||
self[name] = option.bool | ||
? defaultValue || true | ||
: false; | ||
} else { | ||
self[name] = val; | ||
} | ||
} else if (null !== val) { | ||
// reassign | ||
self[name] = val; | ||
} | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Parse `argv`, settings options and invoking commands when defined. | ||
* | ||
* @param {Array} argv | ||
* @return {Command} for chaining | ||
* @api public | ||
*/ | ||
Command.prototype.parse = function(argv){ | ||
// implicit help | ||
if (this.executables) this.addImplicitHelpCommand(); | ||
// store raw args | ||
this.rawArgs = argv; | ||
// guess name | ||
this._name = this._name || basename(argv[1], '.js'); | ||
// process argv | ||
var parsed = this.parseOptions(this.normalize(argv.slice(2))); | ||
var args = this.args = parsed.args; | ||
var result = this.parseArgs(this.args, parsed.unknown); | ||
// executable sub-commands | ||
var name = result.args[0]; | ||
if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); | ||
return result; | ||
}; | ||
/** | ||
* Execute a sub-command executable. | ||
* | ||
* @param {Array} argv | ||
* @param {Array} args | ||
* @param {Array} unknown | ||
* @api private | ||
*/ | ||
Command.prototype.executeSubCommand = function(argv, args, unknown) { | ||
args = args.concat(unknown); | ||
if (!args.length) this.help(); | ||
if ('help' == args[0] && 1 == args.length) this.help(); | ||
// <cmd> --help | ||
if ('help' == args[0]) { | ||
args[0] = args[1]; | ||
args[1] = '--help'; | ||
} | ||
// executable | ||
var dir = dirname(argv[1]); | ||
var bin = basename(argv[1], '.js') + '-' + args[0]; | ||
// check for ./<bin> first | ||
var local = path.join(dir, bin); | ||
// run it | ||
args = args.slice(1); | ||
args.unshift(local); | ||
var proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] }); | ||
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); | ||
} | ||
}); | ||
this.runningCommand = proc; | ||
}; | ||
/** | ||
* Normalize `args`, splitting joined short flags. For example | ||
* the arg "-abc" is equivalent to "-a -b -c". | ||
* This also normalizes equal sign and splits "--abc=def" into "--abc def". | ||
* | ||
* @param {Array} args | ||
* @return {Array} | ||
* @api private | ||
*/ | ||
Command.prototype.normalize = function(args){ | ||
var ret = [] | ||
, arg | ||
, lastOpt | ||
, index; | ||
for (var i = 0, len = args.length; i < len; ++i) { | ||
arg = args[i]; | ||
i > 0 && (lastOpt = this.optionFor(args[i-1])); | ||
if (lastOpt && lastOpt.required) { | ||
ret.push(arg); | ||
} else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { | ||
arg.slice(1).split('').forEach(function(c){ | ||
ret.push('-' + c); | ||
}); | ||
} else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { | ||
ret.push(arg.slice(0, index), arg.slice(index + 1)); | ||
} else { | ||
ret.push(arg); | ||
} | ||
} | ||
return ret; | ||
}; | ||
/** | ||
* Parse command `args`. | ||
* | ||
* When listener(s) are available those | ||
* callbacks are invoked, otherwise the "*" | ||
* event is emitted and those actions are invoked. | ||
* | ||
* @param {Array} args | ||
* @return {Command} for chaining | ||
* @api private | ||
*/ | ||
Command.prototype.parseArgs = function(args, unknown){ | ||
var cmds = this.commands | ||
, len = cmds.length | ||
, name; | ||
if (args.length) { | ||
name = args[0]; | ||
if (this.listeners(name).length) { | ||
this.emit(args.shift(), args, unknown); | ||
} else { | ||
this.emit('*', args); | ||
} | ||
} 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) { | ||
this.unknownOption(unknown[0]); | ||
} | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Return an option matching `arg` if any. | ||
* | ||
* @param {String} arg | ||
* @return {Option} | ||
* @api private | ||
*/ | ||
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]; | ||
} | ||
} | ||
}; | ||
/** | ||
* Parse options from `argv` returning `argv` | ||
* void of these options. | ||
* | ||
* @param {Array} argv | ||
* @return {Array} | ||
* @api public | ||
*/ | ||
Command.prototype.parseOptions = function(argv){ | ||
var args = [] | ||
, len = argv.length | ||
, literal | ||
, option | ||
, arg; | ||
var unknownOptions = []; | ||
// parse options | ||
for (var i = 0; i < len; ++i) { | ||
arg = argv[i]; | ||
// literal args after -- | ||
if ('--' == arg) { | ||
literal = true; | ||
continue; | ||
} | ||
if (literal) { | ||
args.push(arg); | ||
continue; | ||
} | ||
// find matching Option | ||
option = this.optionFor(arg); | ||
// option is defined | ||
if (option) { | ||
// requires arg | ||
if (option.required) { | ||
arg = argv[++i]; | ||
if (null == arg) return this.optionMissingArgument(option); | ||
this.emit(option.name(), arg); | ||
// optional arg | ||
} else if (option.optional) { | ||
arg = argv[i+1]; | ||
if (null == arg || ('-' == arg[0] && '-' != arg)) { | ||
arg = null; | ||
} else { | ||
++i; | ||
} | ||
this.emit(option.name(), arg); | ||
// bool | ||
} else { | ||
this.emit(option.name()); | ||
} | ||
continue; | ||
} | ||
// looks like an option | ||
if (arg.length > 1 && '-' == arg[0]) { | ||
unknownOptions.push(arg); | ||
// 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]) { | ||
unknownOptions.push(argv[++i]); | ||
} | ||
continue; | ||
} | ||
// arg | ||
args.push(arg); | ||
} | ||
return { args: args, unknown: unknownOptions }; | ||
}; | ||
/** | ||
* Argument `name` is missing. | ||
* | ||
* @param {String} name | ||
* @api private | ||
*/ | ||
Command.prototype.missingArgument = function(name){ | ||
console.error(); | ||
console.error(" error: missing required argument `%s'", name); | ||
console.error(); | ||
process.exit(1); | ||
}; | ||
/** | ||
* `Option` is missing an argument, but received `flag` or nothing. | ||
* | ||
* @param {String} option | ||
* @param {String} flag | ||
* @api private | ||
*/ | ||
Command.prototype.optionMissingArgument = function(option, flag){ | ||
console.error(); | ||
if (flag) { | ||
console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); | ||
} else { | ||
console.error(" error: option `%s' argument missing", option.flags); | ||
} | ||
console.error(); | ||
process.exit(1); | ||
}; | ||
/** | ||
* Unknown option `flag`. | ||
* | ||
* @param {String} flag | ||
* @api private | ||
*/ | ||
Command.prototype.unknownOption = function(flag){ | ||
console.error(); | ||
console.error(" error: unknown option `%s'", flag); | ||
console.error(); | ||
process.exit(1); | ||
}; | ||
/** | ||
* Set the program version to `str`. | ||
* | ||
* This method auto-registers the "-V, --version" flag | ||
* which will print the version number when passed. | ||
* | ||
* @param {String} str | ||
* @param {String} flags | ||
* @return {Command} for chaining | ||
* @api public | ||
*/ | ||
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); | ||
process.exit(0); | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Set the description `str`. | ||
* | ||
* @param {String} str | ||
* @return {String|Command} | ||
* @api public | ||
*/ | ||
Command.prototype.description = function(str){ | ||
if (0 == arguments.length) return this._description; | ||
this._description = str; | ||
return this; | ||
}; | ||
/** | ||
* Set / get the command usage `str`. | ||
* | ||
* @param {String} str | ||
* @return {String|Command} | ||
* @api public | ||
*/ | ||
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; | ||
}; | ||
/** | ||
* Return the largest option length. | ||
* | ||
* @return {Number} | ||
* @api private | ||
*/ | ||
Command.prototype.largestOptionLength = function(){ | ||
return this.options.reduce(function(max, option){ | ||
return Math.max(max, option.flags.length); | ||
}, 0); | ||
}; | ||
/** | ||
* Return help for options. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
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; | ||
})) | ||
.join('\n'); | ||
}; | ||
/** | ||
* Return command help documentation. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
Command.prototype.commandHelp = function(){ | ||
if (!this.commands.length) return ''; | ||
return [ | ||
'' | ||
, ' Commands:' | ||
, '' | ||
, this.commands.map(function(cmd){ | ||
var args = cmd._args.map(function(arg){ | ||
return arg.required | ||
? '<' + arg.name + '>' | ||
: '[' + arg.name + ']'; | ||
}).join(' '); | ||
return pad(cmd._name | ||
+ (cmd.options.length | ||
? ' [options]' | ||
: '') + ' ' + args, 22) | ||
+ (cmd.description() | ||
? ' ' + cmd.description() | ||
: ''); | ||
}).join('\n').replace(/^/gm, ' ') | ||
, '' | ||
].join('\n'); | ||
}; | ||
/** | ||
* Return program help documentation. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
Command.prototype.helpInformation = function(){ | ||
return [ | ||
'' | ||
, ' Usage: ' + this._name + ' ' + this.usage() | ||
, '' + this.commandHelp() | ||
, ' Options:' | ||
, '' | ||
, '' + this.optionHelp().replace(/^/gm, ' ') | ||
, '' | ||
, '' | ||
].join('\n'); | ||
}; | ||
/** | ||
* Output help information for this command | ||
* | ||
* @api public | ||
*/ | ||
Command.prototype.outputHelp = function(){ | ||
process.stdout.write(this.helpInformation()); | ||
this.emit('--help'); | ||
}; | ||
/** | ||
* Output help information and exit. | ||
* | ||
* @api public | ||
*/ | ||
Command.prototype.help = function(){ | ||
this.outputHelp(); | ||
process.exit(); | ||
}; | ||
/** | ||
* Camel-case the given `flag` | ||
* | ||
* @param {String} flag | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function camelcase(flag) { | ||
return flag.split('-').reduce(function(str, word){ | ||
return str + word[0].toUpperCase() + word.slice(1); | ||
}); | ||
} | ||
/** | ||
* Pad `str` to `width`. | ||
* | ||
* @param {String} str | ||
* @param {Number} width | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function pad(str, width) { | ||
var len = Math.max(0, width - str.length); | ||
return str + Array(len + 1).join(' '); | ||
} | ||
/** | ||
* 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 | ||
*/ | ||
function outputHelpIfNecessary(cmd, options) { | ||
options = options || []; | ||
for (var i = 0; i < options.length; i++) { | ||
if (options[i] == '--help' || options[i] == '-h') { | ||
cmd.outputHelp(); | ||
process.exit(0); | ||
} | ||
} | ||
} |
{ | ||
"name": "ltcdr" | ||
, "version": "2.1.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/calvinmetcalf/ltcdr.git" } | ||
, "devDependencies": { "should": ">= 0.0.1" } | ||
, "scripts": { "test": "make test" } | ||
, "main": "index" | ||
, "engines": { "node": ">= 0.6.x" } | ||
, "files": ["index.js"] | ||
"name": "ltcdr", | ||
"version": "2.2.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/calvinmetcalf/ltcdr.git" | ||
}, | ||
"devDependencies": { | ||
"tape": "^2.10.2", | ||
"tap-spec": "^0.1.5" | ||
}, | ||
"scripts": { | ||
"test": "tape test/test.*.js | tspec" | ||
}, | ||
"main": "index", | ||
"engines": { | ||
"node": ">= 0.6.x" | ||
}, | ||
"files": [ | ||
"index.js" | ||
] | ||
} |
# Lieutenant Commander | ||
The complete solution for [node.js](http://nodejs.org) command-line interfaces, a for commander [commander](https://github.com/visionmedia/commander-js). | ||
The complete solution for [node.js](http://nodejs.org) command-line interfaces, a fork of [commander](https://github.com/visionmedia/commander.js). | ||
## Installation | ||
$ npm install ltcdr | ||
``` | ||
$ npm install ltcdr | ||
``` | ||
## Commands & Actions | ||
```js | ||
#!/usr/bin/env node | ||
program | ||
.command('initialize [env]') | ||
.alias('init') | ||
.alias('i') | ||
.description('initializes a deploy config for the given environment') | ||
.option('-b, --branch [name]', 'Which branch to use') | ||
.action(function(env, options) { | ||
var branch = options.branch || 'master'; | ||
env = env || 'prod'; | ||
console.log('initialized %s environment for %s branch', env, branch); | ||
}) | ||
.parse(process.argv); | ||
// deployer initialize alpha | ||
// deployer init beta | ||
// deployer i prod | ||
``` | ||
Aliases are optional, and can take a string or an array, e.g. `.aliases('s')` or `.aliases(['s', 'sup'])`. | ||
## Option parsing | ||
@@ -10,0 +40,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
224
0
7049
2
14