tooltwist
Version:
Tooltwist Command Line Interface
483 lines (401 loc) • 13.6 kB
JavaScript
/*
* Run the Tooltwist server.
* This prepares all the config files, then uses Gradle to do the actual build and run.
*/
var Log = require('./log'),
Git = require('git-wrapper'),
Config = require('./config'),
Mustache = require("mustache"),
Templates = require("./templates"),
fs = require('fs'),
mkdirp = require('mkdirp'),
gradle = require('./gradle'),
controller = require('./controller');
// Directory locations
// var PROJECT_ROOT = Config.PROJECT_ROOT;
//var TTDIR = Config.getHiddenDir();
// var WEBDESIGN_DIR = Config.getHiddenDir() + '/webdesign-projects';
// var EXTENSIONS_DIR = Config.getHiddenDir() + '/extension-projects';
//var RESOURCES_DIR = __dirname + '/..';
/**
* Search for the web design project that maps onto a specific repository.
*/
exports.findWebdesignProject = function(repoUrl, callback) {
Log.debug();
Log.debug('server.findWebdesignProject(' + repoUrl + ')')
// Check the input parameters
/*
* Check we have the webdesign project
*/
/*
mkdirp.sync(Config.HIDDEN_DIR);
if (project) {
// A project is specified, see if it has been downlaoded already
var dir = Config.WEBDESIGN_DIR + "/" + project;
if (fs.existsSync(dir)) {
var stat = fs.statSync(dir);
if (stat.isDirectory()) {
// We have a project. If we also have a repository, check it is the right one.
if (repoUrl) {
// Check the repository is the right one.
projectIsForRepository(project, repoUrl, function(isForRepo){
if (isForRepo){
// Outcome - project found for specified repo - update project.
return doPullRequest(project, callback);
} else {
// Outcome - project found but does not match repo - error.
Log.info("\nError: project '" + project + "' is not for " + repoUrl);
return callback(null);
}
});
} else {
// Outcome - project found and no repo specified - update project.
return doPullRequest(project, callback);
}
} else {
// Outcome - specified project is not found - error.
Log.info("\nError: unknown project '" + project + "'.");
return callback(null);
}
} else {
// Specified project does not exist, clone from github if we have a URL
if (repoUrl) {
// Outcome - specified project missing but repo specified - clone repo.
return cloneRepository(repoUrl, project, branch, callback);
} else {
// Outcome - specified project missing and no repo specified - error.
Log.info('\nError: project ' + project + ' not found, and no repository was specified.')
return callback(null);
}
}
} else
{
*/
// Project not specified - see if a repository is specified
Log.debug('no project specified')
if (repoUrl) {
// Find the project that uses this repository
Log.debug('no project but repo ' + repoUrl)
return findProjectForRepository(repoUrl, callback);
/*function(project, remote){
if (project == null) {
// Outcome - repository specified but not found - clone the repo.
//Log.info("No web design project found for repository '" + repoUrl + "'");
return exports.cloneRepository(repoUrl, project, callback);
} else {
// Outcome - repository specified and found - update the project.
return doPullRequest(project, callback);
}
});
*/
} else {
// Outcome - no project or repo has been specified - let the user choose one.
return chooseProject(callback);
/*function(project){
return callback(project);
});
*/
}
/*
}
*/
/**
* Prompt the user for which project to use.
* If there's only one project, use it.
*/
function chooseProject(cb) {
Log.debug()
Log.debug('chooseProject')
if ( !fs.existsSync(Config.WEBDESIGN_DIR)) {
Log.error("No projects found. Try -r <repositoryUrl> to add a project.");
process.exit(1);
// return cb(null);
}
var projects = [];
var list = fs.readdirSync(Config.WEBDESIGN_DIR);
list.forEach(function (file, index) {
var path = Config.WEBDESIGN_DIR + '/' + file + '/project.json';
if (fs.existsSync(path)) {
Log.debug(" ---> " + path + ', ' + index);
projects.push(file);
}
});
// Maybe there are no projects.
if (projects.length == 0) {
Log.debug("NO PROJECTS")
return cb(null);
}
// If there's only one project, use it.
if (projects.length == 1) {
Log.debug('using the only project')
var project = projects[0];
return cb(project);
/*doPullRequest(project, cb);
*/
}
// List the available projects
Log.always('Please select one of the following projects:')
for (var i = 0; i < projects.length; i++) {
Log.always(' ' + (i+1) + ': ' + projects[i]);
}
// Ask the user which project.
var rl = require('readline').createInterface(process.stdin, process.stdout);
rl.setPrompt('Selection: ');
rl.prompt();
rl.on('line', function(line) {
var index = parseInt(line);
if (index > 0 && index <= projects.length){
Log.debug('index is ' + index)
var project = projects[index - 1];
// doPullRequest(project, cb);
rl.close();
return callback(project);
} else {
rl.prompt();
}
});
}
/**
* Find a webdesign project for the specified repository
*/
function findProjectForRepository(repository, callback) {
Log.debug()
Log.debug('server.findProjectForRepository(' + repository + ')')
Log.debug('Scanning existing webdesign projects for: ' + repository)
if ( !fs.existsSync(Config.WEBDESIGN_DIR)) {
return callback(null);
}
// Get a list of the available projects
var projects = [];
var list = fs.readdirSync(Config.WEBDESIGN_DIR);
list.forEach(function (file, index) {
var path = Config.WEBDESIGN_DIR + '/' + file + '/.git';
if (fs.existsSync(path)) {
// Add this project directory to the list
projects.push(file);
// Check we have a project.json file
var path = Config.WEBDESIGN_DIR + '/' + file + '/project.json';
if ( !fs.existsSync(path)) {
Log.warn("WARNING: Missing " + path);
}
}
});
// List the available projects
Log.debug('projects: ', projects)
findProjectForRepository2(repository, projects, 0, callback);
}
function findProjectForRepository2(repoUrl, projects, index, callback){
Log.debug('findProjectForRepository2, repoUrl=' + repoUrl + ", index=" + index)
if (index >= projects.length) {
// Run off the end of the list
Log.debug('checked all projects, and not found')
Log.debug('Project not found')
return callback(null);
}
var project = projects[index];
Log.debug("Checking remotes for " + project)
var path = Config.WEBDESIGN_DIR + '/' + project + '/.git';
//var found = false
var git = new Git({ 'git-dir': path });
git.exec('remote', { v: true}, [ ], function(err, msg){
if (err) {
Log.error('Error: ', err)
process.exit(1);
}
Log.debug('Message is:\n' + msg)
var lines = msg.split('\n');
//Log.debug(" lines=", lines)
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
//Log.debug();
//Log.debug(" line=", line)
if (line === ''){
continue;
}
var arr = line.split('\t');
if (arr.length != 2) {
Log.error('Unrecognized string returned by \'git remote -v\' in ' + path + ':\n' + line);
Log.debug('arr=', arr)
return callback(null);
}
if (arr[0] === 'origin' && endsWith(arr[1], ' (fetch)')) {
//Log.debug(" arr=", arr)
var url = arr[1].substring(0, arr[1].length - 8);
Log.debug(' url=' + url + '.')
if (url === repoUrl) {
var remote = arr[0];
Log.debug('FOUND REPO: ' + project + ', ' + remote)
Log.debug('Project \'' + project + '\' is for this repository.\n')
return callback(project)
}
}
}
// Not this project - try the next project
Log.debug('Check next project')
findProjectForRepository2(repoUrl, projects, index + 1, callback);
});
}
};
exports.cloneWebdesignProject = function(repoUrl, branch, callback) {
Log.debug()
Log.debug('server.cloneWebdesignProject(' + repoUrl + ')')
Log.info('Clone git repository ' + repoUrl)
// callback(null);
if ( !endsWith(repoUrl, '.git')){
Log.error('Error: URL does not end with \'.git\': ' + repoUrl)
process.exit(1);
}
// Get the project name
var project = repoUrl.substring(0, repoUrl.length - 4)
var pos = project.lastIndexOf('/')
if (pos >= 0)
project = project.substring(pos + 1)
// Do the clone
mkdirp.sync(Config.WEBDESIGN_DIR);
try {
// Do the clone, in the Webdesign directory
Log.info('$ cd ' + Config.WEBDESIGN_DIR)
Log.info('$ git clone -b ' + branch + ' '+ repoUrl)
var initialDirectory = process.cwd(); // remember where are, so we can come back.
process.chdir(Config.WEBDESIGN_DIR);
var git = new Git({ });
git.exec('clone', { }, [ '-b', branch, repoUrl ], function(err, msg){
if (err) {
Log.error('Error: ' + err)
process.exit(1);
}
Log.info(msg)
process.chdir(initialDirectory);
return callback(project);
});
} catch (err) {
Log.error('chdir: ' + err);
process.exit(1);
}
}
/**
* Do a git pull
*/
exports.pullWebdesignProject = function(project, branch, callback){
Log.debug()
Log.debug("server.pullWebdesignProject(" + project + ', ' + branch + ')')
Log.info("Update project " + project + ' from git.')
var path = Config.WEBDESIGN_DIR + "/" + project + "/.git";
Log.info('$ cd ' + path)
// Log.info('$ git stash save --include-untracked')
Log.info('$ git pull')
// First stash any changes, in case someone wants them later
// var git = new Git({ 'git-dir': path });
// git.exec('stash', { }, [ 'save', '--include-untracked' ], function(err, msg){
// if (err) {
// Log.error('Error: ' + err)
// throw err;
// }
// Log.info(msg)
// Now do the pull
var git2 = new Git({ 'git-dir': path });
git2.exec('pull', { }, [ ], function(err, msg){
if (err) {
Log.error('Error: ' + err)
throw err;
}
Log.info(msg)
Log.info('Update complete.\n')
// Check we are on the right branch.
return exports.checkBranch(project, branch, callback);
});
// });
}
/**
* Check that the webdesign is on the right branch. If not, don't
* try to rectify the problem - inform the user and bomb out.
*/
exports.checkBranch = function(project, branch, callback){
Log.debug()
Log.debug("server.checkBranch(" + project + ', ' + branch + ')')
Log.info("Check branch of project " + project)
// For some reason, we need to be in the webdesign project
// directory, or we get "Error: stdout maxBuffer exceeded."
var initialDirectory = process.cwd(); // remember where are, so we can come back.
process.chdir(Config.WEBDESIGN_DIR + '/' + project);
// Get the branch using 'git status'
var path = Config.WEBDESIGN_DIR + "/" + project + "/.git";
Log.info('$ cd ' + path)
Log.info('$ git status')
var git = new Git({ 'git-dir': path });
git.exec('status', { }, [ ], function(err, msg){
process.chdir(initialDirectory);
if (err) {
Log.error('Error: ' + err)
throw err;
}
//Log.debug('Status is:\n' + msg)
var lines = msg.split('\n');
//Log.debug(" lines=", lines)
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var currentBranch = null;
if (/^On branch /) {
var regexp = /On branch (.*)/;
var match = regexp.exec(line);
currentBranch = match[1];
break;
}
}
// Check the current branch was found.
Log.info('webdesign is on branch \'' + currentBranch + '\'.');
if (currentBranch == null) {
// Should not happen
Log.error();
Log.error('Error: \'git status\' did not show current branch.');
Log.error();
process.exit(1);
}
// If we are on the wrong branch, change branch now.
if (currentBranch !== branch) {
// Get the path to the config file where the branch was defined.
var branchDefinitionLocation = Config.PROJECT_ROOT + '/' + Config.CONFIG_FILE;
if (Config.getConfig().mode === 'controller') {
branchDefinitionLocation = '/ControllerV8/config-files/deploymentConfig.' + Controller.LAUNCHPAD_NAME + '.xml';
}
// Display the error message.
Log.always();
Log.always('\tPROBLEM:');
Log.always();
Log.always('\tYour webdesign project is currently on the wrong branch. ToolTwist');
Log.always('\tcannot switch branches because it does not know which updates you');
Log.always('\twould like to keep. You will need to switch branches manually.');
Log.always();
Log.always('\tWebdesign directory: ' + (Config.WEBDESIGN_DIR + "/" + project));
Log.always('\tCurrent branch: ' + currentBranch);
Log.always('\tBranch specified in config file: ' + branch);
Log.always('\t(' + branchDefinitionLocation + ')');
Log.always();
process.exit(1);
// // Get the branch using 'git checkout <branch>'
// var path = Config.WEBDESIGN_DIR + "/" + project + "/.git";
// // Log.info('$ cd ' + path)
// Log.info('$ git checkout ' + branch)
// var git = new Git({ 'git-dir': path });
// git.exec('checkout', { }, [ branch ], function(err, msg){
//
// // Check the rply
// if (err) {
// Log.error('Error: ' + err)
// throw err;
// }
// Log.info(msg)
// process.exit(1);
// return callback(project);
// });
}
// All good. Carry on.
return callback(project);
});
}
/**
* See if a string ends with a particular suffix.
*/
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}