diff --git a/tools/commands-cordova.js b/tools/commands-cordova.js index e4d5a14d2b..2e95821951 100644 --- a/tools/commands-cordova.js +++ b/tools/commands-cordova.js @@ -49,8 +49,21 @@ var isValidPlatform = function (name) { } }; -var cordova = exports; +var splitN = function (s, split, n) { + if (n <= 1) { + return s; + } + var tokens = s.split(split); + if (tokens.length <= n) { + return tokens; + } + var firstN = tokens.slice(0, n - 1); + var tail = tokens.slice(n).join(split); + firstN.push(tail); + return firstN; +}; +var cordova = exports; // --- the public interface --- @@ -808,11 +821,28 @@ _.extend(CordovaRunner.prototype, { start: function () { var self = this; + // android, not android-device + if (self.platformName == 'android') { + Android.waitForEmulator(); + } + execCordovaOnPlatform(self.localPath, self.platformName, self.options); }, + prestart: function () { + var self = this; + + // android, not android-device + if (self.platformName == 'android') { + if (!Android.isEmulatorRunning()) { + Console.info("Starting android emulator"); + Android.startEmulator(); + } + } + }, + stop: function () { var self = this; @@ -1668,7 +1698,7 @@ _.extend(Android.prototype, { getAvdName: function () { var self = this; - return "meteor"; + return process.env.METEOR_AVD || "meteor"; }, hasTarget: function (findApi, findArch) { @@ -1728,6 +1758,18 @@ _.extend(Android.prototype, { cmd.start(); }, + runAdb: function (args, options) { + var self = this; + + var androidBundlePath = self.getAndroidBundlePath(); + var adbPath = path.join(androidBundlePath, 'android-sdk', 'platform-tools', "adb"); + + var runOptions = options || {}; + runOptions.env = _.extend({}, process.env, { 'ANDROID_SDK_HOME': androidBundlePath }); + var cmd = new processes.RunCommand(adbPath, args, runOptions); + return cmd.run(); + }, + createAvd: function (avd, options) { var self = this; @@ -1856,6 +1898,66 @@ _.extend(Android.prototype, { ensureAndroidBundle(); }, + waitForEmulator: function () { + var self = this; + + var timeLimit = 120 * 1000; + var interval = 1000; + for (var i = 0; i < timeLimit / interval; i++) { + Console.debug("Waiting for emulator"); + if (self.isEmulatorRunning()) { + Console.debug("Found emulator"); + return; + } + utils.sleepMs(interval); + } + throw new Error("Emulator did not start in expected time"); + }, + + isEmulatorRunning: function () { + var self = this; + + var devices = self.listAdbDevices(); + return _.any(devices, function (device) { + if (device.id && device.id.indexOf('emulator-') == 0) { + if (device.state && device.state == 'device') { + return true; + } + } + return false; + }); + }, + + listAdbDevices: function () { + var self = this; + var execution = self.runAdb(['devices', '-l'], {}); + var devices = []; + _.each(execution.stdout.split('\n'), function (line) { + line = line.trim(); + line = line.replace('\t', ' '); + while (line.indexOf(' ') != -1) { + line = line.replace(' ', ' '); + } + if (line.length == 0) { + return; + } + if (line.indexOf("List of devices") === 0) { + return; + } + var tokens = line.split(' '); + var device = {}; + device.id = tokens[0]; + device.state = tokens[1]; + for (var i = 2; i < tokens.length; i++) { + var kv = splitN(tokens[i], ':', 2); + device[kv[0]] = kv[1]; + } + devices.push(device); + Console.debug("Found device", JSON.stringify(device)); + }); + return devices; + }, + checkRequirements: function (options) { var self = this; @@ -2057,6 +2159,7 @@ main.registerCommand({ Android.runAndroidTool(args, runOptions); } catch (err) { // this tool can crash for whatever reason, ignore its failures + Console.debug("Ignoring error from android tool", err); } return 0; }); @@ -2100,6 +2203,8 @@ main.registerCommand({ minArgs: 0, maxArgs: Infinity }, function (options) { + Console.setVerbose(options.verbose); + if (options.getready) { var okay = Android.checkRequirements({ log: true, fix: true}); if (!okay) { @@ -2107,6 +2212,14 @@ main.registerCommand({ } } + var args = options.args || []; + if (args.length) { + var arg = args[0]; + if (arg == "adb") { + Android.runAdb(args.slice(1), { pipeOutput: true, detached: true }); + } + } + return 0; }); diff --git a/tools/console.js b/tools/console.js index 2fcb53ca6f..151ead7ea4 100644 --- a/tools/console.js +++ b/tools/console.js @@ -214,7 +214,7 @@ _.extend(Console.prototype, { debug: function(/*arguments*/) { var self = this; - if (self._logThreshold > LEVEL_CODE_DEBUG) { + if (!self.verbose && self._logThreshold > LEVEL_CODE_DEBUG) { return; } @@ -251,7 +251,7 @@ _.extend(Console.prototype, { _legacyWrite: function (level, message) { var self = this; - if(message.substr(-1) == '\n') { + if(message.substr && message.substr(-1) == '\n') { message = message.substr(0, message.length - 1); } self._print(level, message); diff --git a/tools/processes.js b/tools/processes.js index 8525e5529f..e208733f4b 100644 --- a/tools/processes.js +++ b/tools/processes.js @@ -92,8 +92,11 @@ _.extend(RunCommand.prototype, { var self = this; self.start(); + if (self.options.detached) { + Console.debug("run called on detached process; won't wait"); + return undefined; + } self.waitForExit(); - return { stdout: self.stdout, stderr: self.stderr, exitCode: self.exitCode }; } }); diff --git a/tools/run-all.js b/tools/run-all.js index 04f860df51..8f933115f9 100644 --- a/tools/run-all.js +++ b/tools/run-all.js @@ -113,6 +113,14 @@ _.extend(Runner.prototype, { start: function () { var self = this; + // XXX: Include all runners, and merge parallel-launch patch + var allRunners = [ ] ; + allRunners = allRunners.concat(self.extraRunners); + _.each(allRunners, function (runner) { + if (!runner) return; + runner.prestart && runner.prestart(); + }); + self.proxy.start(); // print the banner only once we've successfully bound the port