joyent/node-triton#101 Bash completion for server-side data: instances, images, etc.
This commit is contained in:
parent
7d635fc81c
commit
e3b5e6b016
@ -1,7 +1,14 @@
|
||||
# node-triton changelog
|
||||
|
||||
## 4.6.1 (not yet released)
|
||||
## 4.7.0 (not yet released)
|
||||
|
||||
- #101 Bash completion for server-side data: instances, images, etc.
|
||||
Bash completion on TAB should now work for things like the following:
|
||||
`triton create <TAB to complete images> <TAB to complete packages`,
|
||||
`triton inst tag ls <TAB to complete instances>`. Cached (with a 5 minute
|
||||
TTL) completions for the following data are supported: instances, images,
|
||||
packages, networks, fwrules, account keys.
|
||||
See `triton completion --help` for adding/updating Bash completion.
|
||||
- #99 `triton profile set ...` alias for `set-current`
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Functions for Bash completion of some 'triton' option/arg types.
|
||||
|
||||
function complete_tritonprofile {
|
||||
local word="$1"
|
||||
local candidates
|
||||
@ -7,6 +8,144 @@ function complete_tritonprofile {
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Get completions for a given type of Triton (server-side) data.
|
||||
#
|
||||
# Usage:
|
||||
# _complete_tritondata $type # e.g. _complete_tritondata images
|
||||
#
|
||||
# The easiest/slowest thing to do to complete images would be to just call:
|
||||
# triton [profile-related-args] images -Ho name
|
||||
# or similar. Too slow.
|
||||
#
|
||||
# The next easiest would be this:
|
||||
# candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||
# where `triton` is setup to specially just handle completions if
|
||||
# `TRITON_COMPLETE` is set. That special handling writes out a cache file to
|
||||
# avoid hitting the server every time. This is still too slow because the
|
||||
# node.js startup time for `triton` is too slow (around 1s on my laptop).
|
||||
#
|
||||
# The next choice is to (a) use the special `TRITON_COMPLETE` handling to
|
||||
# fetch data from the server and write out a cache file, but (b) attempt to
|
||||
# find and use that cache file without calling node.js code. The win is
|
||||
# (at least in my usage) faster response time to a <TAB>. The cost is doing
|
||||
# reproducing (imperfectly) in Bash the logic for determining the Triton profile
|
||||
# info to find the cache.
|
||||
#
|
||||
function _complete_tritondata {
|
||||
local type=$1
|
||||
|
||||
# First, find the Triton CLI profile.
|
||||
local profile
|
||||
profile=$(echo "$COMP_LINE" | grep -- '\s\+-p\s*\w\+\s\+' | sed -E 's/.* +-p *([^ ]+) +.*/\1/')
|
||||
if [[ -z "$profile" ]]; then
|
||||
profile=$TRITON_PROFILE
|
||||
fi
|
||||
if [[ -z "$profile" ]]; then
|
||||
profile=$(grep '"profile":' ~/.triton/config.json | cut -d'"' -f4)
|
||||
fi
|
||||
if [[ -z "$profile" ]]; then
|
||||
profile=env
|
||||
fi
|
||||
trace " profile: $profile"
|
||||
|
||||
# Then, determine the account and url that go into the cache dir.
|
||||
# TODO: include -a/-U options that change from profile values
|
||||
# TODO: subuser support
|
||||
local url
|
||||
local account
|
||||
local profileFile
|
||||
profileFile=$HOME/.triton/profiles.d/$profile.json
|
||||
if [[ "$profile" == "env" ]]; then
|
||||
url=$TRITON_URL
|
||||
if [[ -z "$url" ]]; then
|
||||
url=$SDC_URL
|
||||
fi
|
||||
account=$TRITON_ACCOUNT
|
||||
if [[ -z "$account" ]]; then
|
||||
account=$SDC_ACCOUNT
|
||||
fi
|
||||
elif [[ -f $profileFile ]]; then
|
||||
url=$(grep '"url":' $profileFile | cut -d'"' -f4)
|
||||
account=$(grep '"account":' $profileFile | cut -d'"' -f4)
|
||||
fi
|
||||
trace " url: $url"
|
||||
trace " account: $account"
|
||||
|
||||
# Mimic node-triton/lib/common.js#profileSlug
|
||||
local profileSlug
|
||||
profileSlug="$(echo "$account" | sed -E 's/@/_/g')@$(echo "$url" | sed -E 's#^https?://##')"
|
||||
profileSlug="$(echo "$profileSlug" | sed -E 's/[^a-zA-Z0-9_@-]/_/g')"
|
||||
|
||||
local cacheFile
|
||||
cacheFile="$HOME/.triton/cache/$profileSlug/$type.completions"
|
||||
trace " cacheFile: $cacheFile"
|
||||
|
||||
# If we have a cache file, remove it and regenerate if it is >5 minutes old.
|
||||
#
|
||||
# Dev Note: This 5min TTL should match what `lib/cli.js#_emitCompletions()`
|
||||
# is using.
|
||||
local candidates
|
||||
if [[ ! -f "$cacheFile" ]]; then
|
||||
candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||
else
|
||||
local mtime
|
||||
mtime=$(stat -r "$cacheFile" | awk '{print $10}')
|
||||
local ttl=300 # 5 minutes in seconds
|
||||
local age
|
||||
age=$(echo "$(date +%s) - $mtime" | bc)
|
||||
if [[ $age -gt $ttl ]]; then
|
||||
# Out of date. Regenerate the cache file.
|
||||
trace " cacheFile out-of-date (mtime=$mtime, age=$age, ttl=$ttl)"
|
||||
rm "$cacheFile"
|
||||
candidates=$(TRITON_COMPLETE=$type $COMP_LINE)
|
||||
else
|
||||
trace " cacheFile is in-date (mtime=$mtime, age=$age, ttl=$ttl)"
|
||||
candidates=$(cat "$cacheFile")
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$candidates"
|
||||
}
|
||||
|
||||
function complete_tritonpackage {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata packages)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
function complete_tritonimage {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata images)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
function complete_tritoninstance {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata instances)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
function complete_tritonnetwork {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata networks)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
function complete_tritonfwrule {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata fwrules)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
function complete_tritonkey {
|
||||
local word="$1"
|
||||
candidates=$(_complete_tritondata keys)
|
||||
compgen $compgen_opts -W "$candidates" -- "$word"
|
||||
}
|
||||
|
||||
|
||||
function complete_tritonupdateaccountfield {
|
||||
local word="$1"
|
||||
local candidates
|
||||
|
208
lib/cli.js
208
lib/cli.js
@ -17,6 +17,7 @@ var child_process = require('child_process'),
|
||||
exec = child_process.exec;
|
||||
var cmdln = require('cmdln'),
|
||||
Cmdln = cmdln.Cmdln;
|
||||
var fs = require('fs');
|
||||
var mkdirp = require('mkdirp');
|
||||
var util = require('util'),
|
||||
format = util.format;
|
||||
@ -32,7 +33,7 @@ var tritonapi = require('./tritonapi');
|
||||
|
||||
//---- globals
|
||||
|
||||
var pkg = require('../package.json');
|
||||
var packageJson = require('../package.json');
|
||||
|
||||
var CONFIG_DIR;
|
||||
if (process.platform === 'win32') {
|
||||
@ -198,7 +199,7 @@ cmdln.dashdash.addOptionType({
|
||||
function CLI() {
|
||||
Cmdln.call(this, {
|
||||
name: 'triton',
|
||||
desc: pkg.description,
|
||||
desc: packageJson.description,
|
||||
options: OPTIONS,
|
||||
helpOpts: {
|
||||
includeEnv: true,
|
||||
@ -260,7 +261,7 @@ CLI.prototype.init = function (opts, args, callback) {
|
||||
}
|
||||
|
||||
if (opts.version) {
|
||||
console.log(this.name, pkg.version);
|
||||
console.log(this.name, packageJson.version);
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
@ -298,8 +299,26 @@ CLI.prototype.init = function (opts, args, callback) {
|
||||
return self._tritonapi;
|
||||
});
|
||||
|
||||
// Cmdln class handles `opts.help`.
|
||||
Cmdln.prototype.init.apply(this, arguments);
|
||||
if (process.env.TRITON_COMPLETE) {
|
||||
/*
|
||||
* If `TRITON_COMPLETE=<type>` is set (typically only in the
|
||||
* Triton CLI bash completion driver, see
|
||||
* "etc/triton-bash-completion-types.sh"), then Bash completions are
|
||||
* fetched and printed, instead of the usual subcommand handling.
|
||||
*
|
||||
* Completion results are typically cached (under "~/.triton/cache")
|
||||
* to avoid hitting the server for data everytime.
|
||||
*
|
||||
* Example usage:
|
||||
* TRITON_COMPLETE=images triton -p my-profile create
|
||||
*/
|
||||
this._emitCompletions(process.env.TRITON_COMPLETE, function (err) {
|
||||
callback(err || false);
|
||||
});
|
||||
} else {
|
||||
// Cmdln class handles `opts.help`.
|
||||
Cmdln.prototype.init.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -313,6 +332,185 @@ CLI.prototype.fini = function fini(subcmd, err, cb) {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Fetch and display Bash completions (one completion per line) for the given
|
||||
* Triton data type (e.g. 'images', 'instances', 'packages', ...).
|
||||
* This caches results (per profile) with a 5 minute TTL.
|
||||
*
|
||||
* Dev Note: If the cache path logic changes, then the *Bash* implementation
|
||||
* of the same logic in "etc/triton-bash-completion-types.sh" must be updated
|
||||
* to match.
|
||||
*/
|
||||
CLI.prototype._emitCompletions = function _emitCompletions(type, cb) {
|
||||
assert.string(type, 'type');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var cacheFile = path.join(this.tritonapi.cacheDir, type + '.completions');
|
||||
var ttl = 5 * 60 * 1000; // timeout of cache file info (ms)
|
||||
var cloudapi = this.tritonapi.cloudapi;
|
||||
|
||||
vasync.pipeline({arg: {}, funcs: [
|
||||
function tryCacheFile(arg, next) {
|
||||
fs.stat(cacheFile, function (err, stats) {
|
||||
if (!err &&
|
||||
stats.mtime.getTime() + ttl >= (new Date()).getTime()) {
|
||||
process.stdout.write(fs.readFileSync(cacheFile));
|
||||
next(true); // early abort
|
||||
} else if (err && err.code !== 'ENOENT') {
|
||||
next(err);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
function gather(arg, next) {
|
||||
var completions;
|
||||
|
||||
switch (type) {
|
||||
case 'packages':
|
||||
cloudapi.listPackages({}, function (err, pkgs) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
pkgs.forEach(function (pkg) {
|
||||
if (pkg.name.indexOf(' ') === -1) {
|
||||
// Cannot bash complete results with spaces, so
|
||||
// skip them here.
|
||||
completions.push(pkg.name);
|
||||
}
|
||||
completions.push(pkg.id);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
case 'images':
|
||||
cloudapi.listImages({}, function (err, imgs) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
imgs.forEach(function (img) {
|
||||
// Cannot bash complete results with spaces, so
|
||||
// skip them here.
|
||||
if (img.name.indexOf(' ') === -1) {
|
||||
completions.push(img.name);
|
||||
if (img.version.indexOf(' ') === -1) {
|
||||
completions.push(img.name + '@' + img.version);
|
||||
}
|
||||
}
|
||||
completions.push(img.id);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
case 'instances':
|
||||
cloudapi.listMachines({}, function (err, insts) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
insts.forEach(function (inst) {
|
||||
if (inst.name.indexOf(' ') === -1) {
|
||||
// Cannot bash complete results with spaces, so
|
||||
// skip them here.
|
||||
completions.push(inst.name);
|
||||
}
|
||||
completions.push(inst.id);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
case 'networks':
|
||||
cloudapi.listNetworks({}, function (err, nets) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
nets.forEach(function (net) {
|
||||
if (net.name.indexOf(' ') === -1) {
|
||||
// Cannot bash complete results with spaces, so
|
||||
// skip them here.
|
||||
completions.push(net.name);
|
||||
}
|
||||
completions.push(net.id);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
case 'fwrules':
|
||||
cloudapi.listFirewallRules({}, function (err, fwrules) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
fwrules.forEach(function (fwrule) {
|
||||
completions.push(fwrule.id);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
case 'keys':
|
||||
cloudapi.listKeys({}, function (err, keys) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
completions = [];
|
||||
keys.forEach(function (key) {
|
||||
if (key.name.indexOf(' ') === -1) {
|
||||
// Cannot bash complete results with spaces, so
|
||||
// skip them here.
|
||||
completions.push(key.name);
|
||||
}
|
||||
completions.push(key.fingerprint);
|
||||
});
|
||||
arg.completions = completions.join('\n') + '\n';
|
||||
next();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
process.stderr.write('warning: unknown triton completion type: '
|
||||
+ type + '\n');
|
||||
next();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
function saveCache(arg, next) {
|
||||
if (!arg.completions) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
fs.writeFile(cacheFile, arg.completions, next);
|
||||
},
|
||||
|
||||
function emit(arg, next) {
|
||||
if (arg.completions) {
|
||||
console.log(arg.completions);
|
||||
}
|
||||
next();
|
||||
}
|
||||
]}, function (err) {
|
||||
if (err === true) { // early abort signal
|
||||
err = null;
|
||||
}
|
||||
cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Apply overrides from CLI options to the given profile object *in place*.
|
||||
*/
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton create ...` bwcompat shortcut for `triton instance create ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_create');
|
||||
|
||||
function do_create(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'create',
|
||||
@ -19,6 +21,8 @@ function do_create(subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
do_create.help = 'A shortcut for "triton instance create".';
|
||||
do_create.options = require('./do_instance/do_create').options;
|
||||
do_create.options = targ.options;
|
||||
|
||||
do_create.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_create;
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton delete ...` bwcompat shortcut for `triton instance delete ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_delete');
|
||||
|
||||
function do_delete(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'delete',
|
||||
@ -20,6 +22,7 @@ function do_delete(subcmd, opts, args, callback) {
|
||||
|
||||
do_delete.help = 'A shortcut for "triton instance delete".';
|
||||
do_delete.aliases = ['rm'];
|
||||
do_delete.options = require('./do_instance/do_delete').options;
|
||||
do_delete.options = targ.options;
|
||||
do_delete.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_delete;
|
||||
|
@ -107,4 +107,6 @@ do_delete.help = [
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
do_delete.completionArgtypes = ['tritonfwrule'];
|
||||
|
||||
module.exports = do_delete;
|
||||
|
@ -65,4 +65,6 @@ do_disable.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_disable.completionArgtypes = ['tritonfwrule'];
|
||||
|
||||
module.exports = do_disable;
|
||||
|
@ -65,4 +65,6 @@ do_enable.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_enable.completionArgtypes = ['tritonfwrule'];
|
||||
|
||||
module.exports = do_enable;
|
||||
|
@ -73,4 +73,6 @@ do_get.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_get.completionArgtypes = ['tritonfwrule', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -159,4 +159,6 @@ do_instances.help = [
|
||||
|
||||
do_instances.aliases = ['insts'];
|
||||
|
||||
do_instances.completionArgtypes = ['tritonfwrule', 'none'];
|
||||
|
||||
module.exports = do_instances;
|
||||
|
@ -265,5 +265,6 @@ do_create.helpOpts = {
|
||||
maxHelpCol: 20
|
||||
};
|
||||
|
||||
do_create.completionArgtypes = ['tritoninstance', 'file'];
|
||||
|
||||
module.exports = do_create;
|
||||
|
@ -151,5 +151,7 @@ do_delete.options = [
|
||||
}
|
||||
];
|
||||
|
||||
do_delete.completionArgtypes = ['tritonimage'];
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
module.exports = do_delete;
|
||||
|
@ -67,4 +67,6 @@ do_get.help = (
|
||||
/* END JSSTYLED */
|
||||
);
|
||||
|
||||
do_get.completionArgtypes = ['tritonimage', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -116,13 +116,14 @@ do_wait.help = [
|
||||
'Wait for images to change to a particular state.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} wait [-s STATES] IMAGE [IMAGE ...]',
|
||||
' {{name}} wait [-s STATES] IMAGE [IMAGE ...]',
|
||||
'',
|
||||
'{{options}}',
|
||||
'Where "states" is a comma-separated list of target instance states,',
|
||||
'by default "active,failed". In other words, "triton img wait foo0" will',
|
||||
'wait for image "foo0" to complete creation.'
|
||||
].join('\n');
|
||||
|
||||
do_wait.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
@ -139,4 +140,6 @@ do_wait.options = [
|
||||
}
|
||||
];
|
||||
|
||||
do_wait.completionArgtypes = ['tritonimage'];
|
||||
|
||||
module.exports = do_wait;
|
||||
|
@ -111,4 +111,6 @@ do_audit.help = (
|
||||
+ '{{options}}'
|
||||
);
|
||||
|
||||
do_audit.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_audit;
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Joyent, Inc.
|
||||
* Copyright 2016 Joyent, Inc.
|
||||
*
|
||||
* `triton instance create ...`
|
||||
*/
|
||||
@ -289,7 +289,8 @@ do_create.options = [
|
||||
type: 'arrayOfCommaSepString',
|
||||
helpArg: 'NETWORK',
|
||||
help: 'One or more comma-separated networks (ID, name or short id). ' +
|
||||
'This option can be used multiple times.'
|
||||
'This option can be used multiple times.',
|
||||
completionType: 'tritonnetwork'
|
||||
},
|
||||
|
||||
// XXX locality: near, far
|
||||
@ -330,5 +331,6 @@ do_create.helpOpts = {
|
||||
maxHelpCol: 18
|
||||
};
|
||||
|
||||
do_create.completionArgtypes = ['tritonimage', 'tritonpackage', 'none'];
|
||||
|
||||
module.exports = do_create;
|
||||
|
@ -100,4 +100,6 @@ do_fwrules.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_fwrules.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_fwrules;
|
||||
|
@ -60,4 +60,6 @@ do_get.help = (
|
||||
/* END JSSTYLED */
|
||||
);
|
||||
|
||||
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -133,4 +133,6 @@ do_create.help = [
|
||||
'Snapshot do not work for instances of type "kvm".'
|
||||
].join('\n');
|
||||
|
||||
do_create.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_create;
|
||||
|
@ -150,4 +150,8 @@ do_delete.help = [
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
// TODO: When have 'tritonsnapshot' completion, then use this:
|
||||
// do_get.completionArgtypes = ['tritoninstance', 'tritonsnapshot'];
|
||||
do_delete.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_delete;
|
||||
|
@ -77,4 +77,8 @@ do_get.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
// TODO: When have 'tritonsnapshot' completion, then use this:
|
||||
// do_get.completionArgtypes = ['tritoninstance', 'tritonsnapshot', 'none'];
|
||||
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -93,6 +93,8 @@ do_list.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_list.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
do_list.aliases = ['ls'];
|
||||
|
||||
module.exports = do_list;
|
||||
|
@ -86,4 +86,8 @@ do_ssh.help = (
|
||||
|
||||
do_ssh.interspersedOptions = false;
|
||||
|
||||
// Use 'file' to fallback to the default bash completion... even though 'file'
|
||||
// isn't quite right.
|
||||
do_ssh.completionArgtypes = ['tritoninstance', 'file'];
|
||||
|
||||
module.exports = do_ssh;
|
||||
|
@ -109,4 +109,6 @@ do_delete.help = [
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
do_delete.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_delete;
|
||||
|
@ -65,4 +65,7 @@ do_get.help = [
|
||||
/* END JSSTYLED */
|
||||
].join('\n');
|
||||
|
||||
// TODO: When have 'tritoninstancetag' completion, add that in.
|
||||
do_get.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -66,4 +66,6 @@ do_list.help = [
|
||||
|
||||
do_list.aliases = ['ls'];
|
||||
|
||||
do_list.completionArgtypes = ['tritoninstance', 'none'];
|
||||
|
||||
module.exports = do_list;
|
||||
|
@ -129,4 +129,6 @@ do_replace_all.help = [
|
||||
/* END JSSTYLED */
|
||||
].join('\n');
|
||||
|
||||
do_replace_all.completionArgtypes = ['tritoninstance', 'file'];
|
||||
|
||||
module.exports = do_replace_all;
|
||||
|
@ -130,4 +130,6 @@ do_set.help = [
|
||||
/* END JSSTYLED */
|
||||
].join('\n');
|
||||
|
||||
do_set.completionArgtypes = ['tritoninstance', 'file'];
|
||||
|
||||
module.exports = do_set;
|
||||
|
@ -137,4 +137,6 @@ do_wait.options = [
|
||||
}
|
||||
];
|
||||
|
||||
do_wait.completionArgtypes = ['tritoninstance'];
|
||||
|
||||
module.exports = do_wait;
|
||||
|
@ -66,6 +66,8 @@ function gen_do_ACTION(opts) {
|
||||
}
|
||||
];
|
||||
|
||||
do_ACTION.completionArgtypes = ['tritoninstance'];
|
||||
|
||||
if (action === 'start') {
|
||||
do_ACTION.options.push({
|
||||
names: ['snapshot'],
|
||||
|
@ -116,4 +116,6 @@ do_delete.help = [
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
do_delete.completionArgtypes = ['tritonkey'];
|
||||
|
||||
module.exports = do_delete;
|
||||
|
@ -77,4 +77,6 @@ do_get.help = [
|
||||
'Where "KEY" is an SSH key "name" or "fingerprint".'
|
||||
].join('\n');
|
||||
|
||||
do_get.completionArgtypes = ['tritonkey', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -60,4 +60,6 @@ do_get.help = (
|
||||
+ '{{options}}'
|
||||
);
|
||||
|
||||
do_get.completionArgtypes = ['tritonnetwork', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -66,4 +66,6 @@ do_get.help = (
|
||||
/* END JSSTYLED */
|
||||
);
|
||||
|
||||
do_get.completionArgtypes = ['tritonpackage', 'none'];
|
||||
|
||||
module.exports = do_get;
|
||||
|
@ -129,6 +129,7 @@ do_delete.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_delete.completionArgtypes = ['tritonprofile', 'none'];
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
|
@ -163,5 +163,6 @@ do_edit.help = [
|
||||
'{{options}}'
|
||||
].join('\n');
|
||||
|
||||
do_edit.completionArgtypes = ['tritonprofile', 'none'];
|
||||
|
||||
module.exports = do_edit;
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton reboot ...` bwcompat shortcut for `triton instance reboot ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_reboot');
|
||||
|
||||
function do_reboot(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'reboot',
|
||||
@ -19,6 +21,7 @@ function do_reboot(subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
do_reboot.help = 'A shortcut for "triton instance reboot".';
|
||||
do_reboot.options = require('./do_instance/do_reboot').options;
|
||||
do_reboot.options = targ.options;
|
||||
do_reboot.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_reboot;
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton ssh ...` bwcompat shortcut for `triton instance ssh ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_ssh');
|
||||
|
||||
function do_ssh(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'ssh',
|
||||
@ -19,6 +21,7 @@ function do_ssh(subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
do_ssh.help = 'A shortcut for "triton instance ssh".';
|
||||
do_ssh.options = require('./do_instance/do_ssh').options;
|
||||
do_ssh.options = targ.options;
|
||||
do_ssh.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_ssh;
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton start ...` bwcompat shortcut for `triton instance start ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_start');
|
||||
|
||||
function do_start(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'start',
|
||||
@ -19,6 +21,7 @@ function do_start(subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
do_start.help = 'A shortcut for "triton instance start".';
|
||||
do_start.options = require('./do_instance/do_start').options;
|
||||
do_start.options = targ.options;
|
||||
do_start.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_start;
|
||||
|
@ -10,6 +10,8 @@
|
||||
* `triton stop ...` bwcompat shortcut for `triton instance stop ...`.
|
||||
*/
|
||||
|
||||
var targ = require('./do_instance/do_stop');
|
||||
|
||||
function do_stop(subcmd, opts, args, callback) {
|
||||
this.handlerFromSubcmd('instance').dispatch({
|
||||
subcmd: 'stop',
|
||||
@ -19,6 +21,7 @@ function do_stop(subcmd, opts, args, callback) {
|
||||
}
|
||||
|
||||
do_stop.help = 'A shortcut for "triton instance stop".';
|
||||
do_stop.options = require('./do_instance/do_stop').options;
|
||||
do_stop.options = targ.options;
|
||||
do_stop.completionArgtypes = targ.completionArgtypes;
|
||||
|
||||
module.exports = do_stop;
|
||||
|
@ -1271,7 +1271,7 @@ function waitForInstanceTagChanges(opts, cb) {
|
||||
if (elapsedTime > timeout) {
|
||||
cb(new errors.TimeoutError(format('timeout waiting for '
|
||||
+ 'tag changes on instance %s (elapsed %ds)',
|
||||
opts.id, Math.round(elapsedTime * 1000))));
|
||||
opts.id, Math.round(elapsedTime / 1000))));
|
||||
} else {
|
||||
setTimeout(poll, POLL_INTERVAL);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "triton",
|
||||
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
||||
"version": "4.6.1",
|
||||
"version": "4.7.0",
|
||||
"author": "Joyent (joyent.com)",
|
||||
"dependencies": {
|
||||
"assert-plus": "0.2.0",
|
||||
|
Reference in New Issue
Block a user