/*!
* Copyright (C) 2010-2015 by Revolution Analytics Inc.
*
* This program is licensed to you under the terms of Version 2.0 of the
* Apache License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0) for more
* details.
*/
'use strict';
/**
* The DeployR command line interface, a tool for running useful DeployR
* utilities.
* @module deployr-cli
*/
var path = require('path'),
opn = require('opn'),
flatiron = require('flatiron'),
clear = require('./lib/util/clear');
/**
* @alias module:deployr-cli
*/
var di = module.exports = flatiron.app;
/**
* Expose the CLI name _di_.
* @property {String} name - The CLI name.
*/
di.name = 'di';
//
// Setup `di` to use `pkginfo` to expose version,
//
require('pkginfo')(module, 'name', 'version');
//
// Configure `di` to use `flatiron.plugins.cli`
//
di.use(flatiron.plugins.cli, {
version: true,
usage: require('./lib/usage'),
source: path.join(__dirname, 'lib', 'commands'),
argv: {
version: {
alias: 'v',
description: 'prints DeployR version and exit',
string: true
},
diconf: {
alias: 'j',
description: 'specify file to load configuration from',
string: true
},
help: {
alias: 'h',
description: 'prints cli help and exit',
string: true
}
}
});
//
// Configure `di` to use `cli-inquirer` for more sophisticated prompts.
//
di.use(require('./lib/plugins/inquirer'));
//
// Setup `di` with: config, command aliases settings
//
di.chalk = require('chalk');
di._ = require('lodash');
di.brand = require('./lib/util/brand');
di.spawnCommand = require('./lib/util/spawn-command');
require('./lib/config');
require('./lib/alias');
require('./lib/commands');
//
// Setup other di settings.
//
di.started = false;
di.displayExit = true;
di.noop = function() {};
/**
* Starts the di CLI and runs the specified command.
*
* @param {Function} callback - Continuation to pass control to when complete.
*/
di.start = function(callback) {
//
// whoami command should not output anything but username
//
if (di.argv._[0] === 'whoami') {
di.displayExit = false;
console.log(di.config.get('username') || '');
return;
}
di.init(function(err) {
if (err) {
di.showError(di.argv._.join(' '), err);
return callback(err);
}
// intercept `--help, -h` help options
di.argv._ = di.argv.help ? ['help'] : di.argv._;
// `di` with no command or options routes to `home`
if (!di.argv._[0]) {
di.home();
} else {
return di.exec(di.argv._, callback);
}
});
};
/**
* Runs the specified command in the `di` CLI.
*
* @param {String} command - Command to execute
* @param {Function} callback - Continuation to pass control to when complete.
*/
di.exec = function(command, callback) {
function execCommand(err) {
if (err) {
return callback(err);
}
di.displayExit = false;
di.router.dispatch('on', command.join(' '), di.log, function(err, shallow) {
if (err) {
di.showError(command.join(' '), err, shallow);
return callback(err);
}
callback();
});
}
return !di.started ? di.setup(execCommand) : execCommand();
};
/**
* Sets up the instances of the Resource clients for di.
* there is no io here, yet this function is ASYNC.
*
* @param {Function} callback - continuation to pass control to when complete.
*/
di.setup = function(callback) {
if (di.started === true) {
return callback();
}
di.started = true;
// Hack - override the 'jitsu' refrence in `$di help config list`
di.commands.config.list.usage = [
'Lists all configuration values currently',
'set in the .diconf file',
'',
'di config list'
];
callback();
};
/**
* Displays the `err` to the user for the `command` supplied.
*
* @param {String} command - Command which has errored.
* @param {Error} err - Error received for the command.
* @param {Boolean} shallow - Indicate if a deep stack should be displayed
*/
di.showError = function(command, err, shallow) {
di.log.error('Error running command ' + di.chalk.magenta(command));
if (err.stack && !shallow) {
err.stack.split('\n').forEach(function(trace) {
di.log.error(trace);
});
} else if (err.deployr) {
di.log.error('DeployR API error on call "' + err.get('call') + '"');
di.log.error('Error Code: ' + err.get('errorCode'));
di.log.error('Error: ' + err.get('error'));
} else {
di.log.error(err);
}
};
/**
* Menu selection to run commands.
*/
di.goto = function(command, callback) {
var cmdStr = (command || []).join(' ');
di.plugins.cli.executeCommand(command, function(err, shallow) {
if (err) {
di.showError(cmdStr, err, shallow);
}
di.displayExit = false;
});
};
/**
* Display the home `di` screen with the intial set of options.
*/
di.home = function() {
var separator = di.prompt.separator,
endpoint = di.config.get('endpoint'),
name = di.config.get('username'),
defaults = [{
name: 'Install an example',
value: {
method: 'goto',
args: ['install', 'example']
}
}, {
name: 'Settings',
value: {
method: 'settings'
}
}, {
name: 'Find some help',
value: {
method: 'findHelp'
}
}, {
name: 'Get me out of here!',
value: {
method: 'noop'
}
}];
name = (name && endpoint ? ' ' + name + '@' + endpoint.replace(/^https?:\/\//, '') : '');
di.prompt.inquirer([{
name: 'whatNext',
type: 'list',
message: 'Welcome to DeployR CLI' + di.chalk.magenta(name) + '!',
choices: this._.flatten([
separator('Choices'),
separator(),
defaults,
separator()
])
}], function(answer) {
this[answer.whatNext.method](answer.whatNext.args);
}.bind(this));
};
/**
* Prompts user with a few helpful resources, then opens it in their browser.
*/
di.findHelp = function() {
di.prompt.inquirer([{
name: 'whereTo',
type: 'list',
message: 'Here are a few helpful resources.\n' +
'\nI will open the link you select in your browser for you',
choices: [{
name: 'Take me to the documentation',
value: di.config.get('homepage')
}, {
name: 'File an issue on GitHub',
value: di.config.get('git').cli + '/issues'
}, {
name: 'Take me back home!',
value: {
method: 'home'
}
}]
}], function(answer) {
if (this._.isFunction(this[answer.whereTo.method])) {
this[answer.whereTo.method](answer.whereTo.args);
} else {
opn(answer.whereTo);
}
}.bind(this));
};
/**
* Prompts user with setting options.
*/
di.settings = function() {
var separator = di.prompt.separator,
choices = [{
name: 'DeployR endpoint',
value: {
method: 'goto',
args: ['endpoint']
}
}, {
name: 'About server',
value: {
method: 'goto',
args: ['about']
}
}, {
name: 'Take me back home!',
value: {
method: 'home'
}
}];
di.prompt.inquirer([{
name: 'general',
type: 'list',
message: 'General settings',
choices: this._.flatten([
separator('Choices'),
separator(),
choices,
separator()
])
}], function(answer) {
this[answer.general.method](answer.general.args, function() {
di.home();
});
}.bind(di));
};
/**
* Clears stdout and bring the cursor to postion 0.
*/
di.clearScreen = function() {
clear();
};
/**
* Ends the `di` process with the a common exit message.
*/
di.exit = function() {
if (di.displayExit) {
var url = 'https://github.com/deployr',
newLine = '\n';
console.log(
di.brand +
newLine +
'Good Bye!' +
newLine +
newLine +
'The DeployR Team' + di.chalk.dim.yellow(' ♥ ' + url)
);
}
};
process.once('exit', di.exit.bind(this));