diff --git a/CHANGES.md b/CHANGES.md index b85a219..4018e3d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,9 +5,31 @@ Known issues: - `triton ssh ...` disables ssh ControlMaster to avoid issue #52. -## 4.12.1 (not yet released) +## 4.13.0 (not yet released) -(nothing yet) +- [#113] *Usage* errors now some "error help", including option or command + synopses. Some examples (the new thing is marked with `>`): + + - Command synopses when argument errors: + + $ triton create + triton instance create: error (Usage): incorrect number of args + > usage: triton instance create [OPTIONS] IMAGE PACKAGE + + - Option synopsis with option errors: + + $ triton image ls --bogus + triton image ls: error (Option): unknown option: "--bogus" + > usage: triton image ls [ --help | -h ] [ --all | -a ] [ -H ] [ -o field1,... ] + > [ --long | -l ] [ -s field1,... ] [ --json | -j ] ... + + - Suggested command name misspellings: + + $ triton in + triton: error (UnknownCommand): unknown command: "in" + > Did you mean this? + > info + > inst ## 4.12.0 diff --git a/lib/cli.js b/lib/cli.js index d5533b8..2dcf50a 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -342,7 +342,7 @@ CLI.prototype.fini = function fini(subcmd, err, cb) { this._tritonapi.close(); delete this._tritonapi; } - cb(err, subcmd); + cb(); }; @@ -667,7 +667,7 @@ function main(argv) { } var cli = new CLI(); - cli.main(argv, function (err, subcmd) { + cli.main(argv, function (err) { var exitStatus = (err ? err.exitStatus || 1 : 0); var showErr = (cli.showErr !== undefined ? cli.showErr : true); @@ -677,7 +677,7 @@ function main(argv) { /* jsl:pass */ } else if (err.message !== undefined) { /* - * If the err has `body.errors` (as some Triton/SDC APIs do per + * If the err has `body.errors`, as some Triton/SDC APIs do per * // JSSTYLED * https://github.com/joyent/eng/blob/master/docs/index.md#error-handling * then append a one-line summary for each error object. @@ -692,27 +692,14 @@ function main(argv) { }); } - console.error('%s%s: error%s: %s%s', - cli.name, - (subcmd ? ' ' + subcmd : ''), + console.error('%s: error%s: %s%s', + cmdln.nameFromErr(err), (code ? format(' (%s)', code) : ''), (cli.showErrStack ? err.stack : err.message), bodyErrors); - - // If this is a usage error, attempt to show some usage info. - if (['Usage', 'Option'].indexOf(code) !== -1 && subcmd) { - var help = cli.helpFromSubcmd(subcmd); - if (help && typeof (help) === 'string') { - // Would like a shorter synopsis. Attempt to - // parse it down, somewhat generally. Unfortunately this - // doesn't work for multi-level subcmds, like - // `triton rbac subcmd ...`. - var usageIdx = help.indexOf('\nUsage:'); - if (usageIdx !== -1) { - help = help.slice(usageIdx); - } - console.error(help); - } + var errHelp = cmdln.errHelpFromErr(err); + if (errHelp) { + console.error(errHelp); } } } @@ -728,6 +715,7 @@ function main(argv) { }); } + //---- exports module.exports = { diff --git a/lib/common.js b/lib/common.js index 54a53fc..ba192cd 100644 --- a/lib/common.js +++ b/lib/common.js @@ -129,6 +129,8 @@ function jsonStream(arr, stream) { * * @param {Array} kvs - an array of key=value pairs * @param {Array} valid (optional) - an array to validate pairs + * + * TODO: merge this with objFromKeyValueArgs ! */ function kvToObj(kvs, valid) { assert.arrayOfString(kvs, 'kvs'); diff --git a/lib/do_account/do_get.js b/lib/do_account/do_get.js index d9079d5..5901db1 100644 --- a/lib/do_account/do_get.js +++ b/lib/do_account/do_get.js @@ -58,13 +58,15 @@ do_get.options = [ help: 'JSON output.' } ]; -do_get.help = ( - 'Show account information\n' - + '\n' - + 'Usage:\n' - + ' {{name}} get\n' - + '\n' - + '{{options}}' -); + +do_get.synopses = ['{{name}} {{cmd}}']; + +do_get.help = [ + 'Show account information', + '', + '{{usage}}', + '', + '{{options}}' +].join('\n'); module.exports = do_get; diff --git a/lib/do_account/do_update.js b/lib/do_account/do_update.js index ea0c0c4..fa0f62f 100644 --- a/lib/do_account/do_update.js +++ b/lib/do_account/do_update.js @@ -148,13 +148,17 @@ do_update.options = [ 'JSON from stdin.' } ]; + +do_update.synopses = [ + '{{name}} {{cmd}} [FIELD=VALUE ...]', + '{{name}} {{cmd}} -f JSON-FILE' +]; + do_update.help = [ /* BEGIN JSSTYLED */ 'Update account information', '', - 'Usage:', - ' {{name}} update [FIELD=VALUE ...]', - ' {{name}} update -f JSON-FILE', + '{{usage}}', '', '{{options}}', diff --git a/lib/do_cloudapi.js b/lib/do_cloudapi.js index 7f21c4c..e0ed906 100644 --- a/lib/do_cloudapi.js +++ b/lib/do_cloudapi.js @@ -57,7 +57,7 @@ function do_cloudapi(subcmd, opts, args, callback) { reqOpts.data = JSON.parse(opts.data); } catch (parseErr) { callback(new errors.TritonError(parseErr, - 'given is not valid JSON: ' + parseErr.message)); + 'given DATA is not valid JSON: ' + parseErr.message)); return; } } @@ -94,13 +94,13 @@ do_cloudapi.options = [ { names: ['method', 'X'], type: 'string', - helpArg: '', + helpArg: 'METHOD', help: 'Request method to use. Default is "GET".' }, { names: ['header', 'H'], type: 'arrayOfString', - helpArg: '
', + helpArg: 'HEADER', help: 'Headers to send with request.' }, { @@ -111,19 +111,25 @@ do_cloudapi.options = [ { names: ['data', 'd'], type: 'string', - helpArg: '', + helpArg: 'DATA', help: 'Add POST data. This must be valid JSON.' } ]; -do_cloudapi.help = ( - 'Raw cloudapi request.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} cloudapi [-X ] [-H ] \\\n' - + ' [-d ] \n' - + '\n' - + '{{options}}' -); + +do_cloudapi.synopses = [ + '{{name}} {{cmd}} [-X METHOD] [-H HEADER=VAL] [-d DATA] ENDPOINT' +]; + +do_cloudapi.help = [ + 'Raw cloudapi request.', + '', + '{{usage}}', + '', + '{{options}}', + 'Examples:', + ' {{name}} {{cmd}} /--ping', + ' {{name}} {{cmd}} /my/machines' +].join('\n'); do_cloudapi.hidden = true; diff --git a/lib/do_datacenters.js b/lib/do_datacenters.js index 310957d..afb45b2 100644 --- a/lib/do_datacenters.js +++ b/lib/do_datacenters.js @@ -75,15 +75,16 @@ do_datacenters.options = [ sortDefault: sortDefault })); -do_datacenters.help = ( - 'Show datacenters in this cloud.\n' - + 'A "cloud" is a set of related datacenters that share account\n' - + 'information.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} datacenters\n' - + '\n' - + '{{options}}' -); +do_datacenters.synopses = ['{{name}} {{cmd}}']; + +do_datacenters.help = [ + 'Show datacenters in this cloud.', + 'A "cloud" is a set of related datacenters that share account', + 'information.', + '', + '{{usage}}', + '', + '{{options}}' +].join('\n'); module.exports = do_datacenters; diff --git a/lib/do_env.js b/lib/do_env.js index 4a44646..9653879 100644 --- a/lib/do_env.js +++ b/lib/do_env.js @@ -198,7 +198,8 @@ do_env.options = [ } ]; -// TODO: support env for docker usage. +do_env.synopses = ['{{name}} {{cmd}} [PROFILE]']; + do_env.help = [ /* BEGIN JSSTYLED */ 'Emit shell commands to setup environment.', @@ -207,8 +208,7 @@ do_env.help = [ 'and node-triton itself. By default this emits the environment for all', 'supported tools. Use options to be specific.', '', - 'Usage:', - ' {{name}} env [PROFILE]', + '{{usage}}', '', '{{options}}', 'If no options are given, environment variables are emitted for all clients.', diff --git a/lib/do_fwrule/do_create.js b/lib/do_fwrule/do_create.js index cc24858..d1ec831 100644 --- a/lib/do_fwrule/do_create.js +++ b/lib/do_fwrule/do_create.js @@ -28,7 +28,7 @@ function do_create(subcmd, opts, args, cb) { return; } if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing FWRULE argument')); return; } else if (args.length > 1) { cb(new errors.UsageError('incorrect number of arguments')); @@ -79,17 +79,31 @@ do_create.options = [ { names: ['description', 'D'], type: 'string', - helpArg: '', + helpArg: 'DESC', help: 'Description of the firewall rule.' } ]; + +do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] RULE-TEXT']; + do_create.help = [ + /* BEGIN JSSTYLED */ 'Create a firewall rule.', '', - 'Usage:', - ' {{name}} create [] ', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Examples:', + ' # Allow SSH access from any IP to all instances in a datacenter.', + ' triton fwrule create -D "ssh" "FROM any TO all vms ALLOW tcp PORT 22"', + '', + ' # Allow SSH access to a specific instance.', + ' triton fwrule create \\', + ' "FROM any TO vm ba2c95e9-1cdf-4295-8253-3fee371374d9 ALLOW tcp PORT 22"' + // TODO: link to + // https://github.com/joyent/sdc-fwrule/blob/master/docs/examples.md + // or docs.jo Cloud Firewall examples? What link? Ditto in parent. + /* END JSSTYLED */ ].join('\n'); do_create.helpOpts = { diff --git a/lib/do_fwrule/do_delete.js b/lib/do_fwrule/do_delete.js index 62f1a89..b4369d8 100644 --- a/lib/do_fwrule/do_delete.js +++ b/lib/do_fwrule/do_delete.js @@ -27,7 +27,7 @@ function do_delete(subcmd, opts, args, cb) { } if (args.length < 1) { - cb(new errors.UsageError('missing argument(s)')); + cb(new errors.UsageError('missing FWRULE argument(s)')); return; } @@ -96,13 +96,16 @@ do_delete.options = [ help: 'Skip confirmation of delete.' } ]; + +do_delete.synopses = ['{{name}} {{cmd}} FWRULE [FWRULE ...]']; + do_delete.help = [ 'Remove a firewall rule.', '', - 'Usage:', - ' {{name}} delete [] [...]', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where FWRULE is a firewall rule id (full UUID) or short id.' ].join('\n'); do_delete.aliases = ['rm']; diff --git a/lib/do_fwrule/do_disable.js b/lib/do_fwrule/do_disable.js index 0be5104..7ea887b 100644 --- a/lib/do_fwrule/do_disable.js +++ b/lib/do_fwrule/do_disable.js @@ -26,7 +26,7 @@ function do_disable(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('Missing argument(s)')); + cb(new errors.UsageError('missing FWRULE argument(s)')); return; } @@ -56,13 +56,16 @@ do_disable.options = [ help: 'Show this help.' } ]; + +do_disable.synopses = ['{{name}} {{cmd}} FWRULE [FWRULE ...]']; + do_disable.help = [ 'Disable a specific firewall rule.', '', - 'Usage:', - ' {{name}} disable [...]', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where FWRULE is a firewall rule id (full UUID) or short id.' ].join('\n'); do_disable.completionArgtypes = ['tritonfwrule']; diff --git a/lib/do_fwrule/do_enable.js b/lib/do_fwrule/do_enable.js index 32ae1ef..4f22747 100644 --- a/lib/do_fwrule/do_enable.js +++ b/lib/do_fwrule/do_enable.js @@ -26,7 +26,7 @@ function do_enable(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('Missing argument(s)')); + cb(new errors.UsageError('missing FWRULE argument(s)')); return; } @@ -56,13 +56,16 @@ do_enable.options = [ help: 'Show this help.' } ]; + +do_enable.synopses = ['{{name}} {{cmd}} FWRULE [FWRULE ...]']; + do_enable.help = [ 'Enable a specific firewall rule.', '', - 'Usage:', - ' {{name}} enable [...]', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where FWRULE is a firewall rule id (full UUID) or short id.' ].join('\n'); do_enable.completionArgtypes = ['tritonfwrule']; diff --git a/lib/do_fwrule/do_get.js b/lib/do_fwrule/do_get.js index 88244bd..b919036 100644 --- a/lib/do_fwrule/do_get.js +++ b/lib/do_fwrule/do_get.js @@ -25,7 +25,7 @@ function do_get(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing FWRULE argument')); return; } else if (args.length > 1) { cb(new errors.UsageError('incorrect number of arguments')); @@ -64,13 +64,16 @@ do_get.options = [ help: 'JSON stream output.' } ]; + +do_get.synopses = ['{{name}} {{cmd}} FWRULE']; + do_get.help = [ 'Show a specific firewall rule.', '', - 'Usage:', - ' {{name}} get ', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where FWRULE is a firewall rule id (full UUID) or short id.' ].join('\n'); do_get.completionArgtypes = ['tritonfwrule', 'none']; diff --git a/lib/do_fwrule/do_instances.js b/lib/do_fwrule/do_instances.js index 2931a09..34911a0 100644 --- a/lib/do_fwrule/do_instances.js +++ b/lib/do_fwrule/do_instances.js @@ -30,7 +30,7 @@ function do_instances(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing FWRULE argument')); return; } else if (args.length > 1) { cb(new errors.UsageError('incorrect number of arguments')); @@ -135,14 +135,16 @@ do_instances.options = [ sortDefault: SORT_DEFAULT })); +do_instances.synopses = ['{{name}} {{cmd}} [OPTIONS] FWRULE']; + do_instances.help = [ /* BEGIN JSSTYLED */ - 'List instances a firewall rule is applied to.', + 'List instances to which a firewall rule applies', '', - 'Usage:', - ' {{name}} instances [] ', + '{{usage}}', '', '{{options}}', + 'Where FWRULE is a firewall rule id (full UUID) or short id.', '', 'Fields (most are self explanatory, "*" indicates a field added client-side', 'for convenience):', diff --git a/lib/do_fwrule/do_list.js b/lib/do_fwrule/do_list.js index daec3e4..108d4f0 100644 --- a/lib/do_fwrule/do_list.js +++ b/lib/do_fwrule/do_list.js @@ -84,11 +84,12 @@ do_list.options = [ sortDefault: SORT_DEFAULT })); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS]']; + do_list.help = [ 'Show all firewall rules.', '', - 'Usage:', - ' {{name}} list []', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_fwrule/do_update.js b/lib/do_fwrule/do_update.js index e9c62e0..8238c61 100644 --- a/lib/do_fwrule/do_update.js +++ b/lib/do_fwrule/do_update.js @@ -31,7 +31,7 @@ function do_update(subcmd, opts, args, cb) { var tritonapi = this.top.tritonapi; if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing FWRULE argument')); return; } @@ -164,17 +164,20 @@ do_update.options = [ { names: ['file', 'f'], type: 'string', - helpArg: '', + helpArg: 'JSON-FILE', help: 'A file holding a JSON file of updates, or "-" to read ' + 'JSON from stdin.' } ]; + +do_update.synopses = [ + '{{name}} {{cmd}} FWRULE [FIELD=VALUE ...]', + '{{name}} {{cmd}} -f JSON-FILE FWRULE' +]; do_update.help = [ 'Update a firewall rule', '', - 'Usage:', - ' {{name}} update [FIELD=VALUE ...]', - ' {{name}} update -f ', + '{{usage}}', '', '{{options}}', @@ -182,7 +185,8 @@ do_update.help = [ ' ' + Object.keys(UPDATE_FWRULE_FIELDS).sort().map(function (f) { return f + ' (' + UPDATE_FWRULE_FIELDS[f] + ')'; }).join('\n '), - '' + '', + 'Where FWRULE is a firewall rule id (full UUID) or short id.' ].join('\n'); do_update.completionArgtypes = ['tritonfwrule', 'tritonupdatefwrulefield']; diff --git a/lib/do_image/do_create.js b/lib/do_image/do_create.js index e859857..c63634c 100644 --- a/lib/do_image/do_create.js +++ b/lib/do_image/do_create.js @@ -250,16 +250,20 @@ do_create.options = [ } ]; -do_create.help = ( +do_create.synopses = [ + '{{name}} {{cmd}} [OPTIONS] INST IMAGE-NAME IMAGE-VERSION' +]; + +do_create.help = [ /* BEGIN JSSTYLED */ - 'Create a new instance.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} create [] INSTANCE IMAGE-NAME IMAGE-VERSION\n' + - '\n' + - '{{options}}' + 'Create a new instance.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' /* END JSSTYLED */ -); +].join('\n'); do_create.helpOpts = { maxHelpCol: 20 diff --git a/lib/do_image/do_delete.js b/lib/do_image/do_delete.js index 2a7e72b..a11501b 100644 --- a/lib/do_image/do_delete.js +++ b/lib/do_image/do_delete.js @@ -125,19 +125,21 @@ function do_delete(subcmd, opts, args, cb) { }); } +do_delete.synopses = ['{{name}} {{cmd}} [OPTIONS] IMAGE [IMAGE ...]']; + do_delete.help = [ /* BEGIN JSSTYLED */ 'Delete one or more images.', '', - 'Usage:', - ' {{name}} delete IMAGE [IMAGE...]', + '{{usage}}', '', '{{options}}', - 'Where "IMAGE" is an image ID (a full UUID), an image name (selects the', + 'Where "IMAGE" is an image id (a full UUID), an image name (selects the', 'latest, by "published_at", image with that name), an image "name@version"', '(selects latest match by "published_at"), or an image short ID (ID prefix).' /* END JSSTYLED */ ].join('\n'); + do_delete.options = [ { names: ['help', 'h'], diff --git a/lib/do_image/do_get.js b/lib/do_image/do_get.js index 1eca39e..4e22268 100644 --- a/lib/do_image/do_get.js +++ b/lib/do_image/do_get.js @@ -50,22 +50,24 @@ do_get.options = [ help: 'JSON stream output.' } ]; -do_get.help = ( + +do_get.synopses = ['{{name}} {{cmd}} [OPTIONS] IMAGE']; + +do_get.help = [ /* BEGIN JSSTYLED */ - 'Get an image.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} get [] ID|NAME\n' + - '\n' + - '{{options}}' + - '\n' + - 'If there is more than one image with the given "NAME", the latest\n' + - 'image (by "published_at") is returned.\n' + - '\n' + - 'Note: Currently this dumps prettified JSON by default. That might change\n' + - 'in the future. Use "-j" to explicitly get JSON output.\n' + 'Get an image.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where "IMAGE" is an image id (a full UUID), an image name (selects the', + 'latest, by "published_at", image with that name), an image "name@version"', + '(selects latest match by "published_at"), or an image short ID (ID prefix).', + '', + 'Note: Currently this dumps prettified JSON by default. That might change', + 'in the future. Use "-j" to explicitly get JSON output.' /* END JSSTYLED */ -); +].join('\n'); do_get.completionArgtypes = ['tritonimage', 'none']; diff --git a/lib/do_image/do_list.js b/lib/do_image/do_list.js index 0889d3f..d9b917c 100644 --- a/lib/do_image/do_list.js +++ b/lib/do_image/do_list.js @@ -122,6 +122,8 @@ do_list.options = [ sortDefault: sortDefault })); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS] [FILTERS]']; + do_list.help = [ /* BEGIN JSSTYLED */ 'List images.', @@ -130,8 +132,7 @@ do_list.help = [ 'You must use `docker images` against the Docker service for this data center.', 'See .', '', - 'Usage:', - ' {{name}} list [] []', + '{{usage}}', '', '{{options}}', 'Filters:', diff --git a/lib/do_image/do_wait.js b/lib/do_image/do_wait.js index f7cec9f..c887cec 100644 --- a/lib/do_image/do_wait.js +++ b/lib/do_image/do_wait.js @@ -112,11 +112,12 @@ function do_wait(subcmd, opts, args, cb) { }); } +do_wait.synopses = ['{{name}} {{cmd}} [-s STATES] IMAGE [IMAGE ...]']; + do_wait.help = [ 'Wait for images to change to a particular state.', '', - 'Usage:', - ' {{name}} wait [-s STATES] IMAGE [IMAGE ...]', + '{{usage}}', '', '{{options}}', 'Where "states" is a comma-separated list of target instance states,', diff --git a/lib/do_info.js b/lib/do_info.js index c67d9e4..af0f94c 100644 --- a/lib/do_info.js +++ b/lib/do_info.js @@ -105,13 +105,15 @@ do_info.options = [ help: 'JSON output.' } ]; -do_info.help = ( - 'Print an account summary.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} info\n' - + '\n' - + '{{options}}' -); + +do_info.synopses = ['{{name}} {{cmd}}']; + +do_info.help = [ + 'Print an account summary.', + '', + '{{usage}}', + '', + '{{options}}' +].join('\n'); module.exports = do_info; diff --git a/lib/do_instance/do_audit.js b/lib/do_instance/do_audit.js index 04e8496..82b09f8 100644 --- a/lib/do_instance/do_audit.js +++ b/lib/do_instance/do_audit.js @@ -28,13 +28,15 @@ var sortDefault = 'id,time'; function do_audit(subcmd, opts, args, cb) { var self = this; - if (opts.help) { this.do_help('help', {}, [subcmd], cb); return; - } else if (args.length !== 1) { - //XXX Support multiple machines. - return cb(new Error('incorrect args: ' + args)); + } else if (args.length === 0) { + cb(new errors.UsageError('missing INST argument')); + return; + } else if (args.length > 1) { + cb(new errors.UsageError('too many arguments: ' + args)); + return; } var columns = columnsDefault; @@ -102,14 +104,15 @@ do_audit.options = [ sortDefault: sortDefault })); -do_audit.help = ( - 'List instance actions.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} audit \n' - + '\n' - + '{{options}}' -); +do_audit.synopses = ['{{name}} {{cmd}} [OPTIONS] INST']; +do_audit.help = [ + 'List instance actions.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' +].join('\n'); do_audit.completionArgtypes = ['tritoninstance', 'none']; diff --git a/lib/do_instance/do_create.js b/lib/do_instance/do_create.js index 7bc6867..0562dc1 100644 --- a/lib/do_instance/do_create.js +++ b/lib/do_instance/do_create.js @@ -498,16 +498,20 @@ do_create.options = [ } ]; -do_create.help = ( +do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] IMAGE PACKAGE']; + +do_create.help = [ /* BEGIN JSSTYLED */ - 'Create a new instance.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} create [] IMAGE PACKAGE\n' + - '\n' + - '{{options}}' + 'Create a new instance.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where IMAGE is an image name, name@version, id, or short id (from ', + '`triton image list`) and PACKAGE is a package name, id, or short id', + '(from `triton package list`).' /* END JSSTYLED */ -); +].join('\n'); do_create.helpOpts = { maxHelpCol: 16 diff --git a/lib/do_instance/do_disable_firewall.js b/lib/do_instance/do_disable_firewall.js index 9cf7d8b..370c542 100644 --- a/lib/do_instance/do_disable_firewall.js +++ b/lib/do_instance/do_disable_firewall.js @@ -26,7 +26,7 @@ function do_disable_firewall(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('Missing argument(s)')); + cb(new errors.UsageError('missing INST argument(s)')); return; } @@ -88,13 +88,16 @@ do_disable_firewall.options = [ help: 'Wait for the firewall to be disabled.' } ]; +do_disable_firewall.synopses = [ + '{{name}} disable-firewall [OPTIONS] INST [INST ...]' +]; do_disable_firewall.help = [ 'Disable the firewall of one or more instances.', '', - 'Usage:', - ' {{name}} disable-firewall [] [...]', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' ].join('\n'); do_disable_firewall.completionArgtypes = ['tritoninstance']; diff --git a/lib/do_instance/do_enable_firewall.js b/lib/do_instance/do_enable_firewall.js index 2d64025..ea15610 100644 --- a/lib/do_instance/do_enable_firewall.js +++ b/lib/do_instance/do_enable_firewall.js @@ -26,7 +26,7 @@ function do_enable_firewall(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('Missing argument(s)')); + cb(new errors.UsageError('missing INST argument(s)')); return; } @@ -88,13 +88,16 @@ do_enable_firewall.options = [ help: 'Wait for the firewall to be enabled.' } ]; +do_enable_firewall.synopses = [ + '{{name}} enable-firewall [OPTIONS] INST [INST ...]' +]; do_enable_firewall.help = [ 'Enable the firewall of one or more instances.', '', - 'Usage:', - ' {{name}} enable-firewall [] [...]', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' ].join('\n'); do_enable_firewall.completionArgtypes = ['tritoninstance']; diff --git a/lib/do_instance/do_fwrules.js b/lib/do_instance/do_fwrules.js index 32da3c7..bf06fad 100644 --- a/lib/do_instance/do_fwrules.js +++ b/lib/do_instance/do_fwrules.js @@ -31,10 +31,10 @@ function do_fwrules(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing INST argument')); return; } else if (args.length > 1) { - cb(new errors.UsageError('incorrect number of arguments')); + cb(new errors.UsageError('too many arguments: ' + args.join(' '))); return; } @@ -91,13 +91,15 @@ do_fwrules.options = [ sortDefault: SORT_DEFAULT })); +do_fwrules.synopses = ['{{name}} {{cmd}} [OPTIONS] INST']; + do_fwrules.help = [ 'Show firewall rules applied to an instance.', '', - 'Usage:', - ' {{name}} fwrules [] ', + '{{usage}}', '', - '{{options}}' + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' ].join('\n'); do_fwrules.completionArgtypes = ['tritoninstance', 'none']; diff --git a/lib/do_instance/do_get.js b/lib/do_instance/do_get.js index 05dd084..18afe2d 100644 --- a/lib/do_instance/do_get.js +++ b/lib/do_instance/do_get.js @@ -43,22 +43,24 @@ do_get.options = [ help: 'JSON output.' } ]; -do_get.help = ( +do_get.synopses = ['{{name}} {{cmd}} [OPTIONS] INST']; +do_get.help = [ /* BEGIN JSSTYLED */ - 'Get an instance.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} get \n' - + '\n' - + '{{options}}' - + '\n' - + 'A *deleted* instance may still respond with the instance object. In that\n' - + 'case a the instance will be print *and* an error will be raised.\n' - + '\n' - + 'Currently this dumps prettified JSON by default. That might change\n' - + 'in the future. Use "-j" to explicitly get JSON output.\n' + 'Get an instance.', + '', + '{{usage}}', + '', + '{{options}}', + '', + 'Where "INST" is an instance name, id, or short id.', + '', + 'A *deleted* instance may still respond with the instance object. In that', + 'case a the instance will be print *and* an error will be raised.', + '', + 'Currently this dumps prettified JSON by default. That might change', + 'in the future. Use "-j" to explicitly get JSON output.' /* END JSSTYLED */ -); +].join('\n'); do_get.completionArgtypes = ['tritoninstance', 'none']; diff --git a/lib/do_instance/do_ip.js b/lib/do_instance/do_ip.js index ff6ee39..9dd5af7 100644 --- a/lib/do_instance/do_ip.js +++ b/lib/do_instance/do_ip.js @@ -20,10 +20,10 @@ function do_ip(subcmd, opts, args, cb) { this.do_help('help', {}, [subcmd], cb); return; } else if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing INST argument')); return; } else if (args.length > 1) { - cb(new errors.UsageError('too many arguments: ' + args)); + cb(new errors.UsageError('too many arguments: ' + args.join(' '))); return; } @@ -54,14 +54,16 @@ do_ip.options = [ } ]; +do_ip.synopses = ['{{name}} {{cmd}} INST']; + do_ip.help = [ /* BEGIN JSSTYLED */ - 'Print the primaryIp of the given instance.', + 'Print the primary IP of the given instance.', '', - 'Usage:', - ' {{name}} ip ', + '{{usage}}', '', '{{options}}', + 'Where "INST" is an instance name, id, or short id.', 'For example: ssh root@$(triton ip my-instance)' ].join('\n'); diff --git a/lib/do_instance/do_list.js b/lib/do_instance/do_list.js index 418162b..64dfe14 100644 --- a/lib/do_instance/do_list.js +++ b/lib/do_instance/do_list.js @@ -159,12 +159,13 @@ do_list.options = [ sortDefault: sortDefault })); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS] [FILTERS...]']; + do_list.help = [ /* BEGIN JSSTYLED */ 'List instances.', '', - 'Usage:', - ' {{name}} list [...]', + '{{usage}}', '', '{{options}}', 'Filters:', diff --git a/lib/do_instance/do_snapshot/do_create.js b/lib/do_instance/do_snapshot/do_create.js index 6c42f61..d8aa522 100644 --- a/lib/do_instance/do_snapshot/do_create.js +++ b/lib/do_instance/do_snapshot/do_create.js @@ -114,7 +114,7 @@ do_create.options = [ { names: ['name', 'n'], type: 'string', - helpArg: '', + helpArg: 'SNAPNAME', help: 'An optional name for a snapshot.' }, { @@ -123,11 +123,13 @@ do_create.options = [ help: 'Wait for the creation to complete.' } ]; + +do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] INST']; + do_create.help = [ 'Create a snapshot of an instance.', '', - 'Usage:', - ' {{name}} create [] ', + '{{usage}}', '', '{{options}}', 'Snapshot do not work for instances of type "kvm".' diff --git a/lib/do_instance/do_snapshot/do_delete.js b/lib/do_instance/do_snapshot/do_delete.js index 681f8a9..99d6c9b 100644 --- a/lib/do_instance/do_snapshot/do_delete.js +++ b/lib/do_instance/do_snapshot/do_delete.js @@ -27,7 +27,7 @@ function do_delete(subcmd, opts, args, cb) { } if (args.length < 2) { - cb(new errors.UsageError('missing and argument(s)')); + cb(new errors.UsageError('missing INST and SNAPNAME argument(s)')); return; } @@ -139,11 +139,13 @@ do_delete.options = [ help: 'Wait for the deletion to complete.' } ]; + +do_delete.synopses = ['{{name}} {{cmd}} [OPTIONS] INST SNAPNAME [SNAPNAME...]']; + do_delete.help = [ 'Remove a snapshot from an instance.', '', - 'Usage:', - ' {{name}} delete [] [...]', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_instance/do_snapshot/do_get.js b/lib/do_instance/do_snapshot/do_get.js index 79e442b..437a724 100644 --- a/lib/do_instance/do_snapshot/do_get.js +++ b/lib/do_instance/do_snapshot/do_get.js @@ -25,7 +25,7 @@ function do_get(subcmd, opts, args, cb) { } if (args.length < 2) { - cb(new errors.UsageError('missing and/or arguments')); + cb(new errors.UsageError('missing INST and/or SNAPNAME arguments')); return; } else if (args.length > 2) { cb(new errors.UsageError('incorrect number of arguments')); @@ -55,7 +55,6 @@ function do_get(subcmd, opts, args, cb) { }); } - do_get.options = [ { names: ['help', 'h'], @@ -68,11 +67,13 @@ do_get.options = [ help: 'JSON stream output.' } ]; + +do_get.synopses = ['{{name}} {{cmd}} [OPTIONS] INST SNAPNAME']; + do_get.help = [ 'Show a specific snapshot of an instance.', '', - 'Usage:', - ' {{name}} get ', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_instance/do_snapshot/do_list.js b/lib/do_instance/do_snapshot/do_list.js index 70686c0..622f576 100644 --- a/lib/do_instance/do_snapshot/do_list.js +++ b/lib/do_instance/do_snapshot/do_list.js @@ -30,7 +30,7 @@ function do_list(subcmd, opts, args, cb) { } if (args.length === 0) { - cb(new errors.UsageError('missing argument')); + cb(new errors.UsageError('missing INST argument')); return; } else if (args.length > 1) { cb(new errors.UsageError('incorrect number of arguments')); @@ -84,11 +84,12 @@ do_list.options = [ sortDefault: SORT_DEFAULT })); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS] INST']; + do_list.help = [ 'Show all of an instance\'s snapshots.', '', - 'Usage:', - ' {{name}} list [] ', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_instance/do_snapshot/index.js b/lib/do_instance/do_snapshot/index.js index 471dc6f..ba65a97 100644 --- a/lib/do_instance/do_snapshot/index.js +++ b/lib/do_instance/do_snapshot/index.js @@ -31,7 +31,7 @@ function SnapshotCLI(top) { 'delete' ], helpBody: 'Instances can be rolled back to a snapshot using\n' + - '`triton instance start --snapshot=`.' + '`triton instance start --snapshot=SNAPNAME`.' }); } util.inherits(SnapshotCLI, Cmdln); diff --git a/lib/do_instance/do_ssh.js b/lib/do_instance/do_ssh.js index ee1d035..bdf8fed 100644 --- a/lib/do_instance/do_ssh.js +++ b/lib/do_instance/do_ssh.js @@ -14,6 +14,7 @@ var path = require('path'); var spawn = require('child_process').spawn; var common = require('../common'); +var errors = require('../errors'); function do_ssh(subcmd, opts, args, callback) { @@ -23,7 +24,7 @@ function do_ssh(subcmd, opts, args, callback) { this.do_help('help', {}, [subcmd], callback); return; } else if (args.length === 0) { - callback(new Error('invalid args: ' + args)); + callback(new errors.UsageError('missing INST arg')); return; } @@ -94,23 +95,23 @@ do_ssh.options = [ help: 'Show this help.' } ]; +do_ssh.synopses = ['{{name}} ssh [-h] INST [SSH-ARGUMENTS]']; do_ssh.help = [ /* BEGIN JSSTYLED */ 'SSH to the primary IP of an instance', '', - 'Usage:', - ' {{name}} ssh [-h] [-M] []', + '{{usage}}', '', '{{options}}', - 'Where is the name, short ID or ID of a given instance. Note that', - 'the argument must come before any `ssh` options or arguments.', + 'Where INST is the name, id, or short id of an instance. Note that', + 'the INST argument must come before any `ssh` options or arguments.', '', 'There is a known issue with SSH connection multiplexing (a.k.a. ', 'ControlMaster, mux) where stdout/stderr is lost. As a workaround, `ssh`', 'is spawned with options disabling ControlMaster. See ', ' for details. If you ', 'want to use ControlMaster, an alternative is:', - ' ssh root@$(triton ip )' + ' ssh root@$(triton ip INST)' /* END JSSTYLED */ ].join('\n'); diff --git a/lib/do_instance/do_tag/do_delete.js b/lib/do_instance/do_tag/do_delete.js index 591468e..deeb518 100644 --- a/lib/do_instance/do_tag/do_delete.js +++ b/lib/do_instance/do_tag/do_delete.js @@ -91,20 +91,21 @@ do_delete.options = [ } ]; +do_delete.synopses = [ + '{{name}} {{cmd}} INST [NAME ...]', + '{{name}} {{cmd}} --all INST # delete all tags' +]; + do_delete.help = [ - /* BEGIN JSSTYLED */ 'Delete one or more instance tags.', '', - 'Usage:', - ' {{name}} delete [ ...]', - ' {{name}} delete --all # delete all tags', + '{{usage}}', '', '{{options}}', - 'Where is an instance id, name, or shortid and is a tag name.', + 'Where INST is an instance id, name, or shortid and NAME is a tag name.', '', 'Changing instance tags is asynchronous. Use "--wait" to not return until', 'the changes are completed.' - /* END JSSTYLED */ ].join('\n'); do_delete.aliases = ['rm']; diff --git a/lib/do_instance/do_tag/do_get.js b/lib/do_instance/do_tag/do_get.js index 776c656..9060300 100644 --- a/lib/do_instance/do_tag/do_get.js +++ b/lib/do_instance/do_tag/do_get.js @@ -53,16 +53,15 @@ do_get.options = [ } ]; +do_get.synopses = ['{{name}} {{cmd}} INST NAME']; + do_get.help = [ - /* BEGIN JSSTYLED */ 'Get an instance tag.', '', - 'Usage:', - ' {{name}} get ', + '{{usage}}', '', '{{options}}', - 'Where is an instance id, name, or shortid and is a tag name.' - /* END JSSTYLED */ + 'Where INST is an instance id, name, or shortid and NAME is a tag name.' ].join('\n'); // TODO: When have 'tritoninstancetag' completion, add that in. diff --git a/lib/do_instance/do_tag/do_list.js b/lib/do_instance/do_tag/do_list.js index cd2a3b8..60023ef 100644 --- a/lib/do_instance/do_tag/do_list.js +++ b/lib/do_instance/do_tag/do_list.js @@ -49,19 +49,18 @@ do_list.options = [ } ]; +do_list.synopses = ['{{name}} {{cmd}} INST']; + do_list.help = [ - /* BEGIN JSSTYLED */ 'List instance tags.', '', - 'Usage:', - ' {{name}} list ', + '{{usage}}', '', '{{options}}', - 'Where is an instance id, name, or shortid.', + 'Where INST is an instance id, name, or shortid.', '', 'Note: Currently this dumps prettified JSON by default. That might change', 'in the future. Use "-j" to explicitly get JSON output.' - /* END JSSTYLED */ ].join('\n'); do_list.aliases = ['ls']; diff --git a/lib/do_instance/do_tag/do_replace_all.js b/lib/do_instance/do_tag/do_replace_all.js index 384dc7c..fa6f643 100644 --- a/lib/do_instance/do_tag/do_replace_all.js +++ b/lib/do_instance/do_tag/do_replace_all.js @@ -108,17 +108,19 @@ do_replace_all.options = [ } ]; +do_replace_all.synopses = [ + '{{name}} {{cmd}} INST [NAME=VALUE ...]', + '{{name}} {{cmd}} INST -f FILE # tags from file' +]; + do_replace_all.help = [ - /* BEGIN JSSTYLED */ 'Replace all tags on the given instance.', '', - 'Usage:', - ' {{name}} replace-all [= ...]', - ' {{name}} replace-all -f # tags from file', + '{{usage}}', '', '{{options}}', - 'Where is an instance id, name, or shortid; is a tag name;', - 'and is a tag value (bool and numeric "value" are converted to ', + 'Where INST is an instance id, name, or shortid; NAME is a tag name;', + 'and VALUE is a tag value (bool and numeric "value" are converted to ', 'that type).', '', 'Currently this dumps prettified JSON by default. That might change in the', @@ -126,7 +128,6 @@ do_replace_all.help = [ '', 'Changing instance tags is asynchronous. Use "--wait" to not return until', 'the changes are completed.' - /* END JSSTYLED */ ].join('\n'); do_replace_all.completionArgtypes = ['tritoninstance', 'file']; diff --git a/lib/do_instance/do_tag/do_set.js b/lib/do_instance/do_tag/do_set.js index 77556aa..8040e63 100644 --- a/lib/do_instance/do_tag/do_set.js +++ b/lib/do_instance/do_tag/do_set.js @@ -109,17 +109,20 @@ do_set.options = [ } ]; +do_set.synopses = [ + '{{name}} set INST [NAME=VALUE ...]', + '{{name}} set INST -f FILE # tags from file' +]; + do_set.help = [ /* BEGIN JSSTYLED */ 'Set one or more instance tags.', '', - 'Usage:', - ' {{name}} set [= ...]', - ' {{name}} set -f # tags from file', + '{{usage}}', '', '{{options}}', - 'Where is an instance id, name, or shortid; is a tag name;', - 'and is a tag value (bool and numeric "value" are converted to ', + 'Where INST is an instance id, name, or shortid; NAME is a tag name;', + 'and VALUE is a tag value (bool and numeric "value" are converted to ', 'that type).', '', 'Currently this dumps prettified JSON by default. That might change in the', diff --git a/lib/do_instance/do_wait.js b/lib/do_instance/do_wait.js index 3e220ad..529acb2 100644 --- a/lib/do_instance/do_wait.js +++ b/lib/do_instance/do_wait.js @@ -21,7 +21,7 @@ function do_wait(subcmd, opts, args, cb) { if (opts.help) { return this.do_help('help', {}, [subcmd], cb); } else if (args.length < 1) { - return cb(new errors.UsageError('missing INSTANCE arg(s)')); + return cb(new errors.UsageError('missing INST arg(s)')); } var ids = args; var states = []; @@ -110,16 +110,19 @@ function do_wait(subcmd, opts, args, cb) { }); } +do_wait.synopses = ['{{name}} {{cmd}} [-s STATES] INST [INST ...]']; do_wait.help = [ + /* BEGIN JSSTYLED */ 'Wait on instances changing state.', '', - 'Usage:', - ' {{name}} wait [-s STATES] INSTANCE [INSTANCE ...]', + '{{usage}}', '', '{{options}}', - 'Where "states" is a comma-separated list of target instance states,', - 'by default "running,failed". In other words, "triton inst wait foo0" will', - 'wait for instance "foo0" to complete provisioning.' + 'Where "INST" is an instance name, id, or short id; and "STATES" is a', + 'comma-separated list of target instance states, by default "running,failed".', + 'In other words, "triton inst wait foo0" will wait for instance "foo0" to', + 'complete provisioning.' + /* END JSSTYLED */ ].join('\n'); do_wait.options = [ { diff --git a/lib/do_instance/gen_do_ACTION.js b/lib/do_instance/gen_do_ACTION.js index 09489f5..1e86fc7 100644 --- a/lib/do_instance/gen_do_ACTION.js +++ b/lib/do_instance/gen_do_ACTION.js @@ -5,7 +5,7 @@ */ /* - * Copyright 2015 Joyent, Inc. + * Copyright 2016 Joyent, Inc. * * Shared support for: * `triton instance start ...` @@ -18,9 +18,7 @@ var assert = require('assert-plus'); var vasync = require('vasync'); var common = require('../common'); - - -var f = require('util').format; +var errors = require('../errors'); function perror(err) { @@ -40,18 +38,20 @@ function gen_do_ACTION(opts) { function do_ACTION(subcmd, _opts, args, callback) { return _doTheAction.call(this, action, subcmd, _opts, args, callback); } + do_ACTION.name = 'do_' + action; if (opts.aliases) { do_ACTION.aliases = opts.aliases; } + do_ACTION.synopses = ['{{name}} ' + action + ' [OPTIONS] INST [INST ...]']; do_ACTION.help = [ - f('%s one or more instances.', common.capitalize(action)), - f(''), - f('Usage:'), - f(' {{name}} %s ...', action), - f(''), - f('{{options}}') + common.capitalize(action) + ' one or more instances.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where "INST" is an instance name, id, or short id.' ].join('\n'); do_ACTION.options = [ { @@ -72,7 +72,8 @@ function gen_do_ACTION(opts) { do_ACTION.options.push({ names: ['snapshot'], type: 'string', - help: 'Name of snapshot to start machine with.' + help: 'Name of snapshot with which to start the instance.', + helpArg: 'SNAPNAME' }); } @@ -112,7 +113,7 @@ function _doTheAction(action, subcmd, opts, args, callback) { this.do_help('help', {}, [subcmd], callback); return; } else if (args.length < 1) { - callback(new Error('invalid args: ' + args)); + callback(new errors.UsageError('missing INST arg(s)')); return; } diff --git a/lib/do_key/do_add.js b/lib/do_key/do_add.js index d767006..15b5d5a 100644 --- a/lib/do_key/do_add.js +++ b/lib/do_key/do_add.js @@ -125,11 +125,13 @@ do_add.options = [ help: 'An optional name for an added key.' } ]; + +do_add.synopses = ['{{name}} {{cmd}} [OPTIONS] FILE']; + do_add.help = [ 'Add an SSH key to an account.', '', - 'Usage:', - ' {{name}} add [] FILE', + '{{usage}}', '', '{{options}}', 'Where "FILE" must be a file path to an SSH public key, ', diff --git a/lib/do_key/do_delete.js b/lib/do_key/do_delete.js index 64ca8b7..69e77d2 100644 --- a/lib/do_key/do_delete.js +++ b/lib/do_key/do_delete.js @@ -104,11 +104,13 @@ do_delete.options = [ help: 'Answer yes to confirmation to delete.' } ]; + +do_delete.synopses = ['{{name}} {{cmd}} [OPTIONS] KEY [KEY ...]']; + do_delete.help = [ 'Remove an SSH key from an account.', '', - 'Usage:', - ' {{name}} delete [] KEY [KEY...]', + '{{usage}}', '', '{{options}}', 'Where "KEY" is an SSH key "name" or "fingerprint".' diff --git a/lib/do_key/do_get.js b/lib/do_key/do_get.js index c37f62d..92fd43a 100644 --- a/lib/do_key/do_get.js +++ b/lib/do_key/do_get.js @@ -67,11 +67,13 @@ do_get.options = [ help: 'JSON stream output.' } ]; + +do_get.synopses = ['{{name}} {{cmd}} KEY']; + do_get.help = [ 'Show a specific SSH key in an account.', '', - 'Usage:', - ' {{name}} get KEY', + '{{usage}}', '', '{{options}}', 'Where "KEY" is an SSH key "name" or "fingerprint".' diff --git a/lib/do_key/do_list.js b/lib/do_key/do_list.js index a6ddd1a..69f9c4b 100644 --- a/lib/do_key/do_list.js +++ b/lib/do_key/do_list.js @@ -90,11 +90,11 @@ do_list.options = [ } ]); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS]']; do_list.help = [ 'Show all of an account\'s SSH keys.', '', - 'Usage:', - ' {{name}} list []', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_network/do_get.js b/lib/do_network/do_get.js index 7283b80..8d62ed3 100644 --- a/lib/do_network/do_get.js +++ b/lib/do_network/do_get.js @@ -51,14 +51,17 @@ do_get.options = [ help: 'JSON output.' } ]; -do_get.help = ( - 'Show a network.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} get \n' - + '\n' - + '{{options}}' -); + +do_get.synopses = ['{{name}} {{cmd}} NETWORK']; + +do_get.help = [ + 'Show a network.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where NETWORK is a network id (full UUID), name, or short id.' +].join('\n'); do_get.completionArgtypes = ['tritonnetwork', 'none']; diff --git a/lib/do_network/do_list.js b/lib/do_network/do_list.js index 43bc0f4..b3bd3c9 100644 --- a/lib/do_network/do_list.js +++ b/lib/do_network/do_list.js @@ -85,17 +85,17 @@ do_list.options = [ sortDefault: sortDefault })); +do_list.synopses = ['{{name}} {{cmd}}']; + do_list.help = [ 'List available networks.', '', - 'Usage:', - ' {{name}} list', + '{{usage}}', '', + '{{options}}', 'Fields (most are self explanatory, the client adds some for convenience):', ' vlan A shorter alias for "vlan_id".', - ' shortid A short ID prefix.', - '', - '{{options}}' + ' shortid A short ID prefix.' ].join('\n'); do_list.aliases = ['ls']; diff --git a/lib/do_package/do_get.js b/lib/do_package/do_get.js index 34e432b..d02b3a5 100644 --- a/lib/do_package/do_get.js +++ b/lib/do_package/do_get.js @@ -50,21 +50,23 @@ do_get.options = [ help: 'JSON stream output.' } ]; -do_get.help = ( + +do_get.synopses = ['{{name}} {{cmd}} [OPTIONS] PACKAGE']; + +do_get.help = [ /* BEGIN JSSTYLED */ - 'Get a package.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} get [] ID|NAME\n' + - '\n' + - '{{options}}' + - '\n' + - 'The given "NAME" must be a unique match.\n' + - '\n' + - 'Note: Currently this dumps prettified JSON by default. That might change\n' + - 'in the future. Use "-j" to explicitly get JSON output.\n' + 'Get a package.', + '', + '{{usage}}', + '', + '{{options}}', + '', + 'Where PACKAGE is a package id (full UUID), exact name, or short id.', + '', + 'Note: Currently this dumps prettified JSON by default. That might change', + 'in the future. Use "-j" to explicitly get JSON output.' /* END JSSTYLED */ -); +].join('\n'); do_get.completionArgtypes = ['tritonpackage', 'none']; diff --git a/lib/do_package/do_list.js b/lib/do_package/do_list.js index 72bdd4d..b7ba5a0 100644 --- a/lib/do_package/do_list.js +++ b/lib/do_package/do_list.js @@ -28,10 +28,10 @@ var validFilters = [ ]; // columns default without -o -var columnsDefault = 'shortid,name,default,memory,swap,disk,vcpus'; +var columnsDefault = 'shortid,name,memory,swap,disk,vcpus'; // columns default with -l -var columnsDefaultLong = 'id,name,default,memory,swap,disk,vcpus'; +var columnsDefaultLong = 'id,name,memory,swap,disk,vcpus,description'; // sort default with -s var sortDefault = '_groupPlus,memory'; @@ -154,12 +154,12 @@ do_list.options = [ } ]); +do_list.synopses = ['{{name}} {{cmd}} [FILTERS]']; do_list.help = [ /* BEGIN JSSTYLED */ 'List packages.', '', - 'Usage:', - ' {{name}} list []', + '{{usage}}', '', '{{options}}', 'Filters:', @@ -177,7 +177,7 @@ do_list.help = [ ' zero is shown as "-" in tabular output.', '', 'Examples:', - ' {{name}} packages memory=8192 # list packages with 8G RAM' + ' {{name}} list memory=8192 # list packages with 8G RAM' /* END JSSTYLED */ ].join('\n'); diff --git a/lib/do_package/index.js b/lib/do_package/index.js index 7823a2b..e64c1ca 100644 --- a/lib/do_package/index.js +++ b/lib/do_package/index.js @@ -23,7 +23,11 @@ function PackageCLI(top) { name: top.name + ' package', /* BEGIN JSSTYLED */ desc: [ - 'List and get Triton packages.' + 'List and get Triton packages.', + '', + 'A package is a collection of attributes -- for example disk quota,', + 'amount of RAM -- used when creating an instance. They have a name', + 'and ID for identification.' ].join('\n'), /* END JSSTYLED */ helpOpts: { diff --git a/lib/do_profile/do_create.js b/lib/do_profile/do_create.js index 493ad05..6a9f979 100644 --- a/lib/do_profile/do_create.js +++ b/lib/do_profile/do_create.js @@ -366,11 +366,11 @@ do_create.options = [ ]; +do_create.synopses = ['{{name}} {{cmd}} [OPTIONS]']; do_create.help = [ 'Create a Triton CLI profile.', '', - 'Usage:', - ' {{name}} create ', + '{{usage}}', '', '{{options}}', '', diff --git a/lib/do_profile/do_delete.js b/lib/do_profile/do_delete.js index 3210209..256253e 100644 --- a/lib/do_profile/do_delete.js +++ b/lib/do_profile/do_delete.js @@ -120,11 +120,11 @@ do_delete.options = [ } ]; +do_delete.synopses = ['{{name}} {{cmd}} PROFILE']; do_delete.help = [ 'Delete a Triton CLI profile.', '', - 'Usage:', - ' {{name}} delete NAME', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_profile/do_docker_setup.js b/lib/do_profile/do_docker_setup.js index 0dedb7c..048792e 100644 --- a/lib/do_profile/do_docker_setup.js +++ b/lib/do_profile/do_docker_setup.js @@ -33,12 +33,12 @@ do_docker_setup.options = [ } ]; +do_docker_setup.synopses = ['{{name}} {{cmd}} [PROFILE]']; do_docker_setup.help = [ /* BEGIN JSSTYLED */ 'Setup for using Docker with the current Triton CLI profile.', '', - 'Usage:', - ' {{name}} docker-setup [PROFILE]', + '{{usage}}', '', '{{options}}', 'A Triton datacenter can act as a virtual Docker Engine, where the entire', @@ -54,5 +54,6 @@ do_docker_setup.help = [ /* END JSSTYLED */ ].join('\n'); +do_docker_setup.completionArgtypes = ['tritonprofile', 'none']; module.exports = do_docker_setup; diff --git a/lib/do_profile/do_edit.js b/lib/do_profile/do_edit.js index 8ca967b..ed3f6fb 100644 --- a/lib/do_profile/do_edit.js +++ b/lib/do_profile/do_edit.js @@ -154,11 +154,11 @@ do_edit.options = [ } ]; +do_edit.synopses = ['{{name}} {{cmd}} [PROFILE]']; do_edit.help = [ 'Edit a Triton CLI profile in your $EDITOR.', '', - 'Usage:', - ' {{name}} edit [NAME]', + '{{usage}}', '', '{{options}}' ].join('\n'); diff --git a/lib/do_profile/do_get.js b/lib/do_profile/do_get.js index 6ff59d3..8831a14 100644 --- a/lib/do_profile/do_get.js +++ b/lib/do_profile/do_get.js @@ -74,15 +74,16 @@ do_get.options = [ } ]; +do_get.synopses = ['{{name}} {{cmd}} [PROFILE]']; do_get.help = [ 'Get a Triton CLI profile.', '', - 'Usage:', - ' {{name}} get [NAME]', + '{{usage}}', '', '{{options}}', 'If NAME is not specified, the current profile is shown.' ].join('\n'); +do_get.completionArgtypes = ['tritonprofile', 'none']; module.exports = do_get; diff --git a/lib/do_profile/do_list.js b/lib/do_profile/do_list.js index 0c1ef59..1597fbf 100644 --- a/lib/do_profile/do_list.js +++ b/lib/do_profile/do_list.js @@ -112,22 +112,21 @@ do_list.options = [ includeLong: true, sortDefault: sortDefault })); +do_list.synopses = ['{{name}} {{cmd}} [OPTIONS]']; do_list.help = [ /* BEGIN JSSTYLED */ 'List Triton CLI profiles.', '', + '{{usage}}', + '', + '{{options}}', 'A profile is a configured Triton CloudAPI endpoint and associated info.', 'I.e. the URL, account name, SSH key fingerprint, etc. information required', 'to call a CloudAPI endpoint in a Triton datacenter. You can then switch', 'between profiles with `triton -p PROFILE`, the TRITON_PROFILE environment', 'variable, or by setting your current profile.', '', - 'The "CURR" column indicates which profile is the current one.', - '', - 'Usage:', - ' {{name}} list', - '', - '{{options}}' + 'The "CURR" column indicates which profile is the current one.' /* END JSSTYLED */ ].join('\n'); diff --git a/lib/do_profile/do_set_current.js b/lib/do_profile/do_set_current.js index 632e569..be1b3e2 100644 --- a/lib/do_profile/do_set_current.js +++ b/lib/do_profile/do_set_current.js @@ -13,8 +13,12 @@ function do_set_current(subcmd, opts, args, cb) { if (opts.help) { this.do_help('help', {}, [subcmd], cb); return; - } else if (args.length !== 1) { - return cb(new errors.UsageError('NAME argument is required')); + } else if (args.length === 0) { + cb(new errors.UsageError('missing NAME argument')); + return; + } else if (args.length > 1) { + cb(new errors.UsageError('too many arguments: ' + args.join(' '))); + return; } profilecommon.setCurrentProfile({cli: this.top, name: args[0]}, cb); @@ -28,11 +32,11 @@ do_set_current.options = [ } ]; +do_set_current.synopses = ['{{name}} {{cmd}} PROFILE']; do_set_current.help = [ 'Set the current Triton CLI profile.', '', - 'Usage:', - ' {{name}} set-current NAME', + '{{usage}}', '', '{{options}}', 'NAME is the name of an existing profile, or "-" to switch to the', diff --git a/lib/do_profile/profilecommon.js b/lib/do_profile/profilecommon.js index ac39950..13c4df7 100644 --- a/lib/do_profile/profilecommon.js +++ b/lib/do_profile/profilecommon.js @@ -416,6 +416,8 @@ function profileDockerSetup(opts, cb) { * `docker-compose` versions). It is debatable if we want to * play this game. E.g. someone moving from Docker 1.8 to newer, * *but not re-setting up envvars* may start hitting timeouts. + * + * TODO: consider using `docker-compose` version on PATH? */ if (!arg.dockerVersion) { setup.env.DOCKER_CLIENT_TIMEOUT = '300'; diff --git a/lib/do_rbac/do_apply.js b/lib/do_rbac/do_apply.js index 528cadc..2bd083d 100644 --- a/lib/do_rbac/do_apply.js +++ b/lib/do_rbac/do_apply.js @@ -203,12 +203,13 @@ do_apply.options = [ } ]; +do_apply.synopses = ['{{name}} {{cmd}} [OPTIONS]']; + do_apply.help = [ /* BEGIN JSSTYLED */ 'Apply an RBAC configuration.', '', - 'Usage:', - ' {{name}} apply []', + '{{usage}}', '', '{{options}}', 'If "--file FILE" is not specified, this defaults to using "./rbac.json".', diff --git a/lib/do_rbac/do_info.js b/lib/do_rbac/do_info.js index c9f6faf..bcb7853 100644 --- a/lib/do_rbac/do_info.js +++ b/lib/do_rbac/do_info.js @@ -211,12 +211,13 @@ do_info.options = [ } ]; +do_info.synopses = ['{{name}} {{cmd}} [OPTIONS]']; + do_info.help = [ /* BEGIN JSSTYLED */ 'Show current RBAC state.', '', - 'Usage:', - ' {{name}} info []', + '{{usage}}', '', '{{options}}', 'List RBAC users, roles and policies and. This summary does not show all', diff --git a/lib/do_rbac/do_key.js b/lib/do_rbac/do_key.js index cab77d4..c1ca23d 100644 --- a/lib/do_rbac/do_key.js +++ b/lib/do_rbac/do_key.js @@ -303,20 +303,23 @@ do_key.options = [ help: 'Delete the named key.' } ]; + +do_key.synopses = [ + '{{name}} {{cmd}} USER KEY # show USER\'s KEY', + '{{name}} {{cmd}} -d|--delete USER [KEY...] # delete USER\'s KEY', + '{{name}} {{cmd}} -a|--add [-n NAME] USER FILE # add an SSH key' +]; + do_key.help = [ /* BEGIN JSSTYLED */ 'Show, upload, and delete RBAC user SSH keys.', '', - 'Usage:', - ' {{name}} key USER KEY # show USER\'s KEY', - ' {{name}} key -d|--delete USER [KEY...] # delete USER\'s KEY', - ' {{name}} key -a|--add [-n NAME] USER FILE', - ' # Add a new role. FILE must be a file path to an SSH public', - ' # key or "-" to pass the public key in on stdin.', + '{{usage}}', '', '{{options}}', 'Where "USER" is a full RBAC user "id", "login" name or a "shortid"; and', - 'KEY is an SSH key "name" or "fingerprint".' + 'KEY is an SSH key "name" or "fingerprint". FILE must be a file path to', + 'an SSH public key or "-" to pass the public key in on stdin.' /* END JSSTYLED */ ].join('\n'); diff --git a/lib/do_rbac/do_keys.js b/lib/do_rbac/do_keys.js index 11682ca..925c0cb 100644 --- a/lib/do_rbac/do_keys.js +++ b/lib/do_rbac/do_keys.js @@ -84,19 +84,18 @@ do_keys.options = [ } ]); -do_keys.help = ( - /* BEGIN JSSTYLED */ - 'List RBAC user SSH keys.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} keys [] USER\n' + - '\n' + - '{{options}}' + - '\n' + - 'Where "USER" is an RBAC user login or id (a UUID).\n' - /* END JSSTYLED */ -); +do_keys.synopses = ['{{name}} {{cmd}} [OPTIONS] USER']; +do_keys.help = [ + /* BEGIN JSSTYLED */ + 'List RBAC user SSH keys.', + '', + '{{usage}}', + '', + '{{options}}', + 'Where "USER" is an RBAC user login or id (a UUID).' + /* END JSSTYLED */ +].join('\n'); module.exports = do_keys; diff --git a/lib/do_rbac/do_policies.js b/lib/do_rbac/do_policies.js index 4bb4af7..a873324 100644 --- a/lib/do_rbac/do_policies.js +++ b/lib/do_rbac/do_policies.js @@ -82,20 +82,17 @@ do_policies.options = [ sortDefault: sortDefault })); -do_policies.help = ( - /* BEGIN JSSTYLED */ - 'List RBAC policies.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} policies []\n' + - '\n' + - '{{options}}' + - '\n' + - 'Fields (most are self explanatory, the client adds some for convenience):\n' + - ' nrules The number of rules in this policy.\n' - /* END JSSTYLED */ -); +do_policies.synopses = ['{{name}} {{cmd}} [OPTIONS]']; +do_policies.help = [ + 'List RBAC policies.', + '', + '{{usage}}', + '', + '{{options}}', + 'Fields (most are self explanatory, the client adds some for convenience):', + ' nrules The number of rules in this policy.' +].join('\n'); module.exports = do_policies; diff --git a/lib/do_rbac/do_policy.js b/lib/do_rbac/do_policy.js index 7f1c161..3e6b278 100644 --- a/lib/do_rbac/do_policy.js +++ b/lib/do_rbac/do_policy.js @@ -512,16 +512,24 @@ do_policy.options = [ help: 'Delete the named policy.' } ]; + +do_policy.synopses = [ + '{{name}} {{cmd}} POLICY # show policy POLICY', + '{{name}} {{cmd}} -e|--edit POLICY # edit policy POLICY in $EDITOR', + '{{name}} {{cmd}} -d|--delete [POLICY...] # delete policy POLICY', + '{{name}} {{cmd}} -a|--add [FILE] # add a new policy' +]; + do_policy.help = [ /* BEGIN JSSTYLED */ 'Show, add, edit and delete RBAC policies.', '', 'Usage:', - ' {{name}} policy POLICY # show policy POLICY', - ' {{name}} policy -e|--edit POLICY # edit policy POLICY in $EDITOR', - ' {{name}} policy -d|--delete [POLICY...] # delete policy POLICY', + ' {{name}} {{cmd}} POLICY # show policy POLICY', + ' {{name}} {{cmd}} -e|--edit POLICY # edit policy POLICY in $EDITOR', + ' {{name}} {{cmd}} -d|--delete [POLICY...] # delete policy POLICY', '', - ' {{name}} policy -a|--add [FILE]', + ' {{name}} {{cmd}} -a|--add [FILE]', ' # Add a new policy. FILE must be a file path to a JSON file', ' # with the policy data or "-" to pass the policy in on stdin.', ' # Or exclude FILE to interactively add.', diff --git a/lib/do_rbac/do_reset.js b/lib/do_rbac/do_reset.js index 6037cea..998bdfa 100644 --- a/lib/do_rbac/do_reset.js +++ b/lib/do_rbac/do_reset.js @@ -104,13 +104,16 @@ do_reset.options = [ } ]; +do_reset.synopses = [ + '{{name}} {{cmd}} [OPTIONS]' +]; + do_reset.help = [ /* BEGIN JSSTYLED */ 'Reset RBAC state for this account.', '**Warning: This will delete all RBAC info for this account.**', '', - 'Usage:', - ' {{name}} reset []', + '{{usage}}', '', '{{options}}', 'Warning: Currently, RBAC state updates can take a few seconds to appear', diff --git a/lib/do_rbac/do_role.js b/lib/do_rbac/do_role.js index 6249989..4fb56a7 100644 --- a/lib/do_rbac/do_role.js +++ b/lib/do_rbac/do_role.js @@ -490,16 +490,24 @@ do_role.options = [ help: 'Delete the named role.' } ]; + +do_role.synopses = [ + '{{name}} {{cmd}} ROLE # show role ROLE', + '{{name}} {{cmd}} -e|--edit ROLE # edit role ROLE in $EDITOR', + '{{name}} {{cmd}} -d|--delete [ROLE...] # delete role ROLE', + '{{name}} {{cmd}} -a|--add [FILE] # add a new role' +]; + do_role.help = [ /* BEGIN JSSTYLED */ 'Show, add, edit and delete RBAC roles.', '', 'Usage:', - ' {{name}} role ROLE # show role ROLE', - ' {{name}} role -e|--edit ROLE # edit role ROLE in $EDITOR', - ' {{name}} role -d|--delete [ROLE...] # delete role ROLE', + ' {{name}} {{cmd}} ROLE # show role ROLE', + ' {{name}} {{cmd}} -e|--edit ROLE # edit role ROLE in $EDITOR', + ' {{name}} {{cmd}} -d|--delete [ROLE...] # delete role ROLE', '', - ' {{name}} role -a|--add [FILE]', + ' {{name}} {{cmd}} -a|--add [FILE]', ' # Add a new role. FILE must be a file path to a JSON file', ' # with the role data or "-" to pass the role in on stdin.', ' # Or exclude FILE to interactively add.', diff --git a/lib/do_rbac/do_role_tags.js b/lib/do_rbac/do_role_tags.js index c84858e..c669f1c 100644 --- a/lib/do_rbac/do_role_tags.js +++ b/lib/do_rbac/do_role_tags.js @@ -508,7 +508,8 @@ function makeRoleTagsFunc(cfg) { } }; - func.name = cfg.funcName; + func.name = cfg.funcName; // XXX + func.subcmd = cfg.funcName; func.options = [ { @@ -564,24 +565,31 @@ function makeRoleTagsFunc(cfg) { helpCol: 23 }; + func.synopses = [ + '{{name}} {{cmd}} $argName # list role tags', + '{{name}} {{cmd}} -a ROLE[,ROLE...] $argName # add', + '{{name}} {{cmd}} -s ROLE[,ROLE...] $argName # set/replace', + '{{name}} {{cmd}} -e $argName # edit in $EDITOR', + '{{name}} {{cmd}} -d ROLE[,ROLE...] $argName # delete', + '{{name}} {{cmd}} -D $argName # delete all' + ]; + func.synopses = func.synopses.map(function (synopsis) { + var key = 'argName'; + return synopsis.replace(new RegExp('\\$' + key, 'g'), cfg[key]); + }); + func.help = [ /* BEGIN JSSTYLED */ 'List and manage role tags for the given $resourceType.', '', - 'Usage:', - ' {{name}} $cmdName $argName # list role tags', - ' {{name}} $cmdName -a ROLE[,ROLE...] $argName # add', - ' {{name}} $cmdName -s ROLE[,ROLE...] $argName # set/replace', - ' {{name}} $cmdName -e $argName # edit in $EDITOR', - ' {{name}} $cmdName -d ROLE[,ROLE...] $argName # delete', - ' {{name}} $cmdName -D $argName # delete all', + '{{usage}}', '', '{{options}}', 'Where "ROLE" is a role tag name (see `triton rbac roles`) and', '$argName is $helpArgIs.' /* END JSSTYLED */ ].join('\n'); - ['resourceType', 'cmdName', 'argName', 'helpArgIs'].forEach(function (key) { + ['resourceType', 'cmdName', 'helpArgIs'].forEach(function (key) { func.help = func.help.replace(new RegExp('\\$' + key, 'g'), cfg[key]); }); diff --git a/lib/do_rbac/do_roles.js b/lib/do_rbac/do_roles.js index 7de0845..772134f 100644 --- a/lib/do_rbac/do_roles.js +++ b/lib/do_rbac/do_roles.js @@ -97,20 +97,20 @@ do_roles.options = [ sortDefault: sortDefault })); -do_roles.help = ( +do_roles.synopses = ['{{name}} {{cmd}} [OPTIONS]']; + +do_roles.help = [ /* BEGIN JSSTYLED */ - 'List RBAC roles.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} roles []\n' + - '\n' + - '{{options}}' + - '\n' + - 'Fields (most are self explanatory, the client adds some for convenience):\n' + - ' members Non-default members (not in the "default_members")\n' + + 'List RBAC roles.', + '', + '{{usage}}', + '', + '{{options}}', + 'Fields (most are self explanatory, the client adds some for convenience):', + ' members Non-default members (not in the "default_members")', ' are shown in magenta.\n' /* END JSSTYLED */ -); +].join('\n'); diff --git a/lib/do_rbac/do_user.js b/lib/do_rbac/do_user.js index 2f5083e..b3a755a 100644 --- a/lib/do_rbac/do_user.js +++ b/lib/do_rbac/do_user.js @@ -497,16 +497,24 @@ do_user.options = [ help: 'Delete the named user.' } ]; + +do_user.synopses = [ + '{{name}} {{cmd}} [OPTIONS] USER # show user USER', + '{{name}} {{cmd}} -e|--edit USER # edit user USER in $EDITOR', + '{{name}} {{cmd}} -d|--delete [USER...] # delete user USER', + '{{name}} {{cmd}} -a|--add [FILE] # add a user' +]; + do_user.help = [ /* BEGIN JSSTYLED */ 'Show, add, edit and delete RBAC users.', '', 'Usage:', - ' {{name}} user [] USER # show user USER', - ' {{name}} user -e|--edit USER # edit user USER in $EDITOR', - ' {{name}} user -d|--delete [USER...] # delete user USER', + ' {{name}} {{cmd}} [OPTIONS] USER # show user USER', + ' {{name}} {{cmd}} -e|--edit USER # edit user USER in $EDITOR', + ' {{name}} {{cmd}} -d|--delete [USER...] # delete user USER', '', - ' {{name}} user -a|--add [FILE]', + ' {{name}} {{cmd}} -a|--add [FILE]', ' # Add a new user. FILE must be a file path to a JSON file', ' # with the user data or "-" to pass the user in on stdin.', ' # Or exclude FILE to interactively add.', diff --git a/lib/do_rbac/do_users.js b/lib/do_rbac/do_users.js index f9c338f..f12aa8f 100644 --- a/lib/do_rbac/do_users.js +++ b/lib/do_rbac/do_users.js @@ -84,22 +84,19 @@ do_users.options = [ sortDefault: sortDefault })); -do_users.help = ( - /* BEGIN JSSTYLED */ - 'List RBAC users.\n' + - '\n' + - 'Usage:\n' + - ' {{name}} users []\n' + - '\n' + - 'Fields (most are self explanatory, the client adds some for convenience):\n' + - ' name "firstName lastName"\n' + - ' cdate Just the date portion of "created"\n' + - ' udate Just the date portion of "updated"\n' + - '\n' + - '{{options}}' - /* END JSSTYLED */ -); +do_users.synopses = ['{{name}} {{cmd}} [OPTIONS]']; +do_users.help = [ + 'List RBAC users.', + '', + '{{usage}}', + '', + '{{options}}', + 'Fields (most are self explanatory, the client adds some for convenience):', + ' name "firstName lastName"', + ' cdate Just the date portion of "created"', + ' udate Just the date portion of "updated"' +].join('\n'); module.exports = do_users; diff --git a/lib/do_services.js b/lib/do_services.js index e1930b5..b8e90be 100644 --- a/lib/do_services.js +++ b/lib/do_services.js @@ -77,13 +77,14 @@ do_services.options = [ sortDefault: sortDefault })); -do_services.help = ( - 'Show services information\n' - + '\n' - + 'Usage:\n' - + ' {{name}} services\n' - + '\n' - + '{{options}}' -); +do_services.synopses = ['{{name}} {{cmd}}']; + +do_services.help = [ + 'Show services information', + '', + '{{usage}}', + '', + '{{options}}' +].join('\n'); module.exports = do_services; diff --git a/lib/errors.js b/lib/errors.js index 5fccaf8..0605bdc 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -10,6 +10,7 @@ * Error classes that the joyent CLI may produce. */ +var cmdln = require('cmdln'); var util = require('util'), format = util.format; var assert = require('assert-plus'); @@ -145,25 +146,6 @@ function ConfigError(cause, message) { util.inherits(ConfigError, _TritonBaseVError); -/** - * CLI usage error - */ -function UsageError(cause, message) { - if (message === undefined) { - message = cause; - cause = undefined; - } - assert.string(message); - _TritonBaseVError.call(this, { - cause: cause, - message: message, - code: 'Usage', - exitStatus: 2 - }); -} -util.inherits(UsageError, _TritonBaseVError); - - /** * Error in setting up (typically in profile update/creation). */ @@ -299,7 +281,7 @@ module.exports = { TritonError: TritonError, InternalError: InternalError, ConfigError: ConfigError, - UsageError: UsageError, + UsageError: cmdln.UsageError, SetupError: SetupError, SigningError: SigningError, SelfSignedCertError: SelfSignedCertError, diff --git a/lib/tritonapi.js b/lib/tritonapi.js index 83ea8f3..8746000 100644 --- a/lib/tritonapi.js +++ b/lib/tritonapi.js @@ -28,7 +28,6 @@ var vasync = require('vasync'); var cloudapi = require('./cloudapi2'); var common = require('./common'); var errors = require('./errors'); -var loadConfigSync = require('./config').loadConfigSync; // ---- globals diff --git a/package.json b/package.json index af29c9d..7e16bba 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "name": "triton", "description": "Joyent Triton CLI and client (https://www.joyent.com/triton)", - "version": "4.12.1", + "version": "4.13.0", "author": "Joyent (joyent.com)", "dependencies": { "assert-plus": "0.2.0", "backoff": "2.4.1", "bigspinner": "3.1.0", "bunyan": "1.5.1", - "cmdln": "3.5.4", + "cmdln": "4.1.1", "extsprintf": "1.0.2", "lomstream": "1.1.0", "mkdirp": "0.5.1",