From ebd4a02d2ce5edbf76de42ffa32b83cd026412e2 Mon Sep 17 00:00:00 2001 From: filmaj Date: Tue, 14 Mar 2017 16:01:32 -0700 Subject: [PATCH] CB-12546: switch to superspawn for shelling out where possible. rework android sdk module to work with new sdk. --- bin/android_sdk_version | 6 +- bin/templates/cordova/lib/android_sdk.js | 94 ++++++++++++++---------- bin/templates/cordova/lib/check_reqs.js | 91 +++++++++++++---------- 3 files changed, 109 insertions(+), 82 deletions(-) diff --git a/bin/android_sdk_version b/bin/android_sdk_version index 4d120c62..9e75325f 100755 --- a/bin/android_sdk_version +++ b/bin/android_sdk_version @@ -19,10 +19,10 @@ under the License. */ -var android_sdk_version = require('./templates/cordova/lib/android_sdk'); +var android_sdk = require('./templates/cordova/lib/android_sdk'); -android_sdk_version.run().done(null, function(err) { - console.log(err); +android_sdk.print_newest_available_sdk_target.done(null, function(err) { + console.error(err); process.exit(2); }); diff --git a/bin/templates/cordova/lib/android_sdk.js b/bin/templates/cordova/lib/android_sdk.js index dbec25e2..6bb00757 100755 --- a/bin/templates/cordova/lib/android_sdk.js +++ b/bin/templates/cordova/lib/android_sdk.js @@ -19,47 +19,14 @@ under the License. */ -var child_process = require('child_process'), - Q = require('q'); +var Q = require('q'), + superspawn = require('cordova-common').superspawn; -var get_highest_sdk = function(results){ - var reg = /\d+/; - var apiLevels = []; - for(var i=0;i= 0; i--) { + if(target_out[i].match(/id:/)) { + targets.push(targets[i].split(' ')[1]); + } + } + return targets; + }).catch(function(err) { + // there's a chance `android` no longer works. + // lets see if `sdkmanager` is available and we can figure it out + var avail_regex = /android command is no longer available/; + if (err.code && (err.stdout.match(avail_regex) || err.stderr.match(avail_regex))) { + return superspawn.spawn('sdkmanager', ['--list'], {capture: ['stdout', 'stderr']}) + .then(function(result) { + var parsing_installed_packages = false; + var lines = result.stdout.split('\n'); + var targets = []; + for (var i = 0, l = lines.length; i < l; i++) { + var line = lines[i]; + if (line.match(/Installed packages/)) { + parsing_installed_packages = true; + } else if (line.match(/Available Packages/) || line.match(/Available Updates/)) { + // we are done working through installed packages, exit + break; + } + if (parsing_installed_packages && line.match(/platforms;android-\d+/)) { + targets.push(line.match(/android-\d+/)[0].split('-')[1]); + } + } + return targets; + }); + } else throw err; + }).then(function(targets) { + if (targets.length === 0) { + return Q.reject(new Error('No android targets (SDKs) installed!')); + } else { + // Ensure we are working with integers + targets = targets.map(function(t) { return parseInt(t); }); + // Sort them in descending order. + targets.sort(function(a, b) { return b-a; }); + return targets; + } + }); +}; diff --git a/bin/templates/cordova/lib/check_reqs.js b/bin/templates/cordova/lib/check_reqs.js index daea4aa6..910c3a6f 100644 --- a/bin/templates/cordova/lib/check_reqs.js +++ b/bin/templates/cordova/lib/check_reqs.js @@ -30,6 +30,7 @@ var shelljs = require('shelljs'), REPO_ROOT = path.join(__dirname, '..', '..', '..', '..'), PROJECT_ROOT = path.join(__dirname, '..', '..'); var CordovaError = require('cordova-common').CordovaError; +var superspawn = require('cordova-common').superspawn; function forgivingWhichSync(cmd) { @@ -83,10 +84,12 @@ module.exports.get_target = function() { // Returns a promise. Called only by build and clean commands. module.exports.check_ant = function() { - return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.') - .then(function (output) { + return superspawn.spawn('ant', ['-version']) + .then(function(output) { // Parse Ant version from command output return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1]; + }).catch(function(err) { + throw new CordovaError("Failed to run `ant -version`. Make sure you have `ant` on your $PATH."); }); }; @@ -98,15 +101,14 @@ module.exports.get_gradle_wrapper = function() { androidStudioPath = path.join(process.env['ProgramFiles'],'Android', 'Android Studio', 'gradle'); } - if(androidStudioPath !== null && fs.existsSync(androidStudioPath)) { - var dirs = fs.readdirSync(androidStudioPath); - if(dirs[0].split('-')[0] == 'gradle') - { - return path.join(androidStudioPath, dirs[0], 'bin', 'gradle'); - } + if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) { + var dirs = fs.readdirSync(androidStudioPath); + if(dirs[0].split('-')[0] == 'gradle') { + return path.join(androidStudioPath, dirs[0], 'bin', 'gradle'); + } } else { - //OK, let's try to check for Gradle! - return forgivingWhichSync('gradle'); + //OK, let's try to check for Gradle! + return forgivingWhichSync('gradle'); } }; @@ -119,16 +121,15 @@ module.exports.check_gradle = function() { 'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.')); var gradlePath = module.exports.get_gradle_wrapper(); - if(gradlePath.length !== 0) - d.resolve(gradlePath); + if (gradlePath.length !== 0) + d.resolve(gradlePath); else - d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' + + d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' + 'or on your system to install the gradle wrapper. Please include gradle \n' + 'in your path, or install Android Studio')); return d.promise; }; - // Returns a promise. module.exports.check_java = function() { var javacPath = forgivingWhichSync('javac'); @@ -141,12 +142,15 @@ module.exports.check_java = function() { } } else { if (javacPath) { - var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.'; // OS X has a command for finding JAVA_HOME. - if (fs.existsSync('/usr/libexec/java_home')) { - return tryCommand('/usr/libexec/java_home', msg) + var find_java = '/usr/libexec/java_home'; + var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.'; + if (fs.existsSync(find_java)) { + return superspawn.spawn(find_java) .then(function(stdout) { process.env['JAVA_HOME'] = stdout.trim(); + }).catch(function(err) { + throw new CordovaError(default_java_error_msg); }); } else { // See if we can derive it from javac's location. @@ -155,7 +159,7 @@ module.exports.check_java = function() { if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) { process.env['JAVA_HOME'] = maybeJavaHome; } else { - throw new CordovaError(msg); + throw new CordovaError(default_java_error_msg); } } } else if (module.exports.isWindows()) { @@ -178,21 +182,21 @@ module.exports.check_java = function() { } } }).then(function() { - var msg = - 'Failed to run "javac -version", make sure that you have a JDK installed.\n' + - 'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n'; - if (process.env['JAVA_HOME']) { - msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n'; - } - // We use tryCommand with catchStderr = true, because - // javac writes version info to stderr instead of stdout - return tryCommand('javac -version', msg, true) - .then(function (output) { - //Let's check for at least Java 8, and keep it future proof so we can support Java 10 - var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output); - return match && match[1]; - }); + var msg = + 'Failed to run "javac -version", make sure that you have a JDK installed.\n' + + 'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n'; + if (process.env['JAVA_HOME']) { + msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n'; + } + // We use tryCommand with catchStderr = true, because + // javac writes version info to stderr instead of stdout + return tryCommand('javac -version', msg, true) + .then(function (output) { + //Let's check for at least Java 8, and keep it future proof so we can support Java 10 + var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output); + return match && match[1]; }); + }); }; // Returns a promise. @@ -297,9 +301,11 @@ module.exports.check_android = function() { module.exports.getAbsoluteAndroidCmd = function () { var cmd = forgivingWhichSync('android'); - if(cmd.length === 0) - cmd = forgivingWhichSync('avdmanager'); - if (process.platform === 'win32') { + // TODO: this probably needs to be `sdkmanager`, no? + if (cmd.length === 0) { + cmd = forgivingWhichSync('avdmanager'); + } + if (module.exports.isWindows()) { return '"' + cmd + '"'; } return cmd.replace(/(\s)/g, '\\$1'); @@ -314,13 +320,13 @@ module.exports.check_android_target = function(originalError) { var valid_target = module.exports.get_target(); var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.'; // Changing "targets" to "target" is stupid and makes more code. Thanks Google! - var cmd = 'android list targets --compact'; + var cmd = 'android'; // TODO: the following conditional needs fixing, probably should leverage `sdkmanager` // oh and tests - if(forgivingWhichSync('avdmanager').length > 0) - cmd = 'avdmanager list target --compact'; - return tryCommand(cmd, msg) - .then(function(output) { + if (forgivingWhichSync('avdmanager').length > 0) + cmd = 'avdmanager'; + return superspawn.spawn(cmd, ['list', 'targets', '--compact']) + .then(function(stdout) { var targets = output.split('\n'); if (targets.indexOf(valid_target) >= 0) { return targets; @@ -337,6 +343,11 @@ module.exports.check_android_target = function(originalError) { msg = originalError + '\n' + msg; } throw new CordovaError(msg); + }).catch(function(err) { + throw new CordovaError(msg); + }); + return tryCommand(cmd, msg) + .then(function(output) { }); };