bin/clever-setup
#!/usr/bin/env node
var path = require('path')
, lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib'))
, program = GLOBAL.program = require('commander')
, async = require('async')
, spawn = require('child_process').spawn
, readline = require('readline')
, fs = require('fs')
, os = require('os')
, isWin = /^win32/.test(os.platform())
, _ = require('lodash');
/** Define CLI Usage
================================*/
program
.option('-A, --allow-root', 'allow root for bower')
.option('-S, --skip-protractor', 'skips installing protractor (Frontend only)')
.option('-B, --bootstrap', 'will run `grunt bootstrap build` as part of the setup')
.option('-v, --verbose', 'verbose output useful for debugging')
.version(lib.pkg.version);
/** Define CLI Help
================================*/
program.on('--help', function() {
console.log(' Description:');
console.log('');
console.log(' Installs all NPM and Bower components for each module as well as building bundleDependencies.');
console.log(' This command will also install Protractor unless explicitly skipping.');
console.log('');
console.log(' Examples:');
console.log('');
console.log(' clever setup');
console.log('');
});
/** Parse CLI Arguments
================================*/
program.parse(process.argv);
/** Start Setup
================================*/
async.waterfall(
[
function startBar(callback) {
lib.utils.initBar();
lib.utils.installing('Modules');
lib.utils.startBar(callback);
},
function findSeedsToTarget(callback) {
lib
.util.locations
.get()
.then(function(projects) {
lib.utils.expandProgress(projects.length * 2);
var backend = _.find(projects, function(p) {
return p.name === 'backend';
});
var frontend = _.find(projects, function(p) {
return p.name === 'frontend';
});
if (frontend) {
lib.utils.expandProgress(1);
if (!!program.bootstrap) {
lib.utils.expandProgress(1);
}
if (!program.skipProtractor) {
lib.utils.expandProgress(2);
}
}
// @todo remove this patch when npm/npm#6435 is fixed
if (backend) {
lib.utils.expandProgress(2);
}
if (typeof backend === 'undefined' && typeof frontend === 'undefined') {
callback('Couldn\'t find a backend or frontend seed for CleverStack within', process.cwd());
} else {
callback(null, projects);
}
})
.catch(callback);
},
function eachSeed(projects, seedsComplete) {
async.eachSeries(
projects,
function setupSeed(seed, seedComplete) {
var _path = seed.moduleDir;
async.waterfall(
[
function npmInstallProject(callback) {
var args = ['install']
, opts = { cwd: _path, env: process.env };
lib
.utils
.info(' Installing NPM modules for ' + seed.name + '...')
.running(' Installing NPM modules for ' + seed.name + '...');
if (!program.verbose) {
args.push('--silent');
}
var posixProc = spawn(!isWin ? 'npm' : 'npm.cmd', args, opts)
, exitHdlr = process.kill.bind(process, posixProc)
, error = '';
if (!!program.verbose) {
readline
.createInterface({
input : posixProc.stdout,
terminal : false
})
.on('line', function(line) {
console.log(' ' + line);
});
}
process.on('SIGTERM', exitHdlr);
posixProc.on('error', function(err) {
error += err;
});
posixProc.on('close', function(code) {
process.removeListener('SIGTERM', exitHdlr);
if (code !== 0) {
return lib.utils.fail(error);
}
lib.utils.progress(1);
callback(null);
});
},
function modulesNpmInstall(callback) {
var modulesFolder = path.join(seed.moduleDir, seed.modulePath)
, modules = []
, folders = [];
if (fs.existsSync(modulesFolder)) {
folders = fs.readdirSync(modulesFolder);
folders.forEach(function(folder) {
if (!/^\./ig.test(folder)) {
var modulesPackageJsonPath = path.join(seed.moduleDir, seed.modulePath, folder)
, stats = fs.statSync(modulesPackageJsonPath)
, modulesPackageJson = path.join(modulesPackageJsonPath, 'package.json');
if (stats.isDirectory() && fs.existsSync(modulesPackageJsonPath) && fs.existsSync(modulesPackageJson)) {
modulesPackageJson = require(modulesPackageJson);
} else {
modulesPackageJson = {
version: 'default',
dependencies: {}
};
}
modules.push({
name: folder,
version: modulesPackageJson.version,
dependencies: _.merge({}, modulesPackageJson.dependencies, modulesPackageJson.devDependencies)
});
}
});
lib.utils.warn(' Installing ' + seed.name + ' modules...');
lib.utils.running(' Installing ' + seed.name + ' modules...');
}
// Expand the progress bar for each module we need to install
lib.utils.expandProgress(modules.length);
async.eachSeries(
modules,
function (m, next) {
lib.utils.warn(' Installing ' + m.name + '@' + m.version + ' module...');
lib.utils.running(' Installing ' + m.name + '@' + m.version + ' module for ' + seed.name + '...');
if (program.verbose) {
Object.keys(m.dependencies).forEach(function(depName) {
lib.utils.info(' Installing ' + depName + '@' + m.dependencies[ depName ] + '...');
});
}
lib.project
.installModule({
moduleDir: seed.moduleDir,
modulePath: path.join('modules', m.name)
}, path.resolve(path.join(seed.moduleDir, seed.modulePath, m.name)))
.then(function() {
lib.utils.progress(1);
next();
})
.catch(next);
},
callback
);
},
function bowerInstall(callback) {
var bowerPath = path.join(seed.moduleDir, 'bower.json');
lib.utils.progress(1);
if (seed.name === 'backend' || !fs.existsSync(bowerPath)) {
return callback(null);
}
lib.utils.info(' Installing ' + seed.name + ' bower components...');
lib.utils.running(' Installing ' + seed.name + ' bower components...');
lib.project
.installBowerComponents(seed)
.then(callback)
.catch(callback);
},
function bootstrapFrontend(callback) {
if (seed.name === 'frontend' && program.bootstrap) {
lib.utils.progress(1);
lib.utils.info(' Building frontend...');
lib.utils.running(' Building frontend...');
var proc = spawn('grunt bootstrap build', { cwd: _path }, function(err, stdout, stderr) {
lib.utils.progress(1);
(!!err || stderr.trim() !== '') ? callback(err || stderr.trim()) : callback(null);
});
// Pipe the output of spawn if verbose has been specified
if (program.verbose) {
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stdout);
}
} else {
callback(null);
}
},
function setupProtractor(callback) {
if (seed.name === 'frontend') {
if (program.skipProtractor) {
lib.utils.warn(' Skipping installation of protractor...');
return callback(null);
}
lib.utils.warn(' Installing protractor...');
lib.utils.running(' Installing protractor components...');
var proc = spawn('npm run-script setup-protractor', { cwd: _path }, function(err, stdout, stderr) {
lib.utils.progress(2);
(!!err || stderr.trim() !== '') ? callback(err || stderr.trim()) : callback(null);
});
// Pipe the output of spawn if verbose has been specified
if (program.verbose) {
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stdout);
}
} else {
callback(null);
}
}
],
seedComplete
);
},
seedsComplete
);
}
],
function setupComplete(err) {
if (!!err) {
lib.utils.fail(err);
process.exit(1);
}
lib.utils
.installing('CleverStack')
.running('Setup has completed.')
.finishProgress()
.success('Successfully setup all projects modules and components.');
process.exit(0);
}
);