b2g/simulator/lib/simulator-process.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/b2g/simulator/lib/simulator-process.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,193 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 + */
     1.8 +
     1.9 +'use strict';
    1.10 +
    1.11 +const { Cc, Ci, Cu, ChromeWorker } = require("chrome");
    1.12 +
    1.13 +Cu.import("resource://gre/modules/Services.jsm");
    1.14 +
    1.15 +const { EventTarget } = require("sdk/event/target");
    1.16 +const { emit, off } = require("sdk/event/core");
    1.17 +const { Class } = require("sdk/core/heritage");
    1.18 +const Environment = require("sdk/system/environment").env;
    1.19 +const Runtime = require("sdk/system/runtime");
    1.20 +const Self = require("sdk/self");
    1.21 +const URL = require("sdk/url");
    1.22 +const Subprocess = require("subprocess");
    1.23 +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
    1.24 +const Prefs = require("sdk/simple-prefs").prefs;
    1.25 +
    1.26 +const { rootURI: ROOT_URI } = require('@loader/options');
    1.27 +const PROFILE_URL = ROOT_URI + "profile/";
    1.28 +const BIN_URL = ROOT_URI + "b2g/";
    1.29 +
    1.30 +// Log subprocess error and debug messages to the console.  This logs messages
    1.31 +// for all consumers of the API.  We trim the messages because they sometimes
    1.32 +// have trailing newlines.  And note that registerLogHandler actually registers
    1.33 +// an error handler, despite its name.
    1.34 +Subprocess.registerLogHandler(
    1.35 +  function(s) console.error("subprocess: " + s.trim())
    1.36 +);
    1.37 +Subprocess.registerDebugHandler(
    1.38 +  function(s) console.debug("subprocess: " + s.trim())
    1.39 +);
    1.40 +
    1.41 +exports.SimulatorProcess = Class({
    1.42 +  extends: EventTarget,
    1.43 +  initialize: function initialize(options) {
    1.44 +    EventTarget.prototype.initialize.call(this, options);
    1.45 +
    1.46 +    this.on("stdout", function onStdout(data) console.log(data.trim()));
    1.47 +    this.on("stderr", function onStderr(data) console.error(data.trim()));
    1.48 +  },
    1.49 +
    1.50 +  // check if b2g is running
    1.51 +  get isRunning() !!this.process,
    1.52 +
    1.53 +  /**
    1.54 +   * Start the process and connect the debugger client.
    1.55 +   */
    1.56 +  run: function() {
    1.57 +    // kill before start if already running
    1.58 +    if (this.process != null) {
    1.59 +      this.process
    1.60 +          .kill()
    1.61 +          .then(this.run.bind(this));
    1.62 +      return;
    1.63 +    }
    1.64 +
    1.65 +    // resolve b2g binaries path (raise exception if not found)
    1.66 +    let b2gExecutable = this.b2gExecutable;
    1.67 +
    1.68 +    this.once("stdout", function () {
    1.69 +      if (Runtime.OS == "Darwin") {
    1.70 +          console.debug("WORKAROUND run osascript to show b2g-desktop window"+
    1.71 +                        " on Runtime.OS=='Darwin'");
    1.72 +        // Escape double quotes and escape characters for use in AppleScript.
    1.73 +        let path = b2gExecutable.path
    1.74 +          .replace(/\\/g, "\\\\").replace(/\"/g, '\\"');
    1.75 +
    1.76 +        Subprocess.call({
    1.77 +          command: "/usr/bin/osascript",
    1.78 +          arguments: ["-e", 'tell application "' + path + '" to activate'],
    1.79 +        });
    1.80 +      }
    1.81 +    });
    1.82 +
    1.83 +    let environment;
    1.84 +    if (Runtime.OS == "Linux") {
    1.85 +      environment = ["TMPDIR=" + Services.dirsvc.get("TmpD",Ci.nsIFile).path];
    1.86 +      if ("DISPLAY" in Environment) {
    1.87 +        environment.push("DISPLAY=" + Environment.DISPLAY);
    1.88 +      }
    1.89 +    }
    1.90 +
    1.91 +    // spawn a b2g instance
    1.92 +    this.process = Subprocess.call({
    1.93 +      command: b2gExecutable,
    1.94 +      arguments: this.b2gArguments,
    1.95 +      environment: environment,
    1.96 +
    1.97 +      // emit stdout event
    1.98 +      stdout: (function(data) {
    1.99 +        emit(this, "stdout", data);
   1.100 +      }).bind(this),
   1.101 +
   1.102 +      // emit stderr event
   1.103 +      stderr: (function(data) {
   1.104 +        emit(this, "stderr", data);
   1.105 +      }).bind(this),
   1.106 +
   1.107 +      // on b2g instance exit, reset tracked process, remoteDebuggerPort and
   1.108 +      // shuttingDown flag, then finally emit an exit event
   1.109 +      done: (function(result) {
   1.110 +        console.log(this.b2gFilename + " terminated with " + result.exitCode);
   1.111 +        this.process = null;
   1.112 +        emit(this, "exit", result.exitCode);
   1.113 +      }).bind(this)
   1.114 +    });
   1.115 +  },
   1.116 +
   1.117 +  // request a b2g instance kill
   1.118 +  kill: function() {
   1.119 +    let deferred = promise.defer();
   1.120 +    if (this.process) {
   1.121 +      this.once("exit", (exitCode) => {
   1.122 +        this.shuttingDown = false;
   1.123 +        deferred.resolve(exitCode);
   1.124 +      });
   1.125 +      if (!this.shuttingDown) {
   1.126 +        this.shuttingDown = true;
   1.127 +        emit(this, "kill", null);
   1.128 +        this.process.kill();
   1.129 +      }
   1.130 +      return deferred.promise;
   1.131 +    } else {
   1.132 +      return promise.resolve(undefined);
   1.133 +    }
   1.134 +  },
   1.135 +
   1.136 +  // compute current b2g filename
   1.137 +  get b2gFilename() {
   1.138 +    return this._executable ? this._executableFilename : "B2G";
   1.139 +  },
   1.140 +
   1.141 +  // compute current b2g file handle
   1.142 +  get b2gExecutable() {
   1.143 +    if (this._executable) {
   1.144 +      return this._executable;
   1.145 +    }
   1.146 +
   1.147 +    if (Prefs.customRuntime) {
   1.148 +      this._executable = Prefs.customRuntime;
   1.149 +      this._executableFilename = "Custom runtime";
   1.150 +      return this._executable;
   1.151 +    }
   1.152 +
   1.153 +    let bin = URL.toFilename(BIN_URL);
   1.154 +    let executables = {
   1.155 +      WINNT: "b2g-bin.exe",
   1.156 +      Darwin: "B2G.app/Contents/MacOS/b2g-bin",
   1.157 +      Linux: "b2g-bin",
   1.158 +    };
   1.159 +
   1.160 +    let path = bin;
   1.161 +    path += Runtime.OS == "WINNT" ? "\\" : "/";
   1.162 +    path += executables[Runtime.OS];
   1.163 +    console.log("simulator path: " + path);
   1.164 +
   1.165 +    let executable = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
   1.166 +    executable.initWithPath(path);
   1.167 +
   1.168 +    if (!executable.exists()) {
   1.169 +      // B2G binaries not found
   1.170 +      throw Error("b2g-desktop Executable not found.");
   1.171 +    }
   1.172 +
   1.173 +    this._executable = executable;
   1.174 +    this._executableFilename = "b2g-bin";
   1.175 +
   1.176 +    return executable;
   1.177 +  },
   1.178 +
   1.179 +  // compute b2g CLI arguments
   1.180 +  get b2gArguments() {
   1.181 +    let args = [];
   1.182 +
   1.183 +    let profile = Prefs.gaiaProfile || URL.toFilename(PROFILE_URL);
   1.184 +    args.push("-profile", profile);
   1.185 +    console.log("profile", profile);
   1.186 +
   1.187 +    // NOTE: push dbgport option on the b2g-desktop commandline
   1.188 +    args.push("-start-debugger-server", "" + this.remoteDebuggerPort);
   1.189 +
   1.190 +    // Ignore eventual zombie instances of b2g that are left over
   1.191 +    args.push("-no-remote");
   1.192 +
   1.193 +    return args;
   1.194 +  },
   1.195 +});
   1.196 +

mercurial