From 597fa051833ca3df6eb185c0143ff82e02dacba1 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 26 Sep 2017 01:35:13 +0200 Subject: push plugin ugh --- .../platforms/android/cordova/lib/android_sdk.js | 106 ++++++++++ .../android/cordova/lib/android_sdk_version.js | 64 ------ .../android/cordova/lib/builders/GradleBuilder.js | 39 ++-- .../platforms/android/cordova/lib/check_reqs.js | 230 ++++++++++++++------- .../platforms/android/cordova/lib/emulator.js | 131 ++++++++++-- .../platforms/android/cordova/lib/list-devices | 2 +- .../android/cordova/lib/list-emulator-images | 2 +- .../android/cordova/lib/list-started-emulators | 2 +- .../platforms/android/cordova/lib/prepare.js | 40 ++++ 9 files changed, 444 insertions(+), 172 deletions(-) create mode 100755 StoneIsland/platforms/android/cordova/lib/android_sdk.js delete mode 100755 StoneIsland/platforms/android/cordova/lib/android_sdk_version.js (limited to 'StoneIsland/platforms/android/cordova/lib') diff --git a/StoneIsland/platforms/android/cordova/lib/android_sdk.js b/StoneIsland/platforms/android/cordova/lib/android_sdk.js new file mode 100755 index 00000000..a1a806a6 --- /dev/null +++ b/StoneIsland/platforms/android/cordova/lib/android_sdk.js @@ -0,0 +1,106 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +var Q = require('q'), + superspawn = require('cordova-common').superspawn; + +var suffix_number_regex = /(\d+)$/; +// Used for sorting Android targets, example strings to sort: +// android-19 +// android-L +// Google Inc.:Google APIs:20 +// Google Inc.:Glass Development Kit Preview:20 +// The idea is to sort based on largest "suffix" number - meaning the bigger +// the number at the end, the more recent the target, the closer to the +// start of the array. +function sort_by_largest_numerical_suffix(a, b) { + var suffix_a = a.match(suffix_number_regex); + var suffix_b = b.match(suffix_number_regex); + if (suffix_a && suffix_b) { + // If the two targets being compared have suffixes, return less than + // zero, or greater than zero, based on which suffix is larger. + return (parseInt(suffix_a[1]) > parseInt(suffix_b[1]) ? -1 : 1); + } else { + // If no suffix numbers were detected, leave the order as-is between + // elements a and b. + return 0; + } +} + +module.exports.print_newest_available_sdk_target = function() { + return module.exports.list_targets() + .then(function(targets) { + targets.sort(sort_by_largest_numerical_suffix); + console.log(targets[0]); + }); +}; + +module.exports.version_string_to_api_level = { + '4.0': 14, + '4.0.3': 15, + '4.1': 16, + '4.2': 17, + '4.3': 18, + '4.4': 19, + '4.4W': 20, + '5.0': 21, + '5.1': 22, + '6.0': 23, + '7.0': 24, + '7.1.1': 25 +}; + +function parse_targets(output) { + var target_out = output.split('\n'); + var targets = []; + for (var i = target_out.length - 1; i >= 0; i--) { + if(target_out[i].match(/id:/)) { // if "id:" is in the line... + targets.push(target_out[i].match(/"(.+)"/)[1]); //.. match whatever is in quotes. + } + } + return targets; +} + +module.exports.list_targets_with_android = function() { + return superspawn.spawn('android', ['list', 'target']) + .then(parse_targets); +}; + +module.exports.list_targets_with_avdmanager = function() { + return superspawn.spawn('avdmanager', ['list', 'target']) + .then(parse_targets); +}; + +module.exports.list_targets = function() { + return module.exports.list_targets_with_avdmanager() + .catch(function(err) { + // If there's an error, like avdmanager could not be found, we can try + // as a last resort, to run `android`, in case this is a super old + // SDK installation. + if (err && (err.code == 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) { + return module.exports.list_targets_with_android(); + } else throw err; + }) + .then(function(targets) { + if (targets.length === 0) { + return Q.reject(new Error('No android targets (SDKs) installed!')); + } + return targets; + }); +}; diff --git a/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js b/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js deleted file mode 100755 index 79af2727..00000000 --- a/StoneIsland/platforms/android/cordova/lib/android_sdk_version.js +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var child_process = require('child_process'), - Q = require('q'); - -var get_highest_sdk = function(results){ - var reg = /\d+/; - var apiLevels = []; - for(var i=0;i= 0) { + var desired_api_level = module.exports.get_target(); + return android_sdk.list_targets() + .then(function(targets) { + if (targets.indexOf(desired_api_level) >= 0) { return targets; } - var androidCmd = module.exports.getAbsoluteAndroidCmd(); - var msg = 'Please install Android target: "' + valid_target + '".\n\n' + + var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' + 'Hint: Open the SDK manager by running: ' + androidCmd + '\n' + 'You will require:\n' + - '1. "SDK Platform" for ' + valid_target + '\n' + + '1. "SDK Platform" for API level ' + desired_api_level + '\n' + '2. "Android SDK Platform-tools (latest)\n' + '3. "Android SDK Build-tools" (latest)'; if (originalError) { @@ -278,7 +367,6 @@ module.exports.run = function() { throw new CordovaError('Requirements check failed for JDK 1.8 or greater'); } - if (!values[1]) { throw new CordovaError('Requirements check failed for Android SDK'); } diff --git a/StoneIsland/platforms/android/cordova/lib/emulator.js b/StoneIsland/platforms/android/cordova/lib/emulator.js index ff1e261c..22209aa0 100644 --- a/StoneIsland/platforms/android/cordova/lib/emulator.js +++ b/StoneIsland/platforms/android/cordova/lib/emulator.js @@ -27,11 +27,15 @@ var path = require('path'); var Adb = require('./Adb'); var AndroidManifest = require('./AndroidManifest'); var events = require('cordova-common').events; -var spawn = require('cordova-common').superspawn.spawn; +var superspawn = require('cordova-common').superspawn; var CordovaError = require('cordova-common').CordovaError; +var shelljs = require('shelljs'); +var android_sdk = require('./android_sdk'); +var check_reqs = require('./check_reqs'); var Q = require('q'); var os = require('os'); +var fs = require('fs'); var child_process = require('child_process'); // constants @@ -42,18 +46,77 @@ var NUM_INSTALL_RETRIES = 3; var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds var EXEC_KILL_SIGNAL = 'SIGKILL'; -/** - * Returns a Promise for a list of emulator images in the form of objects - * { - name : , - path : , - target : , - abi : , - skin : - } - */ -module.exports.list_images = function() { - return spawn('android', ['list', 'avds']) +function forgivingWhichSync(cmd) { + try { + return fs.realpathSync(shelljs.which(cmd)); + } catch (e) { + return ''; + } +} + +module.exports.list_images_using_avdmanager = function () { + return superspawn.spawn('avdmanager', ['list', 'avd']) + .then(function(output) { + var response = output.split('\n'); + var emulator_list = []; + for (var i = 1; i < response.length; i++) { + // To return more detailed information use img_obj + var img_obj = {}; + if (response[i].match(/Name:\s/)) { + img_obj['name'] = response[i].split('Name: ')[1].replace('\r', ''); + if (response[i + 1].match(/Device:\s/)) { + i++; + img_obj['device'] = response[i].split('Device: ')[1].replace('\r', ''); + } + if (response[i + 1].match(/Path:\s/)) { + i++; + img_obj['path'] = response[i].split('Path: ')[1].replace('\r', ''); + } + if (response[i + 1].match(/Target:\s/)) { + i++; + if (response[i + 1].match(/ABI:\s/)) { + img_obj['abi'] = response[i + 1].split('ABI: ')[1].replace('\r', ''); + } + // This next conditional just aims to match the old output of `android list avd` + // We do so so that we don't have to change the logic when parsing for the + // best emulator target to spawn (see below in `best_image`) + // This allows us to transitionally support both `android` and `avdmanager` binaries, + // depending on what SDK version the user has + if (response[i + 1].match(/Based\son:\s/)) { + img_obj['target'] = response[i + 1].split('Based on:')[1]; + if (img_obj['target'].match(/Tag\/ABI:\s/)) { + img_obj['target'] = img_obj['target'].split('Tag/ABI:')[0].replace('\r', '').trim(); + if (img_obj['target'].indexOf('(') > -1) { + img_obj['target'] = img_obj['target'].substr(0, img_obj['target'].indexOf('(') - 1).trim(); + } + } + var version_string = img_obj['target'].replace(/Android\s+/, ''); + + var api_level = android_sdk.version_string_to_api_level[version_string]; + if (api_level) { + img_obj['target'] += ' (API level ' + api_level + ')'; + } + } + } + if (response[i + 1].match(/Skin:\s/)) { + i++; + img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', ''); + } + + emulator_list.push(img_obj); + } + /* To just return a list of names use this + if (response[i].match(/Name:\s/)) { + emulator_list.push(response[i].split('Name: ')[1].replace('\r', ''); + }*/ + + } + return emulator_list; + }); +}; + +module.exports.list_images_using_android = function() { + return superspawn.spawn('android', ['list', 'avd']) .then(function(output) { var response = output.split('\n'); var emulator_list = []; @@ -96,6 +159,29 @@ module.exports.list_images = function() { }); }; +/** + * Returns a Promise for a list of emulator images in the form of objects + * { + name : , + device : , + path : , + target : , + abi : , + skin : + } + */ +module.exports.list_images = function() { + if (forgivingWhichSync('avdmanager')) { + return module.exports.list_images_using_avdmanager(); + } else if (forgivingWhichSync('android')) { + return module.exports.list_images_using_android(); + } else { + return Q().then(function() { + throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); + }); + } +}; + /** * Will return the closest avd to the projects target * or undefined if no avds exist. @@ -109,8 +195,7 @@ module.exports.best_image = function() { var closest = 9999; var best = images[0]; - // Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue - var project_target = require('./check_reqs').get_target().replace('android-', ''); + var project_target = check_reqs.get_target().replace('android-', ''); for (var i in images) { var target = images[i].target; if(target) { @@ -133,8 +218,9 @@ module.exports.list_started = function() { }; // Returns a promise. +// TODO: we should remove this, there's a more robust method under android_sdk.js module.exports.list_targets = function() { - return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}) + return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}) .then(function(output) { var target_out = output.split('\n'); var targets = []; @@ -189,8 +275,7 @@ module.exports.start = function(emulator_ID, boot_timeout) { return best.name; } - // Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue - var androidCmd = require('./check_reqs').getAbsoluteAndroidCmd(); + var androidCmd = check_reqs.getAbsoluteAndroidCmd(); return Q.reject(new CordovaError('No emulator images (avds) found.\n' + '1. Download desired System Image by running: ' + androidCmd + ' sdk\n' + '2. Create an AVD by running: ' + androidCmd + ' avd\n' + @@ -199,10 +284,13 @@ module.exports.start = function(emulator_ID, boot_timeout) { }).then(function(emulatorId) { return self.get_available_port() .then(function (port) { + // Figure out the directory the emulator binary runs in, and set the cwd to that directory. + // Workaround for https://code.google.com/p/android/issues/detail?id=235461 + var emulator_dir = path.dirname(shelljs.which('emulator')); var args = ['-avd', emulatorId, '-port', port]; // Don't wait for it to finish, since the emulator will probably keep running for a long time. child_process - .spawn('emulator', args, { stdio: 'inherit', detached: true }) + .spawn('emulator', args, { stdio: 'inherit', detached: true, cwd: emulator_dir }) .unref(); // wait for emulator to start @@ -294,7 +382,7 @@ module.exports.wait_for_boot = function(emulator_id, time_remaining) { module.exports.create_image = function(name, target) { console.log('Creating new avd named ' + name); if (target) { - return spawn('android', ['create', 'avd', '--name', name, '--target', target]) + return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]) .then(null, function(error) { console.error('ERROR : Failed to create emulator image : '); console.error(' Do you have the latest android targets including ' + target + '?'); @@ -302,7 +390,8 @@ module.exports.create_image = function(name, target) { }); } else { console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.'); - return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]) + // TODO: there's a more robust method for finding targets in android_sdk.js + return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]) .then(function() { // TODO: This seems like another error case, even though it always happens. console.error('ERROR : Unable to create an avd emulator, no targets found.'); diff --git a/StoneIsland/platforms/android/cordova/lib/list-devices b/StoneIsland/platforms/android/cordova/lib/list-devices index fa84d7f6..8e22c7f2 100755 --- a/StoneIsland/platforms/android/cordova/lib/list-devices +++ b/StoneIsland/platforms/android/cordova/lib/list-devices @@ -22,7 +22,7 @@ var devices = require('./device'); // Usage support for when args are given -require('../lib/check_reqs').check_android().then(function() { +require('./check_reqs').check_android().then(function() { devices.list().done(function(device_list) { device_list && device_list.forEach(function(dev) { console.log(dev); diff --git a/StoneIsland/platforms/android/cordova/lib/list-emulator-images b/StoneIsland/platforms/android/cordova/lib/list-emulator-images index 03c827fe..25e5c81a 100755 --- a/StoneIsland/platforms/android/cordova/lib/list-emulator-images +++ b/StoneIsland/platforms/android/cordova/lib/list-emulator-images @@ -22,7 +22,7 @@ var emulators = require('./emulator'); // Usage support for when args are given -require('../lib/check_reqs').check_android().then(function() { +require('./check_reqs').check_android().then(function() { emulators.list_images().done(function(emulator_list) { emulator_list && emulator_list.forEach(function(emu) { console.log(emu.name); diff --git a/StoneIsland/platforms/android/cordova/lib/list-started-emulators b/StoneIsland/platforms/android/cordova/lib/list-started-emulators index a890dec6..43ebda25 100755 --- a/StoneIsland/platforms/android/cordova/lib/list-started-emulators +++ b/StoneIsland/platforms/android/cordova/lib/list-started-emulators @@ -22,7 +22,7 @@ var emulators = require('./emulator'); // Usage support for when args are given -require('../lib/check_reqs').check_android().then(function() { +require('./check_reqs').check_android().then(function() { emulators.list_started().done(function(emulator_list) { emulator_list && emulator_list.forEach(function(emu) { console.log(emu); diff --git a/StoneIsland/platforms/android/cordova/lib/prepare.js b/StoneIsland/platforms/android/cordova/lib/prepare.js index 10a69ea3..504eb612 100644 --- a/StoneIsland/platforms/android/cordova/lib/prepare.js +++ b/StoneIsland/platforms/android/cordova/lib/prepare.js @@ -48,6 +48,7 @@ module.exports.prepare = function (cordovaProject, options) { .then(function () { updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res)); updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res)); + updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root)); }) .then(function () { events.emit('verbose', 'Prepared android project successfully'); @@ -72,6 +73,7 @@ module.exports.clean = function (options) { cleanWww(projectRoot, self.locations); cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res)); cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res)); + cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root)); }); }; @@ -401,6 +403,44 @@ function mapImageResources(rootDir, subDir, type, resourceName) { return pathMap; } + +function updateFileResources(cordovaProject, platformDir) { + var files = cordovaProject.projectConfig.getFileResources('android'); + + // if there are resource-file elements in config.xml + if (files.length === 0) { + events.emit('verbose', 'This app does not have additional resource files defined'); + return; + } + + var resourceMap = {}; + files.forEach(function(res) { + var targetPath = path.join(platformDir, res.target); + resourceMap[targetPath] = res.src; + }); + + events.emit('verbose', 'Updating resource files at ' + platformDir); + FileUpdater.updatePaths( + resourceMap, { rootDir: cordovaProject.root }, logFileOp); +} + + +function cleanFileResources(projectRoot, projectConfig, platformDir) { + var files = projectConfig.getFileResources('android'); + if (files.length > 0) { + events.emit('verbose', 'Cleaning resource files at ' + platformDir); + + var resourceMap = {}; + files.forEach(function(res) { + var filePath = path.join(platformDir, res.target); + resourceMap[filePath] = null; + }); + + FileUpdater.updatePaths( + resourceMap, { rootDir: projectRoot, all: true}, logFileOp); + } +} + /** * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns * preference value and warns if it doesn't seems to be valid -- cgit v1.2.3-70-g09d2