Skip to content

Commit

Permalink
Improved CLI features
Browse files Browse the repository at this point in the history
  • Loading branch information
thejhh committed May 17, 2012
1 parent d43efc1 commit a3876ef
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 80 deletions.
77 changes: 68 additions & 9 deletions cli.js
@@ -1,20 +1,79 @@
/* Builder for simple command line utils */
var cli = module.exports = {};

// FIXME: 'help domain list' does not work but 'domain list help' works
// FIXME: usage lines on cli do not show the parent command names

var cli = module.exports = {},
foreach = require('snippets').foreach;
wrap = require('wordwrap')(79);

cli.init_commands = function(commands, name, parents) {
if( (!commands.hasOwnProperty("__parents__")) && (parents !== undefined) ) {
commands['__parents__'] = [];
foreach(parents).each(function(value) {
commands['__parents__'].push(value);
});
}
if( (!commands.hasOwnProperty("__name__")) && (name !== undefined) ) {
commands['__name__'] = name;
}
if( (!commands.hasOwnProperty("help")) && commands.hasOwnProperty('__desc__') ) {
commands.help = function() {
var opts = [];
if(commands.hasOwnProperty('__opts__')) {
foreach(commands['__opts__']).each(function(value, key) {
opts.push('[--' + key + '=VALUE]');
});
}
var usage = 'usage: ' + commands['__parents__'].join(' ') + ( (commands['__parents__'].length===0) ? '' : ' ') + opts.join(' ');
console.log(wrap(usage));
console.log('');
console.log(wrap(commands['__desc__']));
if(commands.hasOwnProperty('__opts__')) {
console.log('');
console.log('with options:');
foreach(commands['__opts__']).each(function(value, key) {
console.log(wrap( ' ' + key + ' - ' + value ));
});
}
};
}
return commands;
};

/* Core implementation for CLI applications */
cli.run = function(commands) {
cli.run = function(commands_root) {
var optimist = require('optimist'),
argv = optimist
.usage('Usage: $0 COMMAND [argument(s)]')
.argv,
name = argv._.shift(),
fn = commands[name];
if(fn && commands.hasOwnProperty(name) && (typeof fn === 'function')) {
commands[name].apply(commands, argv._);
} else {
console.error('Error: Unknown command: ' + name);
optimist.showHelp();
parents = [];

parents.push( argv.$0 );

function sub_run(commands) {
var name = argv._.shift();
parents.push(name);

// Handle root command
if( (!commands.hasOwnProperty(name)) && commands.hasOwnProperty('_root_') && commands['_root_'] && (typeof commands['_root_'] === 'function') ) {
argv._.unshift(name);
commands['_root_'].apply(commands, argv._);
// Handle direct function callback
} else if(commands.hasOwnProperty(name) && commands[name] && (typeof commands[name] === 'function')) {
commands[name].apply(commands, argv._);
// Handle object with multiple sub callbacks
} else if(commands.hasOwnProperty(name) && commands[name] && (typeof commands[name] === 'object')) {
cli.init_commands(commands[name], name, parents);
sub_run(commands[name]);
} else {
console.error('Error: Unknown command: ' + name);
optimist.showHelp();
}
}

commands_root = cli.init_commands(commands_root);
sub_run(commands_root);
}

/* EOF */
205 changes: 135 additions & 70 deletions joker.js
Expand Up @@ -5,20 +5,26 @@
*/

/*
* API documentation:
* Joker.com API documentation:
* https://dmapi.joker.com/docs/DMAPI-ext.txt
*/

// FIXME: Change filedb so that it doesn't save backups or it can be opted out

function is_func(f) {
if(f && (typeof f === 'function')) return true;
return false;
}

var commands = module.exports = {},
basedir = process.env.HOME || __dirname,
db = require('filedb').config({'keep_backup':false}).open(basedir + '/.joker-cli.json'),
foreach = require('snippets').foreach,
rpad = require('snippets').rpad,
dmapi = require('joker-dmapi');

// FIXME: Change filedb so that it doesn't save backups or it can be opted out
dmapi = require('joker-dmapi'),
cli = require('./cli.js');

commands._opts = {'verbose': 0};
commands._opts_ = {'verbose': 0};

/* Event when database becomes ready */
db.on('ready', function() {
Expand All @@ -28,82 +34,106 @@ db.on('ready', function() {

/* */
dmapi.on('error', function(err) {
console.log("Error: " + err);
console.error("Error: " + err);
});

if(db.auth && db.auth.id && db.auth.date && ((new Date()).getTime() - db.auth.date < 58*60*1000 ) ) {
dmapi.config({'auth_id':db.auth.id});
} else {
delete db.auth;
db.commit(function(err) { if(err) console.log('error when saving data: ' + err);});
db.commit(function(err) { if(err) console.error('error when saving data: ' + err);});
}
});

/* Help command */
commands.help = function() {
console.log('Commands:');
console.log(' config list -- list configuration');
console.log(' config set KEY=VALUE -- set configuration');
console.log(' status -- get session status');
console.log(' login USER PW -- login to DMAPI');
console.log(' logout -- logout');
console.log(' query-domain-list -- list domains');
commands.help = function(command) {
if(command && commands.hasOwnProperty(command)) {
cli.init_commands(commands[command], command);
if(is_func(commands[command].help)) {
commands[command].help();
} else {
console.log("I'm sorry. This command does not have detailed help available.");
}
} else {
console.log('usage: [--help] COMMAND [ARGS]');
console.log("");
console.log('The commands are:');
console.log(' config Change settings');
console.log(' status Get session status');
console.log(' login Login to reseller interface');
console.log(' logout Logout from reseller interface');
console.log(' domain Manage domains');
console.log("");
console.log("See 'joker help COMMAND' for more information on a specific command.");
}
};

/* List domains */
commands['status'] = function() {
db.whenReady(function() {
var now = new Date(),
seconds = (db && db.auth && db.auth.date) ? (now.getTime() - db.auth.date) / 1000 : undefined;
if(db.auth && db.auth.id && db.auth.date && (seconds < 58*60 ) ) {
console.log("Joker: online (" + Math.floor(58*60-seconds) + " seconds left)");
} else {
console.log("Joker: offline");
if(commands._opts.verbose >= 1) {
console.log('DEBUG: seconds = ' + seconds);
if(db && db.auth && db.auth.date) console.log('DEBUG: db.auth.date = ' + db.auth.date);
if(db && db.auth) console.log('DEBUG: db.auth = ' + db.auth);
commands['status'] = {
'__title__': "Get session status",
'__desc__': "Print status of joker.com's reseller session (DMAPI).",
'_root_': function() {
db.whenReady(function() {
var now = new Date(),
seconds = (db && db.auth && db.auth.date) ? (now.getTime() - db.auth.date) / 1000 : undefined;
if(db.auth && db.auth.id && db.auth.date && (seconds < 58*60 ) ) {
console.log("Joker: online (" + Math.floor(58*60-seconds) + " seconds left)");
} else {
console.log("Joker: offline");
if(commands._opts.verbose >= 1) {
console.log('DEBUG: seconds = ' + seconds);
if(db && db.auth && db.auth.date) console.log('DEBUG: db.auth.date = ' + db.auth.date);
if(db && db.auth) console.log('DEBUG: db.auth = ' + db.auth);
}
}
}
});
});
}
};

/* login -- */
commands['login'] = function(username, password) {
db.whenReady(function() {
dmapi.login({'hostname':db.hostname, 'username':username, 'password':password}, function(err, res) {
if(err) {
console.log('Error: ' + err);
return;
}
db.auth = {};
db.auth.date = (new Date()).getTime();
db.auth.id = res.auth_id;
db.commit(function(err) { if(err) console.log('error when saving data: ' + err);});
console.log('Logged in!');
if(commands._opts.verbose >= 1) {
console.log('DEBUG: auth_id = ' + res.auth_id);
}
commands['login'] = {
'__title__': "Login to DMAPI",
'__desc__': "Login to joker.com's reseller interface (DMAPI).",
'_root_': function(username, password) {
db.whenReady(function() {
dmapi.login({'hostname':db.hostname, 'username':username, 'password':password}, function(err, res) {
if(err) {
console.error('Error: ' + err);
return;
}
db.auth = {};
db.auth.date = (new Date()).getTime();
db.auth.id = res.auth_id;
db.commit(function(err) { if(err) console.error('error when saving data: ' + err);});
console.log('Logged in!');
if(commands._opts.verbose >= 1) {
console.log('DEBUG: auth_id = ' + res.auth_id);
}
});
});
});
}
};

/* logout -- */
commands['logout'] = function() {
db.whenReady(function() {
dmapi.logout(function(err) {
if(err) {
console.log('Error: ' + err);
return;
}
db.auth = undefined;
db.commit(function(err) { if(err) console.log('error when saving data: ' + err);});
console.log('Logged out!');
if(commands._opts.verbose >= 1) {
console.log('DEBUG: auth_id = ' + res.auth_id);
}
commands['logout'] = {
'__title__': "Logout from DMAPI",
'__desc__': "Logout from joker.com's reseller interface (DMAPI).",
'_root_': function() {
db.whenReady(function() {
dmapi.logout(function(err) {
if(err) {
console.error('Error: ' + err);
return;
}
db.auth = undefined;
db.commit(function(err) { if(err) console.error('error when saving data: ' + err);});
console.log('Logged out!');
if(commands._opts.verbose >= 1) {
console.log('DEBUG: auth_id = ' + res.auth_id);
}
});
});
});
}
};


Expand All @@ -114,16 +144,31 @@ commands['logout'] = function() {
/* result-delete -- */

/* query-domain-list -- List domains */
commands['query-domain-list'] = function() {
db.whenReady(function() {
dmapi.queryDomainList({}, function(err, domains) {
if(err) {
console.log('Error: ' + err);
return;
}
console.log(domains);
});
});
commands['domain'] = {
'__title__': "Manage domains",
'__desc__': "Try 'domain list' to list your domains.",
'list': {
'__title__': "List domains",
'__desc__': 'List of registered domains and their expiration dates (one per line, separated by whitespace). If "showstatus" is present, the the list will be with three columns, the last one showing domain status (like "lock,autorenew" etc - comma separated).',
'__opts__': {
'pattern': 'Pattern to match (glob-like)',
'from': 'Start from this item in list',
'to': 'End by this',
'showstatus': 'Add additional column, showing domain status, may be 0 or 1.',
'showgrants': 'Add additional column, showing domain grants, may be 0 or 1.'
},
'_root_': function() {
db.whenReady(function() {
dmapi.queryDomainList({}, function(err, domains) {
if(err) {
console.error('Error: ' + err);
return;
}
console.log(domains);
});
});
}
}
};

/* TODO: query-contact-list -- */
Expand Down Expand Up @@ -155,7 +200,27 @@ commands['query-domain-list'] = function() {
/* TODO: dns-zone-get -- */
/* TODO: dns-zone-put -- */

/* */
commands['_root_'] = function() {
console.log("Try 'joker help'.");
};

/* echo */
commands['echo'] = {
'__title__': "Echo arguments",
'__desc__': "Test command for CLI code.",
'_root_': function() {
if(this['__name__']) {
console.log('Command: ' + this['__name__']);
}
console.log('Arguments: ');
for(var i = 0; i< arguments.length; ++i) {
console.log(arguments[i]);
}
}
}

/* Run the framework */
require('./cli.js').run(commands);
cli.run(commands);

/* EOF */
5 changes: 4 additions & 1 deletion package.json
Expand Up @@ -15,6 +15,9 @@
"filedb": "https://github.com/jheusala/node-filedb/tarball/master",
"joker-dmapi": "https://github.com/jheusala/node-joker-dmapi/tarball/master"
},
"devDependencies": {},
"devDependencies": {
"snippets": "*",
"wordwrap": "*"
},
"optionalDependencies": {}
}

0 comments on commit a3876ef

Please sign in to comment.