gradle: Build only the active architecture when applicable

This commit is contained in:
Andrew Grieve 2014-09-24 16:07:31 -04:00
parent 9e3ccf4b3e
commit 162d9b6c2e
4 changed files with 174 additions and 139 deletions

View File

@ -53,7 +53,7 @@ function sortFilesByDate(files) {
}).map(function(p) { return p.p; }); }).map(function(p) { return p.p; });
} }
function findOutputApksHelper(dir, build_type) { function findOutputApksHelper(dir, build_type, arch) {
var ret = findApks(dir).filter(function(candidate) { var ret = findApks(dir).filter(function(candidate) {
// Need to choose between release and debug .apk. // Need to choose between release and debug .apk.
if (build_type === 'debug') { if (build_type === 'debug') {
@ -69,9 +69,15 @@ function findOutputApksHelper(dir, build_type) {
return ret; return ret;
} }
var archSpecific = !!/-x86|-arm/.exec(ret[0]); var archSpecific = !!/-x86|-arm/.exec(ret[0]);
return ret.filter(function(p) { ret = ret.filter(function(p) {
return !!/-x86|-arm/.exec(p) == archSpecific; return !!/-x86|-arm/.exec(p) == archSpecific;
}); });
if (arch) {
ret = ret.filter(function(p) {
return p.indexOf('-' + arch) != -1;
});
}
return ret;
} }
function hasCustomRules() { function hasCustomRules() {
@ -163,11 +169,11 @@ var builders = {
findOutputApks: function(build_type) { findOutputApks: function(build_type) {
var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin'); var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin');
return findOutputApksHelper(binDir, build_type); return findOutputApksHelper(binDir, build_type, null);
} }
}, },
gradle: { gradle: {
getArgs: function(cmd) { getArgs: function(cmd, arch) {
var lintSteps; var lintSteps;
if (process.env['BUILD_MULTIPLE_APKS']) { if (process.env['BUILD_MULTIPLE_APKS']) {
lintSteps = [ lintSteps = [
@ -187,7 +193,15 @@ var builders = {
'copyDebugLint' 'copyDebugLint'
]; ];
} }
if (cmd == 'debug') { if (arch == 'arm' && cmd == 'debug') {
cmd = 'assembleArmv7Debug';
} else if (arch == 'arm' && cmd == 'release') {
cmd = 'assembleArmv7Release';
} else if (arch == 'x86' && cmd == 'debug') {
cmd = 'assembleX86Debug';
} else if (arch == 'x86' && cmd == 'release') {
cmd = 'assembleX86Release';
} else if (cmd == 'debug') {
cmd = 'assembleDebug'; cmd = 'assembleDebug';
} else if (cmd == 'release') { } else if (cmd == 'release') {
cmd = 'assembleRelease'; cmd = 'assembleRelease';
@ -260,10 +274,10 @@ var builders = {
* Builds the project with gradle. * Builds the project with gradle.
* Returns a promise. * Returns a promise.
*/ */
build: function(build_type) { build: function(build_type, arch) {
var builder = this; var builder = this;
var wrapper = path.join(ROOT, 'gradlew'); var wrapper = path.join(ROOT, 'gradlew');
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release'); var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release', arch);
return Q().then(function() { return Q().then(function() {
return spawn(wrapper, args); return spawn(wrapper, args);
}); });
@ -278,9 +292,9 @@ var builders = {
}); });
}, },
findOutputApks: function(build_type) { findOutputApks: function(build_type, arch) {
var binDir = path.join(ROOT, 'build', 'outputs', 'apk'); var binDir = path.join(ROOT, 'build', 'outputs', 'apk');
return findOutputApksHelper(binDir, build_type); return findOutputApksHelper(binDir, build_type, arch);
} }
}, },
@ -295,19 +309,20 @@ var builders = {
clean: function() { clean: function() {
return Q(); return Q();
}, },
findOutputApks: function(build_type) { findOutputApks: function(build_type, arch) {
return sortFilesByDate(builders.ant.findOutputApks(build_type).concat(builders.gradle.findOutputApks(build_type))); return sortFilesByDate(builders.ant.findOutputApks(build_type, arch).concat(builders.gradle.findOutputApks(build_type, arch)));
} }
} }
}; };
function parseOpts(options) { function parseOpts(options, resolvedTarget) {
// Backwards-compatibility: Allow a single string argument // Backwards-compatibility: Allow a single string argument
if (typeof options == "string") options = [options]; if (typeof options == "string") options = [options];
var ret = { var ret = {
buildType: 'debug', buildType: 'debug',
buildMethod: process.env['ANDROID_BUILD'] || 'ant' buildMethod: process.env['ANDROID_BUILD'] || 'ant',
arch: null
}; };
// Iterate through command line options // Iterate through command line options
@ -333,6 +348,12 @@ function parseOpts(options) {
return Q.reject('Build option \'' + options[i] + '\' not recognized.'); return Q.reject('Build option \'' + options[i] + '\' not recognized.');
} }
} }
var multiApk = ret.buildMethod == 'gradle' && process.env['BUILD_MULTIPLE_APKS'];
if (multiApk && !/0|false|no/i.exec(multiApk)) {
ret.arch = resolvedTarget && resolvedTarget.arch;
}
return ret; return ret;
} }
@ -355,15 +376,14 @@ module.exports.runClean = function(options) {
* Builds the project with the specifed options * Builds the project with the specifed options
* Returns a promise. * Returns a promise.
*/ */
module.exports.run = function(options) { module.exports.run = function(options, optResolvedTarget) {
var opts = parseOpts(options); var opts = parseOpts(options, optResolvedTarget);
var builder = builders[opts.buildMethod]; var builder = builders[opts.buildMethod];
return builder.prepEnv() return builder.prepEnv()
.then(function() { .then(function() {
return builder.build(opts.buildType); return builder.build(opts.buildType, opts.arch);
}).then(function() { }).then(function() {
var apkPaths = builder.findOutputApks(opts.buildType); var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
console.log('Built the following apk(s):'); console.log('Built the following apk(s):');
console.log(' ' + apkPaths.join('\n ')); console.log(' ' + apkPaths.join('\n '));
return { return {

View File

@ -43,20 +43,14 @@ module.exports.list = function() {
}); });
} }
/* module.exports.resolveTarget = function(target) {
* Installs a previously built application on the device
* and launches it.
* Returns a promise.
*/
module.exports.install = function(target, buildResults) {
var launchName;
return this.list() return this.list()
.then(function(device_list) { .then(function(device_list) {
if (!device_list || !device_list.length) if (!device_list || !device_list.length) {
return Q.reject('ERROR: Failed to deploy to device, no devices found.'); return Q.reject('ERROR: Failed to deploy to device, no devices found.');
}
// default device // default device
target = typeof target !== 'undefined' ? target : device_list[0]; target = target || device_list[0];
if (device_list.indexOf(target) < 0) { if (device_list.indexOf(target) < 0) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.'); return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
@ -64,28 +58,45 @@ module.exports.install = function(target, buildResults) {
return build.detectArchitecture(target) return build.detectArchitecture(target)
.then(function(arch) { .then(function(arch) {
var apk_path = build.findBestApkForArchitecture(buildResults, arch); return { target: target, arch: arch, isEmulator: false };
launchName = appinfo.getActivityName(); });
});
};
/*
* Installs a previously built application on the device
* and launches it.
* Returns a promise.
*/
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var launchName = appinfo.getActivityName();
console.log('Using apk: ' + apk_path); console.log('Using apk: ' + apk_path);
console.log('Installing app on device...'); console.log('Installing app on device...');
var cmd = 'adb -s ' + target + ' install -r "' + apk_path + '"'; var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
return exec(cmd); return exec(cmd)
}); .then(function(output) {
}).then(function(output) {
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output); if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
//unlock screen //unlock screen
var cmd = 'adb -s ' + target + ' shell input keyevent 82'; var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
return exec(cmd); return exec(cmd);
}, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); }) }, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
.then(function() { .then(function() {
// launch the application // launch the application
console.log('Launching application...'); console.log('Launching application...');
var cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName; var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd); return exec(cmd);
}).then(function() { }).then(function() {
console.log('LAUNCH SUCCESS'); console.log('LAUNCH SUCCESS');
}, function(err) { }, function(err) {
return Q.reject('ERROR: Failed to launch application on device: ' + err); return Q.reject('ERROR: Failed to launch application on device: ' + err);
}); });
});
} }

View File

@ -273,14 +273,7 @@ module.exports.create_image = function(name, target) {
} }
} }
/* module.exports.resolveTarget = function(target) {
* Installs a previously built application on the emulator and launches it.
* If no target is specified, then it picks one.
* If no started emulators are found, error out.
* Returns a promise.
*/
module.exports.install = function(target, buildResults) {
var self = this;
return this.list_started() return this.list_started()
.then(function(emulator_list) { .then(function(emulator_list) {
if (emulator_list.length < 1) { if (emulator_list.length < 1) {
@ -288,19 +281,36 @@ module.exports.install = function(target, buildResults) {
} }
// default emulator // default emulator
target = typeof target !== 'undefined' ? target : emulator_list[0]; target = target || emulator_list[0];
if (emulator_list.indexOf(target) < 0) { if (emulator_list.indexOf(target) < 0) {
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.'); return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
} }
return build.detectArchitecture(target) return build.detectArchitecture(target)
.then(function(arch) { .then(function(arch) {
var apk_path = build.findBestApkForArchitecture(buildResults, arch); return {target:target, arch:arch, isEmulator:true};
});
});
};
/*
* Installs a previously built application on the emulator and launches it.
* If no target is specified, then it picks one.
* If no started emulators are found, error out.
* Returns a promise.
*/
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
console.log('Installing app on emulator...'); console.log('Installing app on emulator...');
console.log('Using apk: ' + apk_path); console.log('Using apk: ' + apk_path);
return exec('adb -s ' + target + ' install -r "' + apk_path + '"'); return exec('adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"')
}); .then(function(output) {
}).then(function(output) {
if (output.match(/Failure/)) { if (output.match(/Failure/)) {
return Q.reject('Failed to install apk to emulator: ' + output); return Q.reject('Failed to install apk to emulator: ' + output);
} }
@ -309,16 +319,17 @@ module.exports.install = function(target, buildResults) {
return Q.reject('Failed to install apk to emulator: ' + err); return Q.reject('Failed to install apk to emulator: ' + err);
}).then(function() { }).then(function() {
//unlock screen //unlock screen
return exec('adb -s ' + target + ' shell input keyevent 82'); return exec('adb -s ' + resolvedTarget.target + ' shell input keyevent 82');
}).then(function() { }).then(function() {
// launch the application // launch the application
console.log('Launching application...'); console.log('Launching application...');
var launchName = appinfo.getActivityName(); var launchName = appinfo.getActivityName();
cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName; cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
return exec(cmd); return exec(cmd);
}).then(function(output) { }).then(function(output) {
console.log('LAUNCH SUCCESS'); console.log('LAUNCH SUCCESS');
}, function(err) { }, function(err) {
return Q.reject('Failed to launch app on emulator: ' + err); return Q.reject('Failed to launch app on emulator: ' + err);
}); });
});
} }

View File

@ -55,73 +55,66 @@ var path = require('path'),
} }
} }
return build.run(buildFlags).then(function(buildResults) { return Q()
if (install_target == '--device') { .then(function() {
return device.install(null, buildResults); if (!install_target) {
} 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(null, buildResults); });
});
} else if (install_target) {
var devices, started_emulators, avds;
return device.list()
.then(function(res) {
devices = res;
return emulator.list_started();
}).then(function(res) {
started_emulators = res;
return emulator.list_images();
}).then(function(res) {
avds = res;
if (devices.indexOf(install_target) > -1) {
return device.install(install_target, buildResults);
} else if (started_emulators.indexOf(install_target) > -1) {
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, buildResults); });
}
}
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
}
});
} else {
// no target given, deploy to device if available, otherwise use the emulator. // no target given, deploy to device if available, otherwise use the emulator.
return device.list() return device.list()
.then(function(device_list) { .then(function(device_list) {
if (device_list.length > 0) { if (device_list.length > 0) {
console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.'); console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
return device.install(device_list[0], buildResults); install_target = device_list[0];
} else { } else {
console.log('WARNING : No target specified, deploying to emulator');
install_target = '--emulator';
}
});
}
}).then(function() {
if (install_target == '--device') {
return device.resolveTarget(null);
} else if (install_target == '--emulator') {
// Give preference to any already started emulators. Else, start one.
return emulator.list_started() return emulator.list_started()
.then(function(emulator_list) { .then(function(started) {
if (emulator_list.length > 0) { return started && started.length > 0 ? started[0] : emulator.start();
console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.'); }).then(function(emulatorId) {
return emulator.install(emulator_list[0], buildResults); return emulator.resolveTarget(emulatorId);
} else {
console.log('WARNING : No started emulators found, starting an emulator.');
return emulator.best_image()
.then(function(best_avd) {
if(best_avd) {
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, buildResults);
});
} else {
return emulator.start();
}
}); });
} }
// They specified a specific device/emulator ID.
return device.list()
.then(function(devices) {
if (devices.indexOf(install_target) > -1) {
return device.resolveTarget(install_target);
}
return emulator.list_started()
.then(function(started_emulators) {
if (started_emulators.indexOf(install_target) > -1) {
return emulator.resolveTarget(install_target);
}
return emulator.list_images()
.then(function(avds) {
// if target emulator isn't started, then start it.
for (avd in avds) {
if (avds[avd].name == install_target) {
return emulator.start(install_target)
.then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
}); });
} }
});
} }
return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
});
});
});
}).then(function(resolvedTarget) {
return build.run(buildFlags, resolvedTarget).then(function(buildResults) {
if (resolvedTarget.isEmulator) {
return emulator.install(resolvedTarget, buildResults);
}
return device.install(resolvedTarget, buildResults);
});
}); });
} }