imo-img
Version:
image optimize.
285 lines • 9.23 kB
JavaScript
// require dependencies
var exec = require('child_process').exec,
colors = require('colors/safe'),
inquirer = require('inquirer'),
request = require('request'),
fs = require('fs-extra'),
del = require('del');
// script default options
var remoteConfigURL = 'https://gitlab.com/yasir-yk/imo/blob/master/config.json' + ('?' + Date.now()),
basePath = process.cwd() + '/',
fileName = 'project.json',
clonePath = '',
projectConfig;
// console menu helper
function showMenu(menuConfig, callback) {
var menu = {
type: 'list',
name: 'value',
message: '',
choices: []
};
menuConfig.forEach(function(item) {
menu.choices.push({
name: item.caption,
value: item.value
});
if(item.question) {
menu.message = item.question;
}
});
inquirer.prompt([menu], function( answers ) {
var selectedValue = answers.value,
childMenuConfig = null;
if(!callback._menuAnswers) {
callback._menuAnswers = [];
}
callback._menuAnswers.push(selectedValue);
// need to show submenu?
menuConfig.forEach(function(item) {
if(item.value === selectedValue && item.menu) {
childMenuConfig = item.menu;
}
});
// show submenu or user selected everything?
if(childMenuConfig) {
showMenu(childMenuConfig, callback);
} else if(typeof callback === 'function') {
callback(callback._menuAnswers);
delete callback._menuAnswers;
}
});
}
// remote config handler
function useMenuConfig(remoteConfig) {
var buildConfig = function(selectedOptions, configSample) {
var isSelectedOption = function(optionName) {
return selectedOptions.indexOf(optionName) > -1;
};
['source', 'ignore', 'run', 'rename'].forEach(function(keyName) {
var currentData = configSample[keyName],
resultData = [];
currentData.forEach(function(item) {
var dependenciesOk = true,
noConflicts = true;
if(item.dependenciesAll) {
item.dependenciesAll.forEach(function(depName) {
if(!isSelectedOption(depName)) {
dependenciesOk = false;
}
});
}
if(item.dependenciesAny && dependenciesOk) {
dependenciesOk = false;
item.dependenciesAny.forEach(function(depName) {
if(isSelectedOption(depName)) {
dependenciesOk = true;
}
});
}
if(item.excludeIf) {
item.excludeIf.forEach(function(depName) {
if(isSelectedOption(depName)) {
noConflicts = false;
}
});
}
if(dependenciesOk && noConflicts) {
resultData.push(item.matchValue);
}
});
configSample[keyName] = resultData;
});
return configSample;
};
showMenu(remoteConfig.createMenu, function(userSelection) {
projectConfig = buildConfig(userSelection, remoteConfig.data);
clonePath += projectConfig.path || '';
if(projectConfig.source) {
cloneGitRepo();
}
});
}
function startExisting(remoteConfig) {
showMenu(remoteConfig.updateMenu, function(userSelection) {
var selectedMode = userSelection[0],
selectedCommands = null;
// detect selected commands
remoteConfig.updateMenu.forEach(function(item) {
if(item.value === selectedMode) {
selectedCommands = item.run;
}
});
// process commands
var resultCommands = [];
selectedCommands.forEach(function(item, index) {
if(typeof item === 'object') {
if(item.fsNotExist && !fs.existsSync(basePath + item.fsNotExist)) {
console.log('>>>', item.matchValue);
resultCommands.push(item.matchValue);
}
} else {
resultCommands.push(item);
}
});
// execute specified shell commands
if(resultCommands.length) {
runShellCommands(resultCommands, basePath + remoteConfig.data.path);
}
});
}
function startInstall() {
// search for default file exists
var localConfig;
if(!fs.existsSync(basePath + fileName)) {
console.log('Searching for configuration files in current directory...');
fs.readdirSync(basePath).forEach(function(tmpFileName){
if(fs.statSync(basePath + tmpFileName).isFile() && /^project.*\.json$/i.test(tmpFileName)) {
fileName = tmpFileName;
}
});
}
function executeConfig(cfg) {
// show copyright
if(cfg.copyright) {
console.log(colors.yellow(cfg.copyright));
}
if(fs.existsSync(basePath + cfg.data.path)) {
startExisting(cfg);
} else {
useMenuConfig(cfg);
}
}
if(fs.existsSync(basePath + fileName)) {
// checkout or use existing folder
try {
console.log('Using configuration file: "' + fileName + '"');
localConfig = require(basePath + fileName);
executeConfig(localConfig);
} catch(e) {
console.log(colors.red('Error in configuration file!'));
process.exit();
}
} else {
console.log('No configuration file found! Loading remote config...');
loadRemoteConfig(function(remoteConfig) {
executeConfig(remoteConfig);
});
}
}
function loadRemoteConfig(callback) {
request(remoteConfigURL, function (error, response, body) {
var remoteConfig = null;
if(error) {
console.log(colors.red('Cannot load config ' + error));
} else {
try {
remoteConfig = JSON.parse(body);
if(typeof callback === 'function') {
callback(remoteConfig);
}
} catch(e) {
console.log(colors.red('Remote config parsing failed!'));
}
}
});
}
// 1. Clone git repo:
function cloneGitRepo() {
var currentCloneIndex = 0,
tempFolder = '_w3m-temp';
var cloneRepo = function() {
var repoURL = projectConfig.source[currentCloneIndex],
child;
if(repoURL) {
console.log('Cloning git repo: "' + repoURL + '"');
child = exec('git clone ' + repoURL + ' "' + tempFolder + '"');
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
child.on('exit', function() {
del.sync(tempFolder + '/.git');
fs.copySync(tempFolder, projectConfig.path);
fs.removeSync(tempFolder);
currentCloneIndex++;
cloneRepo();
});
} else {
fs.removeSync(tempFolder);
removeUnneededFiles();
}
};
if(clonePath && fs.existsSync(clonePath)) {
console.log('Folder "' + clonePath + '" already exists. Skip git clone.');
removeUnneededFiles();
} else {
console.log('creating target directory: "' + projectConfig.path + '"');
fs.mkdirsSync(projectConfig.path);
cloneRepo();
}
}
// 2. Remove unneeded files
function removeUnneededFiles() {
var filesToRemove;
if(projectConfig.ignore) {
console.log('Removing unneeded files...');
filesToRemove = projectConfig.ignore.map(function(value){
return basePath + clonePath + '/' + value;
});
del.sync(filesToRemove);
}
renameFiles();
}
// 3. Rename files
function renameFiles() {
var oldFileName, newFileName;
if(projectConfig.rename) {
console.log('Renaming files...');
projectConfig.rename.forEach(function(item) {
for(var fileName in item) {
oldFileName = basePath + clonePath + '/' + fileName;
newFileName = basePath + clonePath + '/' + item[fileName];
try {
fs.renameSync(oldFileName, newFileName);
} catch(e) { }
}
});
runShellCommands(projectConfig.run, clonePath);
} else {
runShellCommands(projectConfig.run, clonePath);
}
}
// 4. Run shell command
function runShellCommands(commands, cwd, callback) {
var activeProcessIndex = 0;
var startProcess = function() {
var command = commands[activeProcessIndex],
child;
if(command) {
console.log('Starting shell command: "' + command + '"');
child = exec(command);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
child.on('exit', function() {
activeProcessIndex++;
startProcess();
});
} else if(typeof callback === 'function') {
callback();
}
};
if(commands && commands.length) {
process.chdir(cwd);
startProcess();
}
}
// CLI exports
module.exports = {
interpret: function(argv) {
var cliArgs = argv.slice(2),
customFileName = cliArgs[0];
if(customFileName) {
fileName = customFileName;
}
startInstall();
}
};