jitsu
Version:
Flawless command line deployment of Node.js apps to the cloud
270 lines (229 loc) • 7.35 kB
JavaScript
;
/*
* install.js: Commands for installing and deploying starter apps.
*
* (C) 2010, Nodejitsu Inc.
*
*/
var canihaz = require('canihaz')('jitsu'),
fs = require('fs'),
path = require('path'),
exists = fs.exists || path.exists,
common = require('../common'),
cpr = common.cpr,
wizard = require('wizard'),
jitsu = require('../../jitsu'),
utile = jitsu.common,
npm;
//
// "nodeapps" is a hash of aliases and npm packages,
// this mapping allows us to give short names to all node apps
//
var nodeapps = {
"helloworld": {
"package": "nodeapps-helloworld",
"description": " demo `hello world` http server"
},
"express": {
"package": "nodeapps-express",
"description": " express.js boilerplate"
},
"socket.io": {
"package": "nodeapps-socket.io",
"description": " socket.io boilerplate"
},
"http-server": {
"package": "http-server",
"description": " a robust and customizable http server"
},
"ghost": {
"package": "persistent-ghost",
"description": " the ghost blogging platform with MongoDB persistence"
}
};
module.exports = function (requestedApp, callback) {
//
// Allows arbitrary amount of arguments
//
if (arguments.length) {
var args = utile.args(arguments);
callback = args.callback;
requestedApp = args[0] || null;
}
var app = {
name : requestedApp,
config: {
path: null,
schemaPath: null,
schema : null
}
};
canihaz.npm(function fetch(err, module) {
if (err) {
return callback(err);
}
npm = module;
npm.load({ exit: false }, function (err) {
if (err) {
return callback(err);
}
if (typeof app.name === 'string') {
return createApp({starter: app.name}, callback);
}
promptforAppName(callback);
});
});
function createApp(results, cb) {
if (Object.keys(nodeapps).indexOf(results.starter) === -1) {
jitsu.log.error('Sorry, ' + results.starter.magenta + ' is not a node app');
return cb('err');
}
installApp(results.starter, function (err, res) {
return err ? cb(err) : postInstall(results.starter, cb);
});
}
function installApp(appName, cb) {
var thisPath = process.cwd();
jitsu.log.info('Installing ' + appName.magenta + ' locally');
jitsu.log.warn('Downloading packages from npm, this may take a moment...');
npm.commands.install(appName, [nodeapps[appName].package], function (err, result) {
if (err) {
return cb(err);
}
cpr(path.join(thisPath + '/' + appName, 'node_modules', nodeapps[appName].package), thisPath + '/' + appName, function (err) {
if (err) {
return cb(err);
}
//
// Read current package.json
//
var pkg = JSON.parse(fs.readFileSync(thisPath + '/' + appName + '/package.json').toString()),
installhook = pkg['jitsu-install'];
//
// Strip out any un-needed internal ids and our custom `jitsu-install`
// hook.
//
delete pkg['jitsu-install'];
for(var k in pkg) {
if (k.search("_") !== -1) {
delete pkg[k];
}
}
//
// Write modified package.json back out
//
fs.writeFileSync(thisPath + '/' + appName + '/package.json', JSON.stringify(pkg, true, 2));
if (!installhook) return cb(err, result);
//
// We got a custom `jitsu install` hook that needs to be ran.
//
require(thisPath + '/' + appName + '/'+ installhook)(jitsu, function (err) {
cb(err, result);
});
});
});
}
function promptforAppName(cb) {
jitsu.log.help('The ' + 'install'.magenta + ' command downloads pre-built node apps');
jitsu.log.info('Please select a node app to get started');
jitsu.log.info('Available node apps:');
Object.keys(nodeapps).forEach(function (starter) {
jitsu.log.info(starter.magenta + ' ' + nodeapps[starter].description);
});
jitsu.prompt.get(['starter'], function (err, results) {
if (err) {
jitsu.log.warn('Cancelled');
return cb(null, 'Cancelled');
}
return createApp({ starter: results.starter }, callback);
});
}
function postInstall(appName, cb) {
app.name = appName;
jitsu.log.info(app.name.magenta + ' installed');
//
// Check if the app provides any configuration schema
//
app.config.schemaPath = './' + app.name + '/config/schema.json';
exists(app.config.schemaPath, function (exists) {
if (exists) {
try {
app.config.schema = JSON.parse(fs.readFileSync(app.config.schemaPath).toString());
app.config.path = './' + app.name + '/config/development.json';
configureApp(app.config.schema, cb);
} catch (err) {
cb(err);
}
} else {
promptStart(cb);
}
});
}
function configureApp (schema, cb) {
jitsu.log.info('Attempting to configure app based on ' + './config/schema.json'.grey);
jitsu.log.help('Prompting for ' + app.name.magenta + ' configuration data');
jitsu.log.help('Press ' + '[ENTER]'.grey + ' to specify default values');
wizard.cli.run(schema, function (err, config) {
//
// Remark: Now that we have the configuration data,
// we will push it to various sources ( like ENV and file-system )
//
//
// TODO: set ENV values based on config, either package.json so it gets picked up by NJ API
//
//
// Write configuration data to *.json files on file-system
//
writeConfiguration(config, function () {
promptStart(cb);
});
});
}
function writeConfiguration (config, cb) {
return fs.writeFile(app.config.path, JSON.stringify(config, true, 2), cb);
}
function promptStart (cb) {
jitsu.log.help('To deploy type: ');
jitsu.log.help('');
jitsu.log.help((' cd ' + app.name).grey);
jitsu.log.help(' ' + 'jitsu deploy'.grey);
jitsu.log.help('');
//
// Prompt to see if the user wants to start the application
//
jitsu.prompt.get(['start_local'], function (err, results) {
if (err) {
jitsu.log.warn('Cancelled');
return cb(null, 'Cancelled');
}
return results.start_local === 'yes'
? startApp('local', cb)
: cb(null);
});
}
function startApp(dest, cb) {
var spawn = require('child_process').spawn;
jitsu.log.info(app.name.magenta + ' is now starting');
jitsu.log.help('To exit the app, press CTRL-C \n');
if (dest === "local") {
return npm.start(process.cwd() + '/' + app.name, cb);
}
}
function deployApp(cb) {
jitsu.log.info('Jitsu will now help create a package.json');
return jitsu.package.create(process.cwd(), function (err, result) {
if (err) {
return cb(err);
}
jitsu.log.info('The app has been created successfully. Deploying!');
jitsu.log.info('Run additional deployments using `jitsu deploy`');
return jitsu.plugins.cli.executeCommand(['deploy'],callback);
});
}
};
module.exports.usage = [
'Installs a pre-built node.js app locally',
'',
'jitsu install',
'jitsu install <appname>'
];