style: triton img ...

This commit is contained in:
Trent Mick 2015-12-30 13:11:57 -08:00
parent 559162896f
commit 632d5a6568
8 changed files with 233 additions and 155 deletions

View File

@ -206,7 +206,6 @@ function CLI() {
'wait-instance', 'wait-instance',
'ssh', 'ssh',
{ group: 'Images, Packages, Networks' }, { group: 'Images, Packages, Networks' },
'images',
'image', 'image',
'package', 'package',
'networks', 'networks',

View File

@ -7,15 +7,15 @@
/* /*
* Copyright 2015 Joyent, Inc. * Copyright 2015 Joyent, Inc.
* *
* `triton image ...` * `triton image get ...`
*/ */
var format = require('util').format; var format = require('util').format;
var errors = require('./errors'); var errors = require('../errors');
function do_image(subcmd, opts, args, callback) { function do_get(subcmd, opts, args, callback) {
if (opts.help) { if (opts.help) {
this.do_help('help', {}, [subcmd], callback); this.do_help('help', {}, [subcmd], callback);
return; return;
@ -24,7 +24,7 @@ function do_image(subcmd, opts, args, callback) {
'incorrect number of args (%d)', args.length))); 'incorrect number of args (%d)', args.length)));
} }
this.tritonapi.getImage(args[0], function onRes(err, img) { this.top.tritonapi.getImage(args[0], function onRes(err, img) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@ -38,7 +38,7 @@ function do_image(subcmd, opts, args, callback) {
}); });
} }
do_image.options = [ do_get.options = [
{ {
names: ['help', 'h'], names: ['help', 'h'],
type: 'bool', type: 'bool',
@ -50,16 +50,16 @@ do_image.options = [
help: 'JSON stream output.' help: 'JSON stream output.'
} }
]; ];
do_image.help = ( do_get.help = (
/* BEGIN JSSTYLED */ /* BEGIN JSSTYLED */
'Get an image.\n' + 'Get an image.\n' +
'\n' + '\n' +
'Usage:\n' + 'Usage:\n' +
' {{name}} image [<options>] ID|NAME\n' + ' {{name}} image get [<options>] ID|NAME\n' +
'\n' + '\n' +
'{{options}}' + '{{options}}' +
'\n' + '\n' +
'If there are more than one image with the given "NAME", the latest\n' + 'If there is more than one image with the given "NAME", the latest\n' +
'image (by "published_at") is returned.\n' + 'image (by "published_at") is returned.\n' +
'\n' + '\n' +
'Note: Currently this dumps prettified JSON by default. That might change\n' + 'Note: Currently this dumps prettified JSON by default. That might change\n' +
@ -67,6 +67,4 @@ do_image.help = (
/* END JSSTYLED */ /* END JSSTYLED */
); );
do_image.aliases = ['img']; module.exports = do_get;
module.exports = do_image;

158
lib/do_image/do_list.js Normal file
View File

@ -0,0 +1,158 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
* Copyright 2015 Joyent, Inc.
*
* `triton image list ...`
*/
var format = require('util').format;
var tabula = require('tabula');
var common = require('../common');
var errors = require('../errors');
// filters to pass triton.listImages
var validFilters = [
'name',
'os',
'version',
'public',
'state',
'owner',
'type'
];
// columns default without -o
var columnsDefault = 'shortid,name,version,state,flags,os,pubdate';
// columns default with -l
var columnsDefaultLong = 'id,name,version,state,flags,os,pubdate';
// sort default with -s
var sortDefault = 'published_at';
function do_list(subcmd, opts, args, callback) {
if (opts.help) {
this.do_help('help', {}, [subcmd], callback);
return;
}
var columns = columnsDefault;
if (opts.o) {
columns = opts.o;
} else if (opts.long) {
columns = columnsDefaultLong;
}
columns = columns.split(',');
var sort = opts.s.split(',');
var listOpts;
try {
listOpts = common.kvToObj(args, validFilters);
} catch (e) {
callback(e);
return;
}
if (opts.all) {
listOpts.state = 'all';
}
this.top.tritonapi.listImages(listOpts, function onRes(err, imgs, res) {
if (err) {
return callback(err);
}
if (opts.json) {
// XXX we should have a common method for all these:
// XXX sorting
// XXX if opts.o is given, then filter to just those fields?
common.jsonStream(imgs);
} else {
// Add some convenience fields
// Added fields taken from imgapi-cli.git.
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
img.shortid = img.id.split('-', 1)[0];
if (img.published_at) {
// Just the date.
img.pubdate = img.published_at.slice(0, 10);
// Normalize on no milliseconds.
img.pub = img.published_at.replace(/\.\d+Z$/, 'Z');
}
if (img.files && img.files[0]) {
img.size = img.files[0].size;
}
var flags = [];
if (img.origin) flags.push('I');
if (img['public']) flags.push('P');
if (img.state !== 'active') flags.push('X');
img.flags = flags.length ? flags.join('') : undefined;
}
tabula(imgs, {
skipHeader: opts.H,
columns: columns,
sort: sort
});
}
callback();
});
}
do_list.options = [
{
names: ['help', 'h'],
type: 'bool',
help: 'Show this help.'
},
{
group: 'Filtering options'
},
{
names: ['all', 'a'],
type: 'bool',
help: 'List all images, not just "active" ones. This ' +
'is a shortcut for the "state=all" filter.'
}
].concat(common.getCliTableOptions({
includeLong: true,
sortDefault: sortDefault
}));
do_list.help = (
/* BEGIN JSSTYLED */
'List images.\n' +
'\n' +
'Usage:\n' +
' {{name}} image list [<options>] [<filters>]\n' +
'\n' +
'{{options}}' +
'\n' +
'Filters:\n' +
' FIELD=VALUE Field equality filter. Supported fields: \n' +
' account, owner, state, name, os, and type.\n' +
' FIELD=true|false Field boolean filter. Supported fields: public.\n' +
' FIELD=~SUBSTRING Field substring filter. Supported fields: name\n' +
'\n' +
'Fields (most are self explanatory, the client adds some for convenience):\n' +
' shortid A short ID prefix.\n' +
' flags This is a set of single letter flags\n' +
' summarizing some fields. "P" indicates the\n' +
' image is public. "I" indicates an incremental\n' +
' image (i.e. has an origin). "X" indicates an\n' +
' image with a state *other* than "active".\n' +
' pubdate Short form of "published_at" with just the date\n' +
' pub Short form of "published_at" elliding milliseconds.\n' +
' size The number of bytes of the image file (files.0.size)\n'
/* END JSSTYLED */
);
do_list.aliases = ['ls'];
module.exports = do_list;

52
lib/do_image/index.js Normal file
View File

@ -0,0 +1,52 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
* Copyright 2015 Joyent, Inc.
*
* `triton image ...`
*/
var Cmdln = require('cmdln').Cmdln;
var util = require('util');
// ---- CLI class
function ImageCLI(top) {
this.top = top;
Cmdln.call(this, {
name: top.name + ' image',
/* BEGIN JSSTYLED */
desc: [
'List, get, create and update Triton images.'
].join('\n'),
/* END JSSTYLED */
helpOpts: {
minHelpCol: 24 /* line up with option help */
},
helpSubcmds: [
'help',
'list',
'get'
]
});
}
util.inherits(ImageCLI, Cmdln);
ImageCLI.prototype.init = function init(opts, args, cb) {
this.log = this.top.log;
Cmdln.prototype.init.apply(this, arguments);
};
ImageCLI.prototype.do_list = require('./do_list');
ImageCLI.prototype.do_get = require('./do_get');
ImageCLI.aliases = ['img'];
module.exports = ImageCLI;

View File

@ -7,152 +7,23 @@
/* /*
* Copyright 2015 Joyent, Inc. * Copyright 2015 Joyent, Inc.
* *
* `triton images ...` * `triton images ...` bwcompat shortcut for `triton images list ...`.
*/ */
var format = require('util').format;
var tabula = require('tabula');
var common = require('./common');
var errors = require('./errors');
// filters to pass triton.listImages
var validFilters = [
'name',
'os',
'version',
'public',
'state',
'owner',
'type'
];
// columns default without -o
var columnsDefault = 'shortid,name,version,state,flags,os,pubdate';
// columns default with -l
var columnsDefaultLong = 'id,name,version,state,flags,os,pubdate';
// sort default with -s
var sortDefault = 'published_at';
function do_images(subcmd, opts, args, callback) { function do_images(subcmd, opts, args, callback) {
if (opts.help) { var subcmdArgv = ['node', 'triton', 'image', 'list'].concat(args);
this.do_help('help', {}, [subcmd], callback); this.dispatch('image', subcmdArgv, callback);
return;
} }
var columns = columnsDefault; do_images.help = [
if (opts.o) { 'A shortcut for "triton image list".',
columns = opts.o; '',
} else if (opts.long) { 'Usage:',
columns = columnsDefaultLong; ' {{name}} images ...'
} ].join('\n');
columns = columns.split(',');
var sort = opts.s.split(',');
var listOpts;
try {
listOpts = common.kvToObj(args, validFilters);
} catch (e) {
callback(e);
return;
}
if (opts.all) {
listOpts.state = 'all';
}
this.tritonapi.listImages(listOpts, function onRes(err, imgs, res) {
if (err) {
return callback(err);
}
if (opts.json) {
// XXX we should have a common method for all these:
// XXX sorting
// XXX if opts.o is given, then filter to just those fields?
common.jsonStream(imgs);
} else {
// Add some convenience fields
// Added fields taken from imgapi-cli.git.
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
img.shortid = img.id.split('-', 1)[0];
if (img.published_at) {
// Just the date.
img.pubdate = img.published_at.slice(0, 10);
// Normalize on no milliseconds.
img.pub = img.published_at.replace(/\.\d+Z$/, 'Z');
}
if (img.files && img.files[0]) {
img.size = img.files[0].size;
}
var flags = [];
if (img.origin) flags.push('I');
if (img['public']) flags.push('P');
if (img.state !== 'active') flags.push('X');
img.flags = flags.length ? flags.join('') : undefined;
}
tabula(imgs, {
skipHeader: opts.H,
columns: columns,
sort: sort
});
}
callback();
});
}
do_images.options = [
{
names: ['help', 'h'],
type: 'bool',
help: 'Show this help.'
},
{
group: 'Filtering options'
},
{
names: ['all', 'a'],
type: 'bool',
help: 'List all images, not just "active" ones. This ' +
'is a shortcut for the "state=all" filter.'
}
].concat(common.getCliTableOptions({
includeLong: true,
sortDefault: sortDefault
}));
do_images.help = (
/* BEGIN JSSTYLED */
'List images.\n' +
'\n' +
'Usage:\n' +
' {{name}} images [<options>] [<filters>]\n' +
'\n' +
'{{options}}' +
'\n' +
'Filters:\n' +
' FIELD=VALUE Field equality filter. Supported fields: \n' +
' account, owner, state, name, os, and type.\n' +
' FIELD=true|false Field boolean filter. Supported fields: public.\n' +
' FIELD=~SUBSTRING Field substring filter. Supported fields: name\n' +
'\n' +
'Fields (most are self explanatory, the client adds some for convenience):\n' +
' shortid A short ID prefix.\n' +
' flags This is a set of single letter flags\n' +
' summarizing some fields. "P" indicates the\n' +
' image is public. "I" indicates an incremental\n' +
' image (i.e. has an origin). "X" indicates an\n' +
' image with a state *other* than "active".\n' +
' pubdate Short form of "published_at" with just the date\n' +
' pub Short form of "published_at" elliding milliseconds.\n' +
' size The number of bytes of the image file (files.0.size)\n'
/* END JSSTYLED */
);
do_images.aliases = ['imgs']; do_images.aliases = ['imgs'];
do_images.hidden = true;
module.exports = do_images; module.exports = do_images;

View File

@ -55,7 +55,7 @@ do_get.help = (
'Get a package.\n' + 'Get a package.\n' +
'\n' + '\n' +
'Usage:\n' + 'Usage:\n' +
' {{name}} package [<options>] ID|NAME\n' + ' {{name}} package get [<options>] ID|NAME\n' +
'\n' + '\n' +
'{{options}}' + '{{options}}' +
'\n' + '\n' +

View File

@ -159,7 +159,7 @@ do_list.help = [
'List packgaes.', 'List packgaes.',
'', '',
'Usage:', 'Usage:',
' {{name}} packages [<filters>]', ' {{name}} package list [<filters>]',
'', '',
'{{options}}', '{{options}}',
'Filters:', 'Filters:',

View File

@ -100,7 +100,7 @@ test('triton manage workflow', opts, function (tt) {
'minimal-32': true, 'minimal-32': true,
'base': true 'base': true
}; };
h.safeTriton(t, ['imgs', '-j'], function (stdout) { h.safeTriton(t, ['img', 'ls', '-j'], function (stdout) {
var imgs = _jsonStreamParse(stdout); var imgs = _jsonStreamParse(stdout);
// Newest images first. // Newest images first.
tabula.sortArrayOfObjects(imgs, ['-published_at']); tabula.sortArrayOfObjects(imgs, ['-published_at']);