You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by db...@apache.org on 2015/06/12 20:53:01 UTC
android commit: CB-9119 Adding lib/retry.js for retrying
promise-returning functions. Retrying 'adb install' in emulator.js because it
sometimes hangs.
Repository: cordova-android
Updated Branches:
refs/heads/master eb70f0516 -> c0312f9b5
CB-9119 Adding lib/retry.js for retrying promise-returning functions. Retrying 'adb install' in emulator.js because it sometimes hangs.
Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/c0312f9b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/c0312f9b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/c0312f9b
Branch: refs/heads/master
Commit: c0312f9b502c5b947040244b0f4acfb05741e6c5
Parents: eb70f05
Author: Dmitry Blotsky <dm...@gmail.com>
Authored: Mon Jun 8 17:17:12 2015 -0700
Committer: Dmitry Blotsky <dm...@gmail.com>
Committed: Fri Jun 12 11:50:15 2015 -0700
----------------------------------------------------------------------
bin/templates/cordova/lib/emulator.js | 98 +++++++++++++++++++++---------
bin/templates/cordova/lib/exec.js | 39 ++++++++++--
bin/templates/cordova/lib/retry.js | 66 ++++++++++++++++++++
3 files changed, 167 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/c0312f9b/bin/templates/cordova/lib/emulator.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js
index 5e79152..e81dd67 100644
--- a/bin/templates/cordova/lib/emulator.js
+++ b/bin/templates/cordova/lib/emulator.js
@@ -21,14 +21,22 @@
/* jshint sub:true */
-var exec = require('./exec'),
- Q = require('q'),
- os = require('os'),
- appinfo = require('./appinfo'),
- build = require('./build'),
- child_process = require('child_process');
+var exec = require('./exec');
+var appinfo = require('./appinfo');
+var retry = require('./retry');
+var build = require('./build');
var check_reqs = require('./check_reqs');
+var Q = require('q');
+var os = require('os');
+var child_process = require('child_process');
+
+// constants
+var ONE_SECOND = 1000; // in milliseconds
+var INSTALL_COMMAND_TIMEOUT = 120 * ONE_SECOND; // in milliseconds
+var NUM_INSTALL_RETRIES = 3;
+var EXEC_KILL_SIGNAL = 'SIGKILL';
+
/**
* Returns a Promise for a list of emulator images in the form of objects
* {
@@ -298,37 +306,67 @@ module.exports.resolveTarget = function(target) {
* 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;
+module.exports.install = function(givenTarget, buildResults) {
+
+ var target;
+
+ // resolve the target emulator
+ return Q().then(function () {
+ if (givenTarget && typeof givenTarget == 'object') {
+ return givenTarget;
+ } else {
+ return module.exports.resolveTarget(givenTarget);
}
- return module.exports.resolveTarget(target);
- }).then(function(resolvedTarget) {
- var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
+
+ // set the resolved target
+ }).then(function (resolvedTarget) {
+ target = resolvedTarget;
+
+ // install the app
+ }).then(function () {
+
+ var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
+ var execOptions = {
+ timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
+ killSignal: EXEC_KILL_SIGNAL
+ };
+
console.log('Installing app on emulator...');
console.log('Using apk: ' + apk_path);
- return exec('adb -s ' + resolvedTarget.target + ' install -r -d "' + apk_path + '"', os.tmpdir())
- .then(function(output) {
+
+ var retriedInstall = retry.retryPromise(
+ NUM_INSTALL_RETRIES,
+ exec, 'adb -s ' + target.target + ' install -r -d "' + apk_path + '"', os.tmpdir(), execOptions
+ );
+
+ return retriedInstall.then(function (output) {
if (output.match(/Failure/)) {
return Q.reject('Failed to install apk to emulator: ' + output);
+ } else {
+ console.log('INSTALL SUCCESS');
}
- return Q();
- }, function(err) {
+ }, function (err) {
return Q.reject('Failed to install apk to emulator: ' + err);
- }).then(function() {
- //unlock screen
- return exec('adb -s ' + resolvedTarget.target + ' shell input keyevent 82', os.tmpdir());
- }).then(function() {
- // launch the application
- console.log('Launching application...');
- var launchName = appinfo.getActivityName();
- var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
- return exec(cmd, os.tmpdir());
- }).then(function(output) {
- console.log('LAUNCH SUCCESS');
- }, function(err) {
- return Q.reject('Failed to launch app on emulator: ' + err);
});
+
+ // unlock screen
+ }).then(function () {
+
+ console.log('Unlocking screen...');
+ return exec('adb -s ' + target.target + ' shell input keyevent 82', os.tmpdir());
+
+ // launch the application
+ }).then(function () {
+
+ console.log('Launching application...');
+ var launchName = appinfo.getActivityName();
+ var cmd = 'adb -s ' + target.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
+ return exec(cmd, os.tmpdir());
+
+ // report success or failure
+ }).then(function (output) {
+ console.log('LAUNCH SUCCESS');
+ }, function (err) {
+ return Q.reject('Failed to launch app on emulator: ' + err);
});
};
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/c0312f9b/bin/templates/cordova/lib/exec.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/exec.js b/bin/templates/cordova/lib/exec.js
index 342b6fb..798a93b 100644
--- a/bin/templates/cordova/lib/exec.js
+++ b/bin/templates/cordova/lib/exec.js
@@ -19,23 +19,50 @@
under the License.
*/
-var child_process = require('child_process'),
- Q = require('q');
+var child_process = require("child_process");
+var Q = require("q");
+
+// constants
+var DEFAULT_MAX_BUFFER = 1024000;
// Takes a command and optional current working directory.
// Returns a promise that either resolves with the stdout, or
// rejects with an error message and the stderr.
-module.exports = function(cmd, opt_cwd) {
+//
+// WARNING:
+// opt_cwd is an artifact of an old design, and must
+// be removed in the future; the correct solution is
+// to pass the options object the same way that
+// child_process.exec expects
+//
+// NOTE:
+// exec documented here - https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
+module.exports = function(cmd, opt_cwd, options) {
+
var d = Q.defer();
+
+ if (typeof options === "undefined") {
+ options = {};
+ }
+
+ // override cwd to preserve old opt_cwd behavior
+ options.cwd = opt_cwd;
+
+ // set maxBuffer
+ if (typeof options.maxBuffer === "undefined") {
+ options.maxBuffer = DEFAULT_MAX_BUFFER;
+ }
+
try {
- child_process.exec(cmd, {cwd: opt_cwd, maxBuffer: 1024000}, function(err, stdout, stderr) {
- if (err) d.reject('Error executing "' + cmd + '": ' + stderr);
+ child_process.exec(cmd, options, function(err, stdout, stderr) {
+ if (err) d.reject("Error executing \"" + cmd + "\": " + stderr);
else d.resolve(stdout);
});
} catch(e) {
- console.error('error caught: ' + e);
+ console.error("error caught: " + e);
d.reject(e);
}
+
return d.promise;
};
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/c0312f9b/bin/templates/cordova/lib/retry.js
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/retry.js b/bin/templates/cordova/lib/retry.js
new file mode 100644
index 0000000..dc52a7d
--- /dev/null
+++ b/bin/templates/cordova/lib/retry.js
@@ -0,0 +1,66 @@
+#!/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.
+*/
+
+/* jshint node: true */
+
+"use strict";
+
+/*
+ * Retry a promise-returning function a number of times, propagating its
+ * results on success or throwing its error on a failed final attempt.
+ *
+ * @arg {Number} attemts_left - The number of times to retry the passed call.
+ * @arg {Function} promiseFunction - A function that returns a promise.
+ * @arg {...} - Arguments to pass to promiseFunction.
+ *
+ * @returns {Promise}
+ */
+module.exports.retryPromise = function (attemts_left, promiseFunction) {
+
+ // NOTE:
+ // get all trailing arguments, by skipping the first two (attemts_left and
+ // promiseFunction) because they shouldn't get passed to promiseFunction
+ var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
+
+ return promiseFunction.apply(undefined, promiseFunctionArguments).then(
+
+ // on success pass results through
+ function onFulfilled(value) {
+ return value;
+ },
+
+ // on rejection either retry, or throw the error
+ function onRejected(error) {
+
+ attemts_left -= 1;
+
+ if (attemts_left < 1) {
+ throw error;
+ }
+
+ console.log("A retried call failed. Retrying " + attemts_left + " more time(s).");
+
+ // retry call self again with the same arguments, except attemts_left is now lower
+ var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
+ return module.exports.retryPromise.apply(undefined, fullArguments);
+ }
+ );
+};
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org