Repository: cordova-android Updated Branches: refs/heads/4.0.x d022be547 -> 95815a558
CB-7579 Fix run script's ability to use non-arch-specific APKs Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/879da034 Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/879da034 Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/879da034 Branch: refs/heads/4.0.x Commit: 879da03438130c0cf5f9cc70b6cd9ebab615345c Parents: 3f83fdb Author: Andrew Grieve <[email protected]> Authored: Mon Sep 22 14:23:30 2014 -0400 Committer: Andrew Grieve <[email protected]> Committed: Mon Sep 22 14:23:30 2014 -0400 ---------------------------------------------------------------------- bin/templates/cordova/lib/build.js | 152 ++++++++++++++--------------- bin/templates/cordova/lib/device.js | 5 +- bin/templates/cordova/lib/emulator.js | 5 +- bin/templates/cordova/lib/run.js | 26 ++--- 4 files changed, 93 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-android/blob/879da034/bin/templates/cordova/lib/build.js ---------------------------------------------------------------------- diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index 2e6a624..18a2f3b 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -32,23 +32,46 @@ var LOCAL_PROPERTIES_TEMPLATE = '# This file is automatically generated.\n' + '# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n'; -function find_files(directory, predicate) { +function findApks(directory) { + var ret = []; if (fs.existsSync(directory)) { - var candidates = fs.readdirSync(directory).filter(predicate).map(function(p) { - p = path.join(directory, p); - return { p: p, t: fs.statSync(p).mtime }; - }).sort(function(a,b) { - var timeDiff = b.t - a.t; - if (timeDiff === 0) { - return a.p.length - b.p.length; + fs.readdirSync(directory).forEach(function(p) { + if (path.extname(p) == '.apk') { + ret.push(path.join(directory, p)); } - return timeDiff; - }).map(function(p) { return p.p; }); - return candidates; - } else { - console.error('ERROR : unable to find project ' + directory + ' directory, could not locate .apk'); - process.exit(2); + }); } + return ret; +} + +function sortFilesByDate(files) { + return files.map(function(p) { + return { p: p, t: fs.statSync(p).mtime }; + }).sort(function(a, b) { + var timeDiff = b.t - a.t; + return timeDiff === 0 ? a.p.length - b.p.length : timeDiff; + }).map(function(p) { return p.p; }); +} + +function findOutputApksHelper(dir, build_type) { + var ret = findApks(dir).filter(function(candidate) { + // Need to choose between release and debug .apk. + if (build_type === 'debug') { + return /-debug/.exec(candidate) && !/-unaligned|-unsigned/.exec(candidate); + } + if (build_type === 'release') { + return /-release/.exec(candidate) && !/-unaligned/.exec(candidate); + } + return true; + }); + ret = sortFilesByDate(ret); + if (ret.length === 0) { + return ret; + } + var archSpecific = !!/-x86|-arm/.exec(ret[0]); + return ret.filter(function(p) { + return !!/-x86|-arm/.exec(p) == archSpecific; + }); } function hasCustomRules() { @@ -127,8 +150,6 @@ var builders = { return check_reqs.check_ant() .then(function() { return spawn('ant', args); - }).then(function() { - return builder.getOutputFiles(); }); }, @@ -140,22 +161,9 @@ var builders = { }); }, - // Find the recently-generated output APK files - // Ant only generates one output file; return it. - getOutputFiles: function() { - var binDir; - if(hasCustomRules()) { - binDir = path.join(ROOT, 'ant-build'); - } else { - binDir = path.join(ROOT, 'bin'); - } - var candidates = find_files(binDir, function(candidate) { return path.extname(candidate) == '.apk'; }); - if (candidates.length === 0) { - console.error('ERROR : No .apk found in ' + binDir + ' directory'); - process.exit(2); - } - var ret = candidates[0]; - return [ret]; + findOutputApks: function(build_type) { + var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin'); + return findOutputApksHelper(binDir, build_type); } }, gradle: { @@ -227,8 +235,6 @@ var builders = { var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release'); return Q().then(function() { return spawn(wrapper, args); - }).then(function() { - return builder.getOutputFiles(build_type); }); }, @@ -241,21 +247,9 @@ var builders = { }); }, - // Find the recently-generated output APK files - // Gradle can generate multiple output files; return all of them. - getOutputFiles: function(build_type) { + findOutputApks: function(build_type) { var binDir = path.join(ROOT, 'build', 'outputs', 'apk'); - var candidates = find_files(binDir, function(candidate) { - // Need to choose between release and debug .apk. - if (build_type === 'debug') { - return (path.extname(candidate) == '.apk' && candidate.indexOf('-debug') >= 0); - } - if (build_type === 'release') { - return (path.extname(candidate) == '.apk' && candidate.indexOf('-release') >= 0); - } - return path.extname(candidate) == '.apk'; - }); - return candidates; + return findOutputApksHelper(binDir, build_type); } }, @@ -265,11 +259,14 @@ var builders = { }, build: function() { console.log('Skipping build...'); - return Q(); + return Q(null); }, clean: function() { return Q(); }, + findOutputApks: function(build_type) { + return sortFilesByDate(builders.ant.findOutputApks(build_type).concat(builders.gradle.findOutputApks(build_type))); + } } }; @@ -284,7 +281,7 @@ function parseOpts(options) { // Iterate through command line options for (var i=0; options && (i < options.length); ++i) { - if (options[i].substring && options[i].substring(0,2) == "--") { + if (/^--/.exec(options[i])) { var option = options[i].substring(2); switch(option) { case 'debug': @@ -334,20 +331,15 @@ module.exports.run = function(options) { return builder.prepEnv() .then(function() { return builder.build(opts.buildType); - }).then(function(apkFiles) { - // TODO: Rather than copy apks to out, it might be better to - // just write out what the last .apk build was. These files - // are used by get_apk(). - var outputDir = path.join(ROOT, 'out'); - shell.mkdir('-p', outputDir); - var builtApks = []; - for (var i=0; i < apkFiles.length; ++i) { - var dst = path.join(outputDir, path.basename(apkFiles[i])); - builtApks.push(dst); - shell.cp('-f', apkFiles[i], dst); - } - console.log('Built the following APKs:\n' + builtApks.join('\n')); - return builtApks; + }).then(function() { + var apkPaths = builder.findOutputApks(opts.buildType); + console.log('Built the following apk(s):'); + console.log(' ' + apkPaths.join('\n ')); + return { + apkPaths: apkPaths, + buildType: opts.buildType, + buildMethod: opts.buildMethod + }; }); }; @@ -365,21 +357,25 @@ module.exports.detectArchitecture = function(target) { }); }; -/* - * Gets the path to the apk file, if not such file exists then - * the script will error out. (should we error or just return undefined?) - * This is called by the run script to install the apk to the device - */ -module.exports.get_apk = function(build_type, architecture) { - var outputDir = path.join(ROOT, 'out'); - var candidates = find_files(outputDir, function(filename) { return (!architecture) || filename.indexOf(architecture) >= 0; }); - if (candidates.length === 0) { - console.error('ERROR : No .apk found in ' + outputDir + ' directory'); - process.exit(2); +module.exports.findBestApkForArchitecture = function(buildResults, arch) { + var paths = buildResults.apkPaths.filter(function(p) { + if (buildResults.buildType == 'debug') { + return /-debug/.exec(p); + } + return !/-debug/.exec(p); + }); + var archPattern = new RegExp('-' + arch); + var hasArchPattern = /-x86|-arm/; + for (var i = 0; i < paths.length; ++i) { + if (hasArchPattern.exec(paths[i])) { + if (archPattern.exec(paths[i])) { + return paths[i]; + } + } else { + return paths[i]; + } } - // TODO: Use build_type here. - console.log('Using apk: ' + candidates[0]); - return candidates[0]; + throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType); }; module.exports.help = function() { http://git-wip-us.apache.org/repos/asf/cordova-android/blob/879da034/bin/templates/cordova/lib/device.js ---------------------------------------------------------------------- diff --git a/bin/templates/cordova/lib/device.js b/bin/templates/cordova/lib/device.js index 671f93d..b2df1d7 100644 --- a/bin/templates/cordova/lib/device.js +++ b/bin/templates/cordova/lib/device.js @@ -48,7 +48,7 @@ module.exports.list = function() { * and launches it. * Returns a promise. */ -module.exports.install = function(target) { +module.exports.install = function(target, buildResults) { var launchName; return this.list() .then(function(device_list) { @@ -64,8 +64,9 @@ module.exports.install = function(target) { return build.detectArchitecture(target) .then(function(arch) { - var apk_path = build.get_apk(null, arch); + var apk_path = build.findBestApkForArchitecture(buildResults, arch); launchName = appinfo.getActivityName(); + console.log('Using apk: ' + apk_path); console.log('Installing app on device...'); var cmd = 'adb -s ' + target + ' install -r "' + apk_path + '"'; return exec(cmd); http://git-wip-us.apache.org/repos/asf/cordova-android/blob/879da034/bin/templates/cordova/lib/emulator.js ---------------------------------------------------------------------- diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index 88b35f7..ecc8b38 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -279,7 +279,7 @@ module.exports.create_image = function(name, target) { * If no started emulators are found, error out. * Returns a promise. */ -module.exports.install = function(target) { +module.exports.install = function(target, buildResults) { var self = this; return this.list_started() .then(function(emulator_list) { @@ -295,8 +295,9 @@ module.exports.install = function(target) { return build.detectArchitecture(target) .then(function(arch) { - var apk_path = build.get_apk(null, arch); + var apk_path = build.findBestApkForArchitecture(buildResults, arch); console.log('Installing app on emulator...'); + console.log('Using apk: ' + apk_path); return exec('adb -s ' + target + ' install -r "' + apk_path + '"'); }); }).then(function(output) { http://git-wip-us.apache.org/repos/asf/cordova-android/blob/879da034/bin/templates/cordova/lib/run.js ---------------------------------------------------------------------- diff --git a/bin/templates/cordova/lib/run.js b/bin/templates/cordova/lib/run.js index da8fc60..16e8065 100644 --- a/bin/templates/cordova/lib/run.js +++ b/bin/templates/cordova/lib/run.js @@ -33,16 +33,16 @@ var path = require('path'), * Returns a promise. */ module.exports.run = function(args) { - var build_type; + var buildFlags = []; var install_target; for (var i=2; i<args.length; i++) { if (args[i] == '--debug') { - build_type = '--debug'; + buildFlags.push('--debug'); } else if (args[i] == '--release') { - build_type = '--release'; + buildFlags.push('--release'); } else if (args[i] == '--nobuild') { - build_type = '--nobuild'; + buildFlags.push('--nobuild'); } else if (args[i] == '--device') { install_target = '--device'; } else if (args[i] == '--emulator') { @@ -55,13 +55,13 @@ var path = require('path'), } } - return build.run(build_type).then(function() { + return build.run(buildFlags).then(function(buildResults) { if (install_target == '--device') { - return device.install(); + return device.install(null, buildResults); } else if (install_target == '--emulator') { return emulator.list_started().then(function(started) { var p = started && started.length > 0 ? Q() : emulator.start(); - return p.then(function() { emulator.install(); }); + return p.then(function() { emulator.install(null, buildResults); }); }); } else if (install_target) { var devices, started_emulators, avds; @@ -75,16 +75,16 @@ var path = require('path'), }).then(function(res) { avds = res; if (devices.indexOf(install_target) > -1) { - return device.install(install_target); + return device.install(install_target, buildResults); } else if (started_emulators.indexOf(install_target) > -1) { - return emulator.install(install_target); + return emulator.install(install_target, buildResults); } else { // if target emulator isn't started, then start it. var emulator_ID; for(avd in avds) { if(avds[avd].name == install_target) { return emulator.start(install_target) - .then(function() { emulator.install(emulator_ID); }); + .then(function() { emulator.install(emulator_ID, buildResults); }); } } return Q.reject('Target \'' + install_target + '\' not found, unable to run project'); @@ -96,13 +96,13 @@ var path = require('path'), .then(function(device_list) { if (device_list.length > 0) { console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.'); - return device.install(device_list[0]); + return device.install(device_list[0], buildResults); } else { return emulator.list_started() .then(function(emulator_list) { if (emulator_list.length > 0) { console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.'); - return emulator.install(emulator_list[0]); + return emulator.install(emulator_list[0], buildResults); } else { console.log('WARNING : No started emulators found, starting an emulator.'); return emulator.best_image() @@ -111,7 +111,7 @@ var path = require('path'), return emulator.start(best_avd.name) .then(function(emulator_ID) { console.log('WARNING : No target specified, deploying to emulator \'' + emulator_ID + '\'.'); - return emulator.install(emulator_ID); + return emulator.install(emulator_ID, buildResults); }); } else { return emulator.start();
