CB-7044, CB-7299 Fix up PATH problems when possible.

Uses heuristics:
- Adds javac to PATH based on default install paths on Windows
- Adds javac to PATH based on JAVA_HOME
- Adds android and adb to PATH based on ANDROID_HOME
- Sets ANDROID_HOME based on location of "android"
This commit is contained in:
Andrew Grieve 2014-08-15 13:42:43 -04:00
parent 50ea162251
commit 4319447cb5
3 changed files with 67 additions and 39 deletions

View File

@ -19,26 +19,37 @@
under the License. under the License.
*/ */
var shell = require('shelljs'), var shelljs = require('shelljs'),
child_process = require('child_process'), child_process = require('child_process'),
Q = require('q'), Q = require('q'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
ROOT = path.join(__dirname, '..', '..'); ROOT = path.join(__dirname, '..', '..');
var isWindows = process.platform == 'win32';
function tryCommand(cmd, errMsg) {
var d = Q.defer();
child_process.exec(cmd, function(err, stdout, stderr) {
if (err) d.reject(new Error(errMsg));
else d.resolve(stdout);
});
return d.promise;
}
// Get valid target from framework/project.properties // Get valid target from framework/project.properties
module.exports.get_target = function() { module.exports.get_target = function() {
if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) { if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties')); var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', ''); return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
} else if (fs.existsSync(path.join(ROOT, 'project.properties'))) { } else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
// if no target found, we're probably in a project and project.properties is in ROOT. // if no target found, we're probably in a project and project.properties is in ROOT.
// this is called on the project itself, and can support Google APIs AND Vanilla Android // this is called on the project itself, and can support Google APIs AND Vanilla Android
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties')) || var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties')) ||
shell.grep(/target=Google Inc.:Google APIs:[\d+]/, path.join(ROOT, 'project.properties')); shelljs.grep(/target=Google Inc.:Google APIs:[\d+]/, path.join(ROOT, 'project.properties'));
if(target == "" || !target) { if(target == "" || !target) {
// Try Google Glass APIs // Try Google Glass APIs
target = shell.grep(/target=Google Inc.:Glass Development Kit Preview:[\d+]/, path.join(ROOT, 'project.properties')); target = shelljs.grep(/target=Google Inc.:Glass Development Kit Preview:[\d+]/, path.join(ROOT, 'project.properties'));
} }
return target.split('=')[1].replace('\n', '').replace('\r', ''); return target.split('=')[1].replace('\n', '').replace('\r', '');
} }
@ -46,49 +57,66 @@ module.exports.get_target = function() {
// Returns a promise. // Returns a promise.
module.exports.check_ant = function() { module.exports.check_ant = function() {
var d = Q.defer(); return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.');
child_process.exec('ant -version', function(err, stdout, stderr) {
if (err) d.reject(new Error('ERROR : executing command \'ant\', make sure you have ant installed and added to your path.'));
else d.resolve();
});
return d.promise;
} }
// Returns a promise. // Returns a promise.
module.exports.check_java = function() { module.exports.check_java = function() {
var d = Q.defer(); var javacInPath = !!shelljs.which('javac');
child_process.exec('java -version', function(err, stdout, stderr) { var hasJavaHome = !!process.env.JAVA_HOME;
if(err) { // Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
var msg = if (hasJavaHome && !javacInPath) {
'Failed to run \'java -version\', make sure your java environment is set up\n' + process.env.PATH += path.delimiter + path.join(process.env.JAVA_HOME, 'bin');
'including JDK and JRE.\n' + } else if (isWindows && (!hasJavaHome || !javacInPath)) {
'Your JAVA_HOME variable is ' + process.env.JAVA_HOME + '\n'; // Try to auto-detect java in the default install paths.
d.reject(new Error(msg + err)); var firstJdkDir =
shelljs.ls(process.env.ProgramFiles + '\\java\\jdk*')[0] ||
shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
if (firstJdkDir) {
// shelljs always uses / in paths.
firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
if (!javacInPath) {
process.env.PATH += path.delimiter + path.join(firstJdkDir, 'bin');
}
process.env.JAVA_HOME = firstJdkDir;
} }
else d.resolve(); }
var msg =
'Failed to run "java -version", make sure your java environment is set up\n' +
'including JDK and JRE.\n' +
'Your JAVA_HOME variable is: ' + process.env.JAVA_HOME;
return tryCommand('java -version', msg)
.then(function() {
msg = 'Failed to run "javac -version", make sure you have a Java JDK (not just a JRE) installed.';
return tryCommand('javac -version', msg)
}); });
return d.promise;
} }
// Returns a promise. // Returns a promise.
module.exports.check_android = function() { module.exports.check_android = function() {
var valid_target = this.get_target(); var androidCmdPath = !!shelljs.which('android');
var d = Q.defer(); var adbInPath = !!shelljs.which('adb');
child_process.exec('android list targets', function(err, stdout, stderr) { var hasAndroidHome = !!process.env.ANDROID_HOME;
if (err) d.reject(stderr); if (hasAndroidHome && !androidCmdPath) {
else d.resolve(stdout); process.env.PATH += path.delimiter + path.join(process.env.ANDROID_HOME, 'tools');
}); }
if (androidCmdPath && !hasAndroidHome) {
process.env.ANDROID_HOME = path.dirname(path.dirname(androidCmdPath));
hasAndroidHome = true;
}
if (hasAndroidHome && !adbInPath) {
process.env.PATH += path.delimiter + path.join(process.env.ANDROID_HOME, 'platform-tools');
}
return d.promise.then(function(output) { var valid_target = this.get_target();
var msg = 'Failed to run "android". Make sure you have the latest Android SDK installed, and that the "android" command (inside the tools/ folder) is added to your PATH.';
return tryCommand('android list targets', msg)
.then(function(output) {
if (!output.match(valid_target)) { if (!output.match(valid_target)) {
return Q.reject(new Error('Please install Android target ' + valid_target.split('-')[1] + ' (the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.')); return Q.reject(new Error('Please install Android target ' + valid_target.split('-')[1] +
} ' (the Android newest SDK). Make sure you have the latest Android tools installed as well.' +
return Q(); ' Run "android" from your command-line to install/update any missing SDKs or tools.'));
}, function(stderr) {
if (stderr.match(/command\snot\sfound/) || stderr.match(/is not recognized as an internal or external command/)) {
return Q.reject(new Error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.'));
} else {
return Q.reject(new Error('An error occurred while listing Android targets. Error: ' + stderr ));
} }
}); });
} }

View File

@ -196,7 +196,7 @@ exports.createProject = function(project_path, package_name, project_name, proje
}) })
// Check that requirements are met and proper targets are installed // Check that requirements are met and proper targets are installed
.then(function() { .then(function() {
check_reqs.run(); return check_reqs.run();
}).then(function() { }).then(function() {
// Log the given values for the project // Log the given values for the project
console.log('Creating Cordova project for the Android platform:'); console.log('Creating Cordova project for the Android platform:');

View File

@ -28,9 +28,9 @@ if(args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help') { args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
build.help(); build.help();
} else { } else {
reqs.run().then(function() { reqs.run().done(function() {
return build.run(args[2]); return build.run(args[2]);
}).done(null, function(err) { }, function(err) {
console.error(err); console.error(err);
process.exit(2); process.exit(2);
}); });