author | Ryan VanderMeulen <ryanvm@gmail.com> |
Mon, 10 Feb 2014 10:17:41 -0500 | |
changeset 167865 | a4260bb263b6a2a244ed516ecbcd9b99ceb0369e |
parent 167864 | cf1cc24b68ef8357a7020c3beacd2c3bc97f843f |
child 167866 | 8f50eb1030edcea37e96bfc5383fed31e97ec6a3 |
push id | 26190 |
push user | ryanvm@gmail.com |
push date | Mon, 10 Feb 2014 20:37:53 +0000 |
treeherder | mozilla-central@07739c5c874f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 944451 |
milestone | 30.0a1 |
backs out | 81f210d3ad52c0fe6f41a895444da1d91cb30b7a |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/build.mk +++ b/b2g/build.mk @@ -1,22 +1,17 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk - installer: @$(MAKE) -C b2g/installer installer package: @$(MAKE) -C b2g/installer -#ifdef FXOS_SIMULATOR - $(PYTHON) $(srcdir)/b2g/simulator/build_xpi.py $(MOZ_PKG_PLATFORM) -#endif install:: @echo 'B2G can't be installed directly.' @exit 1 upload:: @$(MAKE) -C b2g/installer upload
deleted file mode 100644 --- a/b2g/simulator/build_xpi.py +++ /dev/null @@ -1,145 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# Generate xpi for the simulator addon by: -# - building a special gaia profile for it, as we need: -# * more languages, and, -# * less apps -# than b2g desktop's one -# - retrieve usefull app version metadata from the build system -# - finally, use addon sdk's cfx tool to build the addon xpi -# that ships: -# * a small firefox addon registering to the app manager -# * b2g desktop runtime -# * gaia profile - -import sys, os, re, subprocess -from mozbuild.preprocessor import Preprocessor -from mozbuild.base import MozbuildObject -from mozbuild.util import ensureParentDir -from zipfile import ZipFile -from distutils.version import LooseVersion - -ftp_root_path = "/pub/mozilla.org/labs/fxos-simulator" -UPDATE_LINK = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/%(xpi_name)s" -UPDATE_URL = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/update.rdf" -XPI_NAME = "fxos-simulator-%(version)s-%(platform)s.xpi" - -class GaiaBuilder(object): - def __init__(self, build, gaia_path): - self.build = build - self.gaia_path = gaia_path - - def clean(self): - self.build._run_make(target="clean", directory=self.gaia_path) - - def profile(self, env): - self.build._run_make(target="profile", directory=self.gaia_path, num_jobs=1, silent=False, append_env=env) - - def override_prefs(self, srcfile): - # Note that each time we call `make profile` in gaia, a fresh new pref file is created - # cat srcfile >> profile/user.js - with open(os.path.join(self.gaia_path, "profile", "user.js"), "a") as userJs: - userJs.write(open(srcfile).read()) - -def process_package_overload(src, dst, version, app_buildid): - ensureParentDir(dst) - # First replace numeric version like '1.3' - # Then replace with 'slashed' version like '1_4' - # Finally set the full length addon version like 1.3.20131230 - defines = { - "NUM_VERSION": version, - "SLASH_VERSION": version.replace(".", "_"), - "FULL_VERSION": ("%s.%s" % (version, app_buildid)) - } - pp = Preprocessor(defines=defines) - pp.do_filter("substitution") - with open(dst, "w") as output: - with open(src, "r") as input: - pp.processFile(input=input, output=output) - -def add_dir_to_zip(zip, top, pathInZip, blacklist=()): - zf = ZipFile(zip, "a") - for dirpath, subdirs, files in os.walk(top): - dir_relpath = os.path.relpath(dirpath, top) - if dir_relpath.startswith(blacklist): - continue - zf.write(dirpath, os.path.join(pathInZip, dir_relpath)) - for filename in files: - relpath = os.path.join(dir_relpath, filename) - if relpath in blacklist: - continue - zf.write(os.path.join(dirpath, filename), - os.path.join(pathInZip, relpath)) - zf.close() - -def main(platform): - build = MozbuildObject.from_environment() - topsrcdir = build.topsrcdir - distdir = build.distdir - - srcdir = os.path.join(topsrcdir, "b2g", "simulator") - - app_buildid = open(os.path.join(build.topobjdir, "config", "buildid")).read().strip() - - # The simulator uses a shorter version string, - # it only keeps the major version digits A.B - # whereas MOZ_B2G_VERSION is A.B.C.D - b2g_version = build.config_environment.defines["MOZ_B2G_VERSION"].replace('"', '') - version = ".".join(str(n) for n in LooseVersion(b2g_version).version[0:2]) - - # Build a gaia profile specific to the simulator in order to: - # - disable the FTU - # - set custom prefs to enable devtools debugger server - # - set custom settings to disable lockscreen and screen timeout - # - only ship production apps - gaia_path = build.config_environment.substs["GAIADIR"] - builder = GaiaBuilder(build, gaia_path) - builder.clean() - env = { - "NOFTU": "1", - "GAIA_APP_TARGET": "production", - "SETTINGS_PATH": os.path.join(srcdir, "custom-settings.json") - } - builder.profile(env) - builder.override_prefs(os.path.join(srcdir, "custom-prefs.js")) - - # Substitute version strings in the package manifest overload file - manifest_overload = os.path.join(build.topobjdir, "b2g", "simulator", "package-overload.json") - process_package_overload(os.path.join(srcdir, "package-overload.json.in"), - manifest_overload, - version, - app_buildid) - - # Build the simulator addon xpi - xpi_name = XPI_NAME % {"version": version, "platform": platform} - xpi_path = os.path.join(distdir, xpi_name) - - update_path = "%s/%s" % (version, platform) - update_link = UPDATE_LINK % {"update_path": update_path, "xpi_name": xpi_name} - update_url = UPDATE_URL % {"update_path": update_path} - subprocess.check_call([ - build.virtualenv_manager.python_path, os.path.join(topsrcdir, "addon-sdk", "source", "bin", "cfx"), "xpi", \ - "--pkgdir", srcdir, \ - "--manifest-overload", manifest_overload, \ - "--strip-sdk", \ - "--update-link", update_link, \ - "--update-url", update_url, \ - "--static-args", "{\"label\": \"Firefox OS %s\"}" % version, \ - "--output-file", xpi_path \ - ]) - - # Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi - add_dir_to_zip(xpi_path, os.path.join(distdir, "b2g"), "b2g", ("gaia")) - # Then ship our own gaia profile - add_dir_to_zip(xpi_path, os.path.join(gaia_path, "profile"), "profile") - -if __name__ == '__main__': - if 2 != len(sys.argv): - print("""Usage: - python {0} MOZ_PKG_PLATFORM -""".format(sys.argv[0])) - sys.exit(1) - main(*sys.argv[1:]) -
deleted file mode 100644 --- a/b2g/simulator/custom-prefs.js +++ /dev/null @@ -1,2 +0,0 @@ -user_pref("devtools.debugger.prompt-connection", false); -user_pref("devtools.debugger.forbid-certified-apps", false);
deleted file mode 100644 --- a/b2g/simulator/custom-settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "debugger.remote-mode": "adb-devtools", - "screen.timeout": 0, - "lockscreen.enabled": false, - "lockscreen.locked": false -}
deleted file mode 100644 index c4307fc8418436bb6b2fd3a6afc702c2db28aa77..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 275cd04a5eae3f727c1272cb71d3090dbcecd732..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 --- a/b2g/simulator/lib/main.js +++ /dev/null @@ -1,52 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -const { Cc, Ci, Cu } = require("chrome"); - -const { SimulatorProcess } = require("./simulator-process"); -const Promise = require("sdk/core/promise"); -const Self = require("sdk/self"); -const System = require("sdk/system"); -const { Simulator } = Cu.import("resource://gre/modules/devtools/Simulator.jsm"); - -let process; - -function launch({ port }) { - // Close already opened simulation - if (process) { - return close().then(launch.bind(null, { port: port })); - } - - process = SimulatorProcess(); - process.remoteDebuggerPort = port; - process.run(); - - return Promise.resolve(); -} - -function close() { - if (!process) { - return Promise.resolve(); - } - let p = process; - process = null; - return p.kill(); -} - - -// Load data generated at build time that -// expose various information about the runtime we ship -let appinfo = System.staticArgs; - -Simulator.register(appinfo.label, { - appinfo: appinfo, - launch: launch, - close: close -}); - -require("sdk/system/unload").when(function () { - Simulator.unregister(appinfo.label); - close(); -});
deleted file mode 100644 --- a/b2g/simulator/lib/simulator-process.js +++ /dev/null @@ -1,182 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -'use strict'; - -const { Cc, Ci, Cu, ChromeWorker } = require("chrome"); - -Cu.import("resource://gre/modules/Services.jsm"); - -const { EventTarget } = require("sdk/event/target"); -const { emit, off } = require("sdk/event/core"); -const { Class } = require("sdk/core/heritage"); -const Environment = require("sdk/system/environment").env; -const Runtime = require("sdk/system/runtime"); -const Self = require("sdk/self"); -const URL = require("sdk/url"); -const Subprocess = require("subprocess"); -const Promise = require("sdk/core/promise"); - -const { rootURI: ROOT_URI } = require('@loader/options'); -const PROFILE_URL = ROOT_URI + "profile/"; -const BIN_URL = ROOT_URI + "b2g/"; - -// Log subprocess error and debug messages to the console. This logs messages -// for all consumers of the API. We trim the messages because they sometimes -// have trailing newlines. And note that registerLogHandler actually registers -// an error handler, despite its name. -Subprocess.registerLogHandler( - function(s) console.error("subprocess: " + s.trim()) -); -Subprocess.registerDebugHandler( - function(s) console.debug("subprocess: " + s.trim()) -); - -exports.SimulatorProcess = Class({ - extends: EventTarget, - initialize: function initialize(options) { - EventTarget.prototype.initialize.call(this, options); - - this.on("stdout", function onStdout(data) console.log(data.trim())); - this.on("stderr", function onStderr(data) console.error(data.trim())); - }, - - // check if b2g is running - get isRunning() !!this.process, - - /** - * Start the process and connect the debugger client. - */ - run: function() { - // kill before start if already running - if (this.process != null) { - this.process - .kill() - .then(this.run.bind(this)); - return; - } - - // resolve b2g binaries path (raise exception if not found) - let b2gExecutable = this.b2gExecutable; - - this.once("stdout", function () { - if (Runtime.OS == "Darwin") { - console.debug("WORKAROUND run osascript to show b2g-desktop window"+ - " on Runtime.OS=='Darwin'"); - // Escape double quotes and escape characters for use in AppleScript. - let path = b2gExecutable.path - .replace(/\\/g, "\\\\").replace(/\"/g, '\\"'); - - Subprocess.call({ - command: "/usr/bin/osascript", - arguments: ["-e", 'tell application "' + path + '" to activate'], - }); - } - }); - - let environment; - if (Runtime.OS == "Linux") { - environment = ["TMPDIR=" + Services.dirsvc.get("TmpD",Ci.nsIFile).path]; - if ("DISPLAY" in Environment) { - environment.push("DISPLAY=" + Environment.DISPLAY); - } - } - - // spawn a b2g instance - this.process = Subprocess.call({ - command: b2gExecutable, - arguments: this.b2gArguments, - environment: environment, - - // emit stdout event - stdout: (function(data) { - emit(this, "stdout", data); - }).bind(this), - - // emit stderr event - stderr: (function(data) { - emit(this, "stderr", data); - }).bind(this), - - // on b2g instance exit, reset tracked process, remoteDebuggerPort and - // shuttingDown flag, then finally emit an exit event - done: (function(result) { - console.log(this.b2gFilename + " terminated with " + result.exitCode); - this.process = null; - emit(this, "exit", result.exitCode); - }).bind(this) - }); - }, - - // request a b2g instance kill - kill: function() { - let deferred = Promise.defer(); - if (this.process) { - this.once("exit", (exitCode) => { - this.shuttingDown = false; - deferred.resolve(exitCode); - }); - if (!this.shuttingDown) { - this.shuttingDown = true; - emit(this, "kill", null); - this.process.kill(); - } - return deferred.promise; - } else { - return Promise.resolve(undefined); - } - }, - - // compute current b2g filename - get b2gFilename() { - return this._executable ? this._executableFilename : "B2G"; - }, - - // compute current b2g file handle - get b2gExecutable() { - if (this._executable) return this._executable; - - let bin = URL.toFilename(BIN_URL); - let executables = { - WINNT: "b2g-bin.exe", - Darwin: "Contents/MacOS/b2g-bin", - Linux: "b2g-bin", - }; - - console.log("bin url: "+bin+"/"+executables[Runtime.OS]); - let path = bin + "/" + executables[Runtime.OS]; - - let executable = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - executable.initWithPath(path); - - if (!executable.exists()) { - // B2G binaries not found - throw Error("b2g-desktop Executable not found."); - } - - this._executable = executable; - this._executableFilename = "b2g-bin"; - - return executable; - }, - - // compute b2g CLI arguments - get b2gArguments() { - let args = []; - - let profile = URL.toFilename(PROFILE_URL); - args.push("-profile", profile); - Cu.reportError(profile); - - // NOTE: push dbgport option on the b2g-desktop commandline - args.push("-dbgport", "" + this.remoteDebuggerPort); - - // Ignore eventual zombie instances of b2g that are left over - args.push("-no-remote"); - - return args; - }, -}); -
deleted file mode 100644 --- a/b2g/simulator/package-overload.json.in +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "fxos_@SLASH_VERSION@_simulator@mozilla.org", - "name": "fxos_@SLASH_VERSION@_simulator", - "version": "@FULL_VERSION@", - "fullName": "Firefox OS @NUM_VERSION@ Simulator", - "description": "a Firefox OS @NUM_VERSION@ simulator" -}
deleted file mode 100644 --- a/b2g/simulator/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "fxos_simulator@mozilla.org", - "name": "fxos_simulator", - "version": "1.0.dev", - "fullName": "Firefox OS Simulator", - "label": "Firefox OS", - "description": "a Firefox OS simulator", - "author": "Myk Melez (https://github.com/mykmelez)", - "contributors": [ - "Alexandre Poirot (https://github.com/ochameau)", - "Anant Narayanan (https://github.com/anantn)", - "Brandon Kase (https://github.com/bkase)", - "Breck Yunits (https://github.com/breck7)", - "César Carruitero (https://github.com/ccarruitero)", - "David Gomes (https://github.com/davidgomes)", - "Fabrice Desré (https://github.com/fabricedesre)", - "Fraser Tweedale (https://github.com/frasertweedale)", - "Harald Kirschner (https://github.com/digitarald)", - "Jérémie Patonnier (https://github.com/JeremiePat)", - "J. Ryan Stinnett (https://github.com/jryans)", - "Kan-Ru Chen (陳侃如) (https://github.com/kanru)", - "Louis Stowasser (https://github.com/louisstow)", - "Luca Greco (https://github.com/rpl)", - "Matthew Claypotch (https://github.com/potch)", - "Matthew Riley MacPherson (https://github.com/tofumatt)", - "Nick Desaulniers (https://github.com/nickdesaulniers)", - "Soumen Ganguly (https://github.com/SoumenG)", - "Sudheesh Singanamalla (https://github.com/sudheesh001)", - "Victor Bjelkholm (https://github.com/VictorBjelkholm)" - ], - "permissions": { - "private-browsing": true - }, - "license": "MPL 2.0", - "unpack": true, - "dependencies": ["subprocess"] -}
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/README.md +++ /dev/null @@ -1,124 +0,0 @@ -<h2>What's that?</h2> -Simply package enigmail hard work on providing IPC feature in mozilla platform. -So we are able to launch child proccesses from javascript, -and in our case, from addon-sdk libraries :) - -<h2>Sample of code:</h2> - This object allows to start a process, and read/write data to/from it - using stdin/stdout/stderr streams. - Usage example: - - const subprocess = require("subprocess"); - var p = subprocess.call({ - command: '/bin/foo', - arguments: ['-v', 'foo'], - environment: [ "XYZ=abc", "MYVAR=def" ], - charset: 'UTF-8', - workdir: '/home/foo', - //stdin: "some value to write to stdin\nfoobar", - stdin: function(stdin) { - stdin.write("some value to write to stdin\nfoobar"); - stdin.close(); - }, - stdout: function(data) { - dump("got data on stdout:" + data + "\n"); - }, - stderr: function(data) { - dump("got data on stderr:" + data + "\n"); - }, - done: function(result) { - dump("process terminated with " + result.exitCode + "\n"); - }, - mergeStderr: false - }); - p.wait(); // wait for the subprocess to terminate - // this will block the main thread, - // only do if you can wait that long - - - Description of parameters: - -------------------------- - Apart from <command>, all arguments are optional. - - command: either a |nsIFile| object pointing to an executable file or a - String containing the platform-dependent path to an executable - file. - - arguments: optional string array containing the arguments to the command. - - environment: optional string array containing environment variables to pass - to the command. The array elements must have the form - "VAR=data". Please note that if environment is defined, it - replaces any existing environment variables for the subprocess. - - charset: Output is decoded with given charset and a string is returned. - If charset is undefined, "UTF-8" is used as default. - To get binary data, set this to null and the returned string - is not decoded in any way. - - workdir: optional; String containing the platform-dependent path to a - directory to become the current working directory of the subprocess. - - stdin: optional input data for the process to be passed on standard - input. stdin can either be a string or a function. - A |string| gets written to stdin and stdin gets closed; - A |function| gets passed an object with write and close function. - Please note that the write() function will return almost immediately; - data is always written asynchronously on a separate thread. - - stdout: an optional function that can receive output data from the - process. The stdout-function is called asynchronously; it can be - called mutliple times during the execution of a process. - At a minimum at each occurance of \n or \r. - Please note that null-characters might need to be escaped - with something like 'data.replace(/\0/g, "\\0");'. - - stderr: an optional function that can receive stderr data from the - process. The stderr-function is called asynchronously; it can be - called mutliple times during the execution of a process. Please - note that null-characters might need to be escaped with - something like 'data.replace(/\0/g, "\\0");'. - (on windows it only gets called once right now) - - done: optional function that is called when the process has terminated. - The exit code from the process available via result.exitCode. If - stdout is not defined, then the output from stdout is available - via result.stdout. stderr data is in result.stderr - - mergeStderr: optional boolean value. If true, stderr is merged with stdout; - no data will be provided to stderr. - - - Description of object returned by subprocess.call(...) - ------------------------------------------------------ - The object returned by subprocess.call offers a few methods that can be - executed: - - wait(): waits for the subprocess to terminate. It is not required to use - wait; done will be called in any case when the subprocess terminated. - - kill(hardKill): kill the subprocess. Any open pipes will be closed and - done will be called. - hardKill [ignored on Windows]: - - false: signal the process terminate (SIGTERM) - - true: kill the process (SIGKILL) - - - Other methods in subprocess - --------------------------- - - registerDebugHandler(functionRef): register a handler that is called to get - debugging information - registerLogHandler(functionRef): register a handler that is called to get error - messages - - example: - subprocess.registerLogHandler( function(s) { dump(s); } ); - - -<h2>Credits:</h2> -All enigmail team working on IPC component. - The Initial Developer of this code is Jan Gerber. - Portions created by Jan Gerber <j@mailb.org>, - Patrick Brunschwig (author of almost all code) <patrick@mozilla-enigmail.org>, - Ramalingam Saravanan (from enigmail team) <svn@xmlterm.org>
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/lib/subprocess.js +++ /dev/null @@ -1,1543 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -'use strict'; - -const { Cc, Ci, Cu, ChromeWorker } = require("chrome"); - -Cu.import("resource://gre/modules/ctypes.jsm"); - -const NS_LOCAL_FILE = "@mozilla.org/file/local;1"; - -const Runtime = require("sdk/system/runtime"); -const Environment = require("sdk/system/environment").env; -const DEFAULT_ENVIRONMENT = []; -if (Runtime.OS == "Linux" && "DISPLAY" in Environment) { - DEFAULT_ENVIRONMENT.push("DISPLAY=" + Environment.DISPLAY); -} - -/* -Fake require statements to ensure worker scripts are packaged: -require("subprocess_worker_win.js"); -require("subprocess_worker_unix.js"); -*/ -const URL_PREFIX = module.uri.replace(/subprocess\.js/, ""); -const WORKER_URL_WIN = URL_PREFIX + "subprocess_worker_win.js"; -const WORKER_URL_UNIX = URL_PREFIX + "subprocess_worker_unix.js"; - -//Windows API definitions -if (ctypes.size_t.size == 8) { - var WinABI = ctypes.default_abi; -} else { - var WinABI = ctypes.winapi_abi; -} -const WORD = ctypes.uint16_t; -const DWORD = ctypes.uint32_t; -const LPDWORD = DWORD.ptr; - -const UINT = ctypes.unsigned_int; -const BOOL = ctypes.bool; -const HANDLE = ctypes.size_t; -const HWND = HANDLE; -const HMODULE = HANDLE; -const WPARAM = ctypes.size_t; -const LPARAM = ctypes.size_t; -const LRESULT = ctypes.size_t; -const ULONG_PTR = ctypes.uintptr_t; -const PVOID = ctypes.voidptr_t; -const LPVOID = PVOID; -const LPCTSTR = ctypes.jschar.ptr; -const LPCWSTR = ctypes.jschar.ptr; -const LPTSTR = ctypes.jschar.ptr; -const LPSTR = ctypes.char.ptr; -const LPCSTR = ctypes.char.ptr; -const LPBYTE = ctypes.char.ptr; - -const CREATE_NEW_CONSOLE = 0x00000010; -const CREATE_NO_WINDOW = 0x08000000; -const CREATE_UNICODE_ENVIRONMENT = 0x00000400; -const STARTF_USESHOWWINDOW = 0x00000001; -const STARTF_USESTDHANDLES = 0x00000100; -const SW_HIDE = 0; -const DUPLICATE_SAME_ACCESS = 0x00000002; -const STILL_ACTIVE = 259; -const INFINITE = DWORD(0xFFFFFFFF); -const WAIT_TIMEOUT = 0x00000102; - -/* -typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - LPVOID lpSecurityDescriptor; - BOOL bInheritHandle; -} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; -*/ -const SECURITY_ATTRIBUTES = new ctypes.StructType("SECURITY_ATTRIBUTES", [ - {"nLength": DWORD}, - {"lpSecurityDescriptor": LPVOID}, - {"bInheritHandle": BOOL}, -]); - -/* -typedef struct _STARTUPINFO { - DWORD cb; - LPTSTR lpReserved; - LPTSTR lpDesktop; - LPTSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; -} STARTUPINFO, *LPSTARTUPINFO; -*/ -const STARTUPINFO = new ctypes.StructType("STARTUPINFO", [ - {"cb": DWORD}, - {"lpReserved": LPTSTR}, - {"lpDesktop": LPTSTR}, - {"lpTitle": LPTSTR}, - {"dwX": DWORD}, - {"dwY": DWORD}, - {"dwXSize": DWORD}, - {"dwYSize": DWORD}, - {"dwXCountChars": DWORD}, - {"dwYCountChars": DWORD}, - {"dwFillAttribute": DWORD}, - {"dwFlags": DWORD}, - {"wShowWindow": WORD}, - {"cbReserved2": WORD}, - {"lpReserved2": LPBYTE}, - {"hStdInput": HANDLE}, - {"hStdOutput": HANDLE}, - {"hStdError": HANDLE}, -]); - -/* -typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; -} PROCESS_INFORMATION, *LPPROCESS_INFORMATION; -*/ -const PROCESS_INFORMATION = new ctypes.StructType("PROCESS_INFORMATION", [ - {"hProcess": HANDLE}, - {"hThread": HANDLE}, - {"dwProcessId": DWORD}, - {"dwThreadId": DWORD}, -]); - -/* -typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - PVOID Pointer; - }; - HANDLE hEvent; -} OVERLAPPED, *LPOVERLAPPED; -*/ -const OVERLAPPED = new ctypes.StructType("OVERLAPPED"); - -//UNIX definitions -const pid_t = ctypes.int32_t; -const WNOHANG = 1; -const F_GETFD = 1; -const F_SETFL = 4; - -const LIBNAME = 0; -const O_NONBLOCK = 1; -const RLIM_T = 2; -const RLIMIT_NOFILE = 3; - -function getPlatformValue(valueType) { - - if (! gXulRuntime) - gXulRuntime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); - - const platformDefaults = { - // Windows API: - 'winnt': [ 'kernel32.dll' ], - - // Unix API: - // library name O_NONBLOCK RLIM_T RLIMIT_NOFILE - 'darwin': [ 'libc.dylib', 0x04 , ctypes.uint64_t , 8 ], - 'linux': [ 'libc.so.6', 2024 , ctypes.unsigned_long, 7 ], - 'freebsd': [ 'libc.so.7', 0x04 , ctypes.int64_t , 8 ], - 'openbsd': [ 'libc.so.61.0', 0x04 , ctypes.int64_t , 8 ], - 'sunos': [ 'libc.so', 0x80 , ctypes.unsigned_long, 5 ] - } - - return platformDefaults[gXulRuntime.OS.toLowerCase()][valueType]; -} - - -var gDebugFunc = null, - gLogFunc = null, - gXulRuntime = null; - -function LogError(s) { - if (gLogFunc) - gLogFunc(s); - else - dump(s); -} - -function debugLog(s) { - if (gDebugFunc) - gDebugFunc(s); -} - -function setTimeout(callback, timeout) { - var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.initWithCallback(callback, timeout, Ci.nsITimer.TYPE_ONE_SHOT); -}; - -function getBytes(data) { - var string = ''; - data.forEach(function(x) { string += String.fromCharCode(x < 0 ? x + 256 : x) }); - return string; -} - -function readString(data, length, charset) { - var string = '', bytes = []; - for(var i = 0;i < length; i++) { - if(data[i] == 0 && charset !== null) // stop on NULL character for non-binary data - break - bytes.push(data[i]); - } - if (!bytes || bytes.length == 0) - return string; - if(charset === null) { - return bytes; - } - return convertBytes(bytes, charset); -} - -function convertBytes(bytes, charset) { - var string = ''; - charset = charset || 'UTF-8'; - var unicodeConv = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .getService(Ci.nsIScriptableUnicodeConverter); - try { - unicodeConv.charset = charset; - string = unicodeConv.convertFromByteArray(bytes, bytes.length); - } catch (ex) { - LogError("String conversion failed: "+ex.toString()+"\n") - string = ''; - } - string += unicodeConv.Finish(); - return string; -} - - -// temporary solution for removal of nsILocalFile -function getLocalFileApi() { - if ("nsILocalFile" in Ci) { - return Ci.nsILocalFile; - } - else - return Ci.nsIFile; -} - -function getCommandStr(command) { - let commandStr = null; - if (typeof(command) == "string") { - let file = Cc[NS_LOCAL_FILE].createInstance(getLocalFileApi()); - file.initWithPath(command); - if (! (file.isExecutable() && file.isFile())) - throw("File '"+command+"' is not an executable file"); - commandStr = command; - } - else { - if (! (command.isExecutable() && command.isFile())) - throw("File '"+command.path+"' is not an executable file"); - commandStr = command.path; - } - - return commandStr; -} - -function getWorkDir(workdir) { - let workdirStr = null; - if (typeof(workdir) == "string") { - let file = Cc[NS_LOCAL_FILE].createInstance(getLocalFileApi()); - file.initWithPath(workdir); - if (! (file.isDirectory())) - throw("Directory '"+workdir+"' does not exist"); - workdirStr = workdir; - } - else if (workdir) { - if (! workdir.isDirectory()) - throw("Directory '"+workdir.path+"' does not exist"); - workdirStr = workdir.path; - } - return workdirStr; -} - - -var subprocess = { - call: function(options) { - options.mergeStderr = options.mergeStderr || false; - options.workdir = options.workdir || null; - options.environment = options.environment || DEFAULT_ENVIRONMENT; - if (options.arguments) { - var args = options.arguments; - options.arguments = []; - args.forEach(function(argument) { - options.arguments.push(argument); - }); - } else { - options.arguments = []; - } - - options.libc = getPlatformValue(LIBNAME); - - if (gXulRuntime.OS.substring(0, 3) == "WIN") { - return subprocess_win32(options); - } else { - return subprocess_unix(options); - } - - }, - registerDebugHandler: function(func) { - gDebugFunc = func; - }, - registerLogHandler: function(func) { - gLogFunc = func; - } -}; - - - -function subprocess_win32(options) { - var kernel32dll = ctypes.open(options.libc), - hChildProcess, - active = true, - done = false, - exitCode = -1, - child = {}, - stdinWorker = null, - stdoutWorker = null, - stderrWorker = null, - pendingWriteCount = 0, - readers = options.mergeStderr ? 1 : 2, - stdinOpenState = 2, - error = '', - output = ''; - - // stdin pipe states - const OPEN = 2; - const CLOSEABLE = 1; - const CLOSED = 0; - - //api declarations - /* - BOOL WINAPI CloseHandle( - __in HANDLE hObject - ); - */ - var CloseHandle = kernel32dll.declare("CloseHandle", - WinABI, - BOOL, - HANDLE - ); - - /* - BOOL WINAPI CreateProcess( - __in_opt LPCTSTR lpApplicationName, - __inout_opt LPTSTR lpCommandLine, - __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, - __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, - __in BOOL bInheritHandles, - __in DWORD dwCreationFlags, - __in_opt LPVOID lpEnvironment, - __in_opt LPCTSTR lpCurrentDirectory, - __in LPSTARTUPINFO lpStartupInfo, - __out LPPROCESS_INFORMATION lpProcessInformation - ); - */ - var CreateProcessW = kernel32dll.declare("CreateProcessW", - WinABI, - BOOL, - LPCTSTR, - LPTSTR, - SECURITY_ATTRIBUTES.ptr, - SECURITY_ATTRIBUTES.ptr, - BOOL, - DWORD, - LPVOID, - LPCTSTR, - STARTUPINFO.ptr, - PROCESS_INFORMATION.ptr - ); - -// /* -// BOOL WINAPI ReadFile( -// __in HANDLE hFile, -// __out LPVOID ReadFileBuffer, -// __in DWORD nNumberOfBytesToRead, -// __out_opt LPDWORD lpNumberOfBytesRead, -// __inout_opt LPOVERLAPPED lpOverlapped -// ); -// */ -// var ReadFileBufferSize = 1024, -// ReadFileBuffer = ctypes.char.array(ReadFileBufferSize), -// ReadFile = kernel32dll.declare("ReadFile", -// WinABI, -// BOOL, -// HANDLE, -// ReadFileBuffer, -// DWORD, -// LPDWORD, -// OVERLAPPED.ptr -// ); -// -// /* -// BOOL WINAPI PeekNamedPipe( -// __in HANDLE hNamedPipe, -// __out_opt LPVOID lpBuffer, -// __in DWORD nBufferSize, -// __out_opt LPDWORD lpBytesRead, -// __out_opt LPDWORD lpTotalBytesAvail, -// __out_opt LPDWORD lpBytesLeftThisMessage -// ); -// */ -// var PeekNamedPipe = kernel32dll.declare("PeekNamedPipe", -// WinABI, -// BOOL, -// HANDLE, -// ReadFileBuffer, -// DWORD, -// LPDWORD, -// LPDWORD, -// LPDWORD -// ); -// -// /* -// BOOL WINAPI WriteFile( -// __in HANDLE hFile, -// __in LPCVOID lpBuffer, -// __in DWORD nNumberOfBytesToWrite, -// __out_opt LPDWORD lpNumberOfBytesWritten, -// __inout_opt LPOVERLAPPED lpOverlapped -// ); -// */ -// var WriteFile = kernel32dll.declare("WriteFile", -// WinABI, -// BOOL, -// HANDLE, -// ctypes.char.ptr, -// DWORD, -// LPDWORD, -// OVERLAPPED.ptr -// ); - - /* - BOOL WINAPI CreatePipe( - __out PHANDLE hReadPipe, - __out PHANDLE hWritePipe, - __in_opt LPSECURITY_ATTRIBUTES lpPipeAttributes, - __in DWORD nSize - ); - */ - var CreatePipe = kernel32dll.declare("CreatePipe", - WinABI, - BOOL, - HANDLE.ptr, - HANDLE.ptr, - SECURITY_ATTRIBUTES.ptr, - DWORD - ); - - /* - HANDLE WINAPI GetCurrentProcess(void); - */ - var GetCurrentProcess = kernel32dll.declare("GetCurrentProcess", - WinABI, - HANDLE - ); - - /* - DWORD WINAPI GetLastError(void); - */ - var GetLastError = kernel32dll.declare("GetLastError", - WinABI, - DWORD - ); - - /* - BOOL WINAPI DuplicateHandle( - __in HANDLE hSourceProcessHandle, - __in HANDLE hSourceHandle, - __in HANDLE hTargetProcessHandle, - __out LPHANDLE lpTargetHandle, - __in DWORD dwDesiredAccess, - __in BOOL bInheritHandle, - __in DWORD dwOptions - ); - */ - var DuplicateHandle = kernel32dll.declare("DuplicateHandle", - WinABI, - BOOL, - HANDLE, - HANDLE, - HANDLE, - HANDLE.ptr, - DWORD, - BOOL, - DWORD - ); - - - /* - BOOL WINAPI GetExitCodeProcess( - __in HANDLE hProcess, - __out LPDWORD lpExitCode - ); - */ - var GetExitCodeProcess = kernel32dll.declare("GetExitCodeProcess", - WinABI, - BOOL, - HANDLE, - LPDWORD - ); - - /* - DWORD WINAPI WaitForSingleObject( - __in HANDLE hHandle, - __in DWORD dwMilliseconds - ); - */ - var WaitForSingleObject = kernel32dll.declare("WaitForSingleObject", - WinABI, - DWORD, - HANDLE, - DWORD - ); - - /* - BOOL WINAPI TerminateProcess( - __in HANDLE hProcess, - __in UINT uExitCode - ); - */ - var TerminateProcess = kernel32dll.declare("TerminateProcess", - WinABI, - BOOL, - HANDLE, - UINT - ); - - //functions - function popen(command, workdir, args, environment, child) { - //escape arguments - args.unshift(command); - for (var i = 0; i < args.length; i++) { - if (typeof args[i] != "string") { args[i] = args[i].toString(); } - /* quote arguments with spaces */ - if (args[i].match(/\s/)) { - args[i] = "\"" + args[i] + "\""; - } - /* If backslash is followed by a quote, double it */ - args[i] = args[i].replace(/\\\"/g, "\\\\\""); - } - command = args.join(' '); - - environment = environment || []; - if(environment.length) { - //An environment block consists of - //a null-terminated block of null-terminated strings. - //Using CREATE_UNICODE_ENVIRONMENT so needs to be jschar - environment = ctypes.jschar.array()(environment.join('\0') + '\0'); - } else { - environment = null; - } - - var hOutputReadTmp = new HANDLE(), - hOutputRead = new HANDLE(), - hOutputWrite = new HANDLE(); - - var hErrorRead = new HANDLE(), - hErrorReadTmp = new HANDLE(), - hErrorWrite = new HANDLE(); - - var hInputRead = new HANDLE(), - hInputWriteTmp = new HANDLE(), - hInputWrite = new HANDLE(); - - // Set up the security attributes struct. - var sa = new SECURITY_ATTRIBUTES(); - sa.nLength = SECURITY_ATTRIBUTES.size; - sa.lpSecurityDescriptor = null; - sa.bInheritHandle = true; - - // Create output pipe. - - if(!CreatePipe(hOutputReadTmp.address(), hOutputWrite.address(), sa.address(), 0)) - LogError('CreatePipe hOutputReadTmp failed'); - - if(options.mergeStderr) { - // Create a duplicate of the output write handle for the std error - // write handle. This is necessary in case the child application - // closes one of its std output handles. - if (!DuplicateHandle(GetCurrentProcess(), hOutputWrite, - GetCurrentProcess(), hErrorWrite.address(), 0, - true, DUPLICATE_SAME_ACCESS)) - LogError("DuplicateHandle hOutputWrite failed"); - } else { - // Create error pipe. - if(!CreatePipe(hErrorReadTmp.address(), hErrorWrite.address(), sa.address(), 0)) - LogError('CreatePipe hErrorReadTmp failed'); - } - - // Create input pipe. - if (!CreatePipe(hInputRead.address(),hInputWriteTmp.address(),sa.address(), 0)) - LogError("CreatePipe hInputRead failed"); - - // Create new output/error read handle and the input write handles. Set - // the Properties to FALSE. Otherwise, the child inherits the - // properties and, as a result, non-closeable handles to the pipes - // are created. - if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, - GetCurrentProcess(), - hOutputRead.address(), // Address of new handle. - 0, false, // Make it uninheritable. - DUPLICATE_SAME_ACCESS)) - LogError("DupliateHandle hOutputReadTmp failed"); - - if(!options.mergeStderr) { - if (!DuplicateHandle(GetCurrentProcess(), hErrorReadTmp, - GetCurrentProcess(), - hErrorRead.address(), // Address of new handle. - 0, false, // Make it uninheritable. - DUPLICATE_SAME_ACCESS)) - LogError("DupliateHandle hErrorReadTmp failed"); - } - if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp, - GetCurrentProcess(), - hInputWrite.address(), // Address of new handle. - 0, false, // Make it uninheritable. - DUPLICATE_SAME_ACCESS)) - LogError("DupliateHandle hInputWriteTmp failed"); - - // Close inheritable copies of the handles. - if (!CloseHandle(hOutputReadTmp)) LogError("CloseHandle hOutputReadTmp failed"); - if(!options.mergeStderr) - if (!CloseHandle(hErrorReadTmp)) LogError("CloseHandle hErrorReadTmp failed"); - if (!CloseHandle(hInputWriteTmp)) LogError("CloseHandle failed"); - - var pi = new PROCESS_INFORMATION(); - var si = new STARTUPINFO(); - - si.cb = STARTUPINFO.size; - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = hInputRead; - si.hStdOutput = hOutputWrite; - si.hStdError = hErrorWrite; - - // Launch the process - if(!CreateProcessW(null, // executable name - command, // command buffer - null, // process security attribute - null, // thread security attribute - true, // inherits system handles - CREATE_UNICODE_ENVIRONMENT|CREATE_NO_WINDOW, // process flags - environment, // envrionment block - workdir, // set as current directory - si.address(), // (in) startup information - pi.address() // (out) process information - )) - throw("Fatal - Could not launch subprocess '"+command+"'"); - - // Close any unnecessary handles. - if (!CloseHandle(pi.hThread)) - LogError("CloseHandle pi.hThread failed"); - - // Close pipe handles (do not continue to modify the parent). - // You need to make sure that no handles to the write end of the - // output pipe are maintained in this process or else the pipe will - // not close when the child process exits and the ReadFile will hang. - if (!CloseHandle(hInputRead)) LogError("CloseHandle hInputRead failed"); - if (!CloseHandle(hOutputWrite)) LogError("CloseHandle hOutputWrite failed"); - if (!CloseHandle(hErrorWrite)) LogError("CloseHandle hErrorWrite failed"); - - //return values - child.stdin = hInputWrite; - child.stdout = hOutputRead; - child.stderr = options.mergeStderr ? undefined : hErrorRead; - child.process = pi.hProcess; - return pi.hProcess; - } - - /* - * createStdinWriter () - * - * Create a ChromeWorker object for writing data to the subprocess' stdin - * pipe. The ChromeWorker object lives on a separate thread; this avoids - * internal deadlocks. - */ - function createStdinWriter() { - debugLog("Creating new stdin worker\n"); - stdinWorker = new ChromeWorker(WORKER_URL_WIN); - stdinWorker.onmessage = function(event) { - switch(event.data) { - case "WriteOK": - pendingWriteCount--; - debugLog("got OK from stdinWorker - remaining count: "+pendingWriteCount+"\n"); - break; - case "ClosedOK": - stdinOpenState = CLOSED; - debugLog("Stdin pipe closed\n"); - break; - default: - debugLog("got msg from stdinWorker: "+event.data+"\n"); - } - } - stdinWorker.onerror = function(error) { - pendingWriteCount--; - LogError("got error from stdinWorker: "+error.message+"\n"); - } - - stdinWorker.postMessage({msg: "init", libc: options.libc}); - } - - /* - * writeStdin() - * @data: String containing the data to write - * - * Write data to the subprocess' stdin (equals to sending a request to the - * ChromeWorker object to write the data). - */ - function writeStdin(data) { - ++pendingWriteCount; - debugLog("sending "+data.length+" bytes to stdinWorker\n"); - var pipePtr = parseInt(ctypes.cast(child.stdin.address(), ctypes.uintptr_t).value); - - stdinWorker.postMessage({ - msg: 'write', - pipe: pipePtr, - data: data - }); - } - - /* - * closeStdinHandle() - * - * Close the stdin pipe, either directly or by requesting the ChromeWorker to - * close the pipe. The ChromeWorker will only close the pipe after the last write - * request process is done. - */ - - function closeStdinHandle() { - debugLog("trying to close stdin\n"); - if (stdinOpenState != OPEN) return; - stdinOpenState = CLOSEABLE; - - if (stdinWorker) { - debugLog("sending close stdin to worker\n"); - var pipePtr = parseInt(ctypes.cast(child.stdin.address(), ctypes.uintptr_t).value); - stdinWorker.postMessage({ - msg: 'close', - pipe: pipePtr - }); - } - else { - stdinOpenState = CLOSED; - debugLog("Closing Stdin\n"); - CloseHandle(child.stdin) || LogError("CloseHandle hInputWrite failed"); - } - } - - - /* - * createReader(pipe, name) - * - * @pipe: handle to the pipe - * @name: String containing the pipe name (stdout or stderr) - * - * Create a ChromeWorker object for reading data asynchronously from - * the pipe (i.e. on a separate thread), and passing the result back to - * the caller. - */ - function createReader(pipe, name, callbackFunc) { - var worker = new ChromeWorker(WORKER_URL_WIN); - worker.onmessage = function(event) { - switch(event.data.msg) { - case "data": - debugLog("got "+event.data.count+" bytes from "+name+"\n"); - var data = ''; - if (options.charset === null) { - data = getBytes(event.data.data); - } - else { - try { - data = convertBytes(event.data.data, options.charset); - } - catch(ex) { - console.warn("error decoding output: " + ex); - data = getBytes(event.data.data); - } - } - - callbackFunc(data); - break; - case "done": - debugLog("Pipe "+name+" closed\n"); - --readers; - if (readers == 0) cleanup(); - break; - default: - debugLog("Got msg from "+name+": "+event.data.data+"\n"); - } - } - - worker.onerror = function(errorMsg) { - LogError("Got error from "+name+": "+errorMsg.message); - } - - var pipePtr = parseInt(ctypes.cast(pipe.address(), ctypes.uintptr_t).value); - - worker.postMessage({ - msg: 'read', - pipe: pipePtr, - libc: options.libc, - charset: options.charset === null ? "null" : options.charset, - name: name - }); - - return worker; - } - - /* - * readPipes() - * - * Open the pipes for reading from stdout and stderr - */ - function readPipes() { - - stdoutWorker = createReader(child.stdout, "stdout", function (data) { - if(options.stdout) { - setTimeout(function() { - options.stdout(data); - }, 0); - } else { - output += data; - } - }); - - - if (!options.mergeStderr) stderrWorker = createReader(child.stderr, "stderr", function (data) { - if(options.stderr) { - setTimeout(function() { - options.stderr(data); - }, 0); - } else { - error += data; - } - }); - } - - /* - * cleanup() - * - * close stdin if needed, get the exit code from the subprocess and invoke - * the caller's done() function. - * - * Note: because stdout() and stderr() are called using setTimeout, we need to - * do the same here in order to guarantee the message sequence. - */ - function cleanup() { - debugLog("Cleanup called\n"); - if(active) { - active = false; - - closeStdinHandle(); // should only be required in case of errors - - var exit = new DWORD(); - GetExitCodeProcess(child.process, exit.address()); - exitCode = exit.value; - - if (stdinWorker) - stdinWorker.postMessage({msg: 'stop'}) - - setTimeout(function _done() { - if (options.done) { - try { - options.done({ - exitCode: exitCode, - stdout: output, - stderr: error, - }); - } - catch (ex) { - // prevent from blocking if options.done() throws an error - done = true; - throw ex; - } - } - done = true; - }, 0); - kernel32dll.close(); - } - } - - var cmdStr = getCommandStr(options.command); - var workDir = getWorkDir(options.workdir); - - //main - hChildProcess = popen(cmdStr, workDir, options.arguments, options.environment, child); - - readPipes(); - - if (options.stdin) { - createStdinWriter(); - - if(typeof(options.stdin) == 'function') { - try { - options.stdin({ - write: function(data) { - writeStdin(data); - }, - close: function() { - closeStdinHandle(); - } - }); - } - catch (ex) { - // prevent from failing if options.stdin() throws an exception - closeStdinHandle(); - throw ex; - } - } else { - writeStdin(options.stdin); - closeStdinHandle(); - } - } - else - closeStdinHandle(); - - return { - kill: function(hardKill) { - // hardKill is currently ignored on Windows - var r = !!TerminateProcess(child.process, 255); - cleanup(-1); - return r; - }, - wait: function() { - // wait for async operations to complete - var thread = Cc['@mozilla.org/thread-manager;1'].getService(Ci.nsIThreadManager).currentThread; - while (!done) thread.processNextEvent(true); - - return exitCode; - } - } -} - - -function subprocess_unix(options) { - // stdin pipe states - const OPEN = 2; - const CLOSEABLE = 1; - const CLOSED = 0; - - var libc = ctypes.open(options.libc), - active = true, - done = false, - exitCode = -1, - workerExitCode = 0, - child = {}, - pid = -1, - stdinWorker = null, - stdoutWorker = null, - stderrWorker = null, - pendingWriteCount = 0, - readers = options.mergeStderr ? 1 : 2, - stdinOpenState = OPEN, - error = '', - output = ''; - - //api declarations - - //pid_t fork(void); - var fork = libc.declare("fork", - ctypes.default_abi, - pid_t - ); - - //NULL terminated array of strings, argv[0] will be command >> + 2 - var argv = ctypes.char.ptr.array(options.arguments.length + 2); - var envp = ctypes.char.ptr.array(options.environment.length + 1); - - // posix_spawn_file_actions_t is a complex struct that may be different on - // each platform. We do not care about its attributes, we don't need to - // get access to them, but we do need to allocate the right amount - // of memory for it. - // Bug 936297 - Use OS.File internals to fetch - // sizeof(posix_spawn_file_actions_t) - var { OS } = Cu.import("resource://gre/modules/osfile.jsm", {}); - var sizeof_file_actions_t = OS.Constants.libc.OSFILE_SIZEOF_DIRENT; - var posix_spawn_file_actions_t = ctypes.uint8_t.array(sizeof_file_actions_t); - - //int posix_spawn(pid_t *restrict pid, const char *restrict path, - // const posix_spawn_file_actions_t *file_actions, - // const posix_spawnattr_t *restrict attrp, - // char *const argv[restrict], char *const envp[restrict]); - var posix_spawn = libc.declare("posix_spawn", - ctypes.default_abi, - ctypes.int, - pid_t.ptr, - ctypes.char.ptr, - posix_spawn_file_actions_t.ptr, - ctypes.voidptr_t, - argv, - envp - ); - - //int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions); - var posix_spawn_file_actions_init = libc.declare("posix_spawn_file_actions_init", - ctypes.default_abi, - ctypes.int, - posix_spawn_file_actions_t.ptr - ); - - //int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions); - var posix_spawn_file_actions_destroy = libc.declare("posix_spawn_file_actions_destroy", - ctypes.default_abi, - ctypes.int, - posix_spawn_file_actions_t.ptr - ); - - // int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * - // file_actions, int fildes, int newfildes); - var posix_spawn_file_actions_adddup2 = libc.declare("posix_spawn_file_actions_adddup2", - ctypes.default_abi, - ctypes.int, - posix_spawn_file_actions_t.ptr, - ctypes.int, - ctypes.int - ); - - // int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * - // file_actions, int fildes); - var posix_spawn_file_actions_addclose = libc.declare("posix_spawn_file_actions_addclose", - ctypes.default_abi, - ctypes.int, - posix_spawn_file_actions_t.ptr, - ctypes.int - ); - - //int pipe(int pipefd[2]); - var pipefd = ctypes.int.array(2); - var pipe = libc.declare("pipe", - ctypes.default_abi, - ctypes.int, - pipefd - ); - - //int close(int fd); - var close = libc.declare("close", - ctypes.default_abi, - ctypes.int, - ctypes.int - ); - - //pid_t waitpid(pid_t pid, int *status, int options); - var waitpid = libc.declare("waitpid", - ctypes.default_abi, - pid_t, - pid_t, - ctypes.int.ptr, - ctypes.int - ); - - //int kill(pid_t pid, int sig); - var kill = libc.declare("kill", - ctypes.default_abi, - ctypes.int, - pid_t, - ctypes.int - ); - - //int read(int fd, void *buf, size_t count); - var bufferSize = 1024; - var buffer = ctypes.char.array(bufferSize); - var read = libc.declare("read", - ctypes.default_abi, - ctypes.int, - ctypes.int, - buffer, - ctypes.int - ); - - //ssize_t write(int fd, const void *buf, size_t count); - var write = libc.declare("write", - ctypes.default_abi, - ctypes.int, - ctypes.int, - ctypes.char.ptr, - ctypes.int - ); - - //int chdir(const char *path); - var chdir = libc.declare("chdir", - ctypes.default_abi, - ctypes.int, - ctypes.char.ptr - ); - - //int fcntl(int fd, int cmd, ... /* arg */ ); - var fcntl = libc.declare("fcntl", - ctypes.default_abi, - ctypes.int, - ctypes.int, - ctypes.int, - ctypes.int - ); - - function popen(command, workdir, args, environment, child) { - var _in, - _out, - _err, - pid, - rc; - _in = new pipefd(); - _out = new pipefd(); - if(!options.mergeStderr) - _err = new pipefd(); - - var _args = argv(); - args.unshift(command); - for(var i=0;i<args.length;i++) { - _args[i] = ctypes.char.array()(args[i]); - } - var _envp = envp(); - for(var i=0;i<environment.length;i++) { - _envp[i] = ctypes.char.array()(environment[i]); - // LogError(_envp); - } - - rc = pipe(_in); - if (rc < 0) { - return -1; - } - rc = pipe(_out); - fcntl(_out[0], F_SETFL, getPlatformValue(O_NONBLOCK)); - if (rc < 0) { - close(_in[0]); - close(_in[1]); - return -1 - } - if(!options.mergeStderr) { - rc = pipe(_err); - fcntl(_err[0], F_SETFL, getPlatformValue(O_NONBLOCK)); - if (rc < 0) { - close(_in[0]); - close(_in[1]); - close(_out[0]); - close(_out[1]); - return -1 - } - } - - let STDIN_FILENO = 0; - let STDOUT_FILENO = 1; - let STDERR_FILENO = 2; - - let action = posix_spawn_file_actions_t(); - posix_spawn_file_actions_init(action.address()); - - posix_spawn_file_actions_adddup2(action.address(), _in[0], STDIN_FILENO); - posix_spawn_file_actions_addclose(action.address(), _in[1]); - posix_spawn_file_actions_addclose(action.address(), _in[0]); - - posix_spawn_file_actions_adddup2(action.address(), _out[1], STDOUT_FILENO); - posix_spawn_file_actions_addclose(action.address(), _out[1]); - posix_spawn_file_actions_addclose(action.address(), _out[0]); - - if (!options.mergeStderr) { - posix_spawn_file_actions_adddup2(action.address(), _err[1], STDERR_FILENO); - posix_spawn_file_actions_addclose(action.address(), _err[1]); - posix_spawn_file_actions_addclose(action.address(), _err[0]); - } - - // posix_spawn doesn't support setting a custom workdir for the child, - // so change the cwd in the parent process before launching the child process. - if (workdir) { - if (chdir(workdir) < 0) { - throw new Error("Unable to change workdir before launching child process"); - } - } - - closeOtherFds(action, _in[1], _out[0], options.mergeStderr ? undefined : _err[0]); - - let id = pid_t(0); - let rv = posix_spawn(id.address(), command, action.address(), null, _args, _envp); - posix_spawn_file_actions_destroy(action.address()); - if (rv != 0) { - // we should not really end up here - if(!options.mergeStderr) { - close(_err[0]); - close(_err[1]); - } - close(_out[0]); - close(_out[1]); - close(_in[0]); - close(_in[1]); - throw new Error("Fatal - failed to create subprocess '"+command+"'"); - } - pid = id.value; - - close(_in[0]); - close(_out[1]); - if (!options.mergeStderr) - close(_err[1]); - child.stdin = _in[1]; - child.stdout = _out[0]; - child.stderr = options.mergeStderr ? undefined : _err[0]; - child.pid = pid; - - return pid; - } - - - // close any file descriptors that are not required for the process - function closeOtherFds(action, fdIn, fdOut, fdErr) { - // Unfortunately on mac, any fd registered in posix_spawn_file_actions_addclose - // that can't be closed correctly will make posix_spawn fail... - // Even if we ensure registering only still opened fds. - if (gXulRuntime.OS == "Darwin") - return; - - var maxFD = 256; // arbitrary max - - - var rlim_t = getPlatformValue(RLIM_T); - - const RLIMITS = new ctypes.StructType("RLIMITS", [ - {"rlim_cur": rlim_t}, - {"rlim_max": rlim_t} - ]); - - try { - var getrlimit = libc.declare("getrlimit", - ctypes.default_abi, - ctypes.int, - ctypes.int, - RLIMITS.ptr - ); - - var rl = new RLIMITS(); - if (getrlimit(getPlatformValue(RLIMIT_NOFILE), rl.address()) == 0) { - maxFD = rl.rlim_cur; - } - debugLog("getlimit: maxFD="+maxFD+"\n"); - - } - catch(ex) { - debugLog("getrlimit: no such function on this OS\n"); - debugLog(ex.toString()); - } - - // close any file descriptors - // fd's 0-2 are already closed - for (var i = 3; i < maxFD; i++) { - if (i != fdIn && i != fdOut && i != fdErr && fcntl(i, F_GETFD, -1) >= 0) { - posix_spawn_file_actions_addclose(action.address(), i); - } - } - } - - /* - * createStdinWriter () - * - * Create a ChromeWorker object for writing data to the subprocess' stdin - * pipe. The ChromeWorker object lives on a separate thread; this avoids - * internal deadlocks. - */ - function createStdinWriter() { - debugLog("Creating new stdin worker\n"); - stdinWorker = new ChromeWorker(WORKER_URL_UNIX); - stdinWorker.onmessage = function(event) { - switch (event.data.msg) { - case "info": - switch(event.data.data) { - case "WriteOK": - pendingWriteCount--; - debugLog("got OK from stdinWorker - remaining count: "+pendingWriteCount+"\n"); - break; - case "ClosedOK": - stdinOpenState = CLOSED; - debugLog("Stdin pipe closed\n"); - break; - default: - debugLog("got msg from stdinWorker: "+event.data.data+"\n"); - } - break; - case "debug": - debugLog("stdinWorker: "+event.data.data+"\n"); - break; - case "error": - LogError("got error from stdinWorker: "+event.data.data+"\n"); - pendingWriteCount = 0; - stdinOpenState = CLOSED; - } - } - stdinWorker.onerror = function(error) { - pendingWriteCount = 0; - closeStdinHandle(); - LogError("got error from stdinWorker: "+error.message+"\n"); - } - stdinWorker.postMessage({msg: "init", libc: options.libc}); - } - - /* - * writeStdin() - * @data: String containing the data to write - * - * Write data to the subprocess' stdin (equals to sending a request to the - * ChromeWorker object to write the data). - */ - function writeStdin(data) { - if (stdinOpenState == CLOSED) return; // do not write to closed pipes - - ++pendingWriteCount; - debugLog("sending "+data.length+" bytes to stdinWorker\n"); - var pipe = parseInt(child.stdin); - - stdinWorker.postMessage({ - msg: 'write', - pipe: pipe, - data: data - }); - } - - - /* - * closeStdinHandle() - * - * Close the stdin pipe, either directly or by requesting the ChromeWorker to - * close the pipe. The ChromeWorker will only close the pipe after the last write - * request process is done. - */ - - function closeStdinHandle() { - debugLog("trying to close stdin\n"); - if (stdinOpenState != OPEN) return; - stdinOpenState = CLOSEABLE; - - if (stdinWorker) { - debugLog("sending close stdin to worker\n"); - var pipePtr = parseInt(child.stdin); - - stdinWorker.postMessage({ - msg: 'close', - pipe: pipePtr - }); - } - else { - stdinOpenState = CLOSED; - debugLog("Closing Stdin\n"); - close(child.stdin) && LogError("CloseHandle stdin failed"); - } - } - - - /* - * createReader(pipe, name) - * - * @pipe: handle to the pipe - * @name: String containing the pipe name (stdout or stderr) - * @callbackFunc: function to be called with the read data - * - * Create a ChromeWorker object for reading data asynchronously from - * the pipe (i.e. on a separate thread), and passing the result back to - * the caller. - * - */ - function createReader(pipe, name, callbackFunc) { - var worker = new ChromeWorker(WORKER_URL_UNIX); - worker.onmessage = function(event) { - switch(event.data.msg) { - case "data": - debugLog("got "+event.data.count+" bytes from "+name+"\n"); - var data = ''; - if (options.charset === null) { - data = getBytes(event.data.data); - } - else { - try { - data = convertBytes(event.data.data, options.charset); - } - catch(ex) { - console.warn("error decoding output: " + ex); - data = getBytes(event.data.data); - } - } - - callbackFunc(data); - break; - case "done": - debugLog("Pipe "+name+" closed\n"); - if (event.data.data != 0) workerExitCode = event.data.data; - --readers; - if (readers == 0) cleanup(); - break; - default: - debugLog("Got msg from "+name+": "+event.data.data+"\n"); - } - } - worker.onerror = function(error) { - LogError("Got error from "+name+": "+error.message); - } - - worker.postMessage({ - msg: 'read', - pipe: pipe, - pid: pid, - libc: options.libc, - charset: options.charset === null ? "null" : options.charset, - name: name - }); - - return worker; - } - - /* - * readPipes() - * - * Open the pipes for reading from stdout and stderr - */ - function readPipes() { - - stdoutWorker = createReader(child.stdout, "stdout", function (data) { - if(options.stdout) { - setTimeout(function() { - options.stdout(data); - }, 0); - } else { - output += data; - } - }); - - if (!options.mergeStderr) stderrWorker = createReader(child.stderr, "stderr", function (data) { - if(options.stderr) { - setTimeout(function() { - options.stderr(data); - }, 0); - } else { - error += data; - } - }); - } - - function cleanup() { - debugLog("Cleanup called\n"); - if(active) { - active = false; - - closeStdinHandle(); // should only be required in case of errors - - var result, status = ctypes.int(); - result = waitpid(child.pid, status.address(), 0); - if (result > 0) - exitCode = status.value - else - if (workerExitCode >= 0) - exitCode = workerExitCode - else - exitCode = status.value; - - if (stdinWorker) - stdinWorker.postMessage({msg: 'stop'}) - - setTimeout(function _done() { - if (options.done) { - try { - options.done({ - exitCode: exitCode, - stdout: output, - stderr: error, - }); - } - catch(ex) { - // prevent from blocking if options.done() throws an error - done = true; - throw ex; - } - - } - done = true; - }, 0); - - libc.close(); - } - } - - //main - - var cmdStr = getCommandStr(options.command); - var workDir = getWorkDir(options.workdir); - - child = {}; - pid = popen(cmdStr, workDir, options.arguments, options.environment, child); - - debugLog("subprocess started; got PID "+pid+"\n"); - - readPipes(); - - if (options.stdin) { - createStdinWriter(); - if(typeof(options.stdin) == 'function') { - try { - options.stdin({ - write: function(data) { - writeStdin(data); - }, - close: function() { - closeStdinHandle(); - } - }); - } - catch(ex) { - // prevent from failing if options.stdin() throws an exception - closeStdinHandle(); - throw ex; - } - } else { - writeStdin(options.stdin); - closeStdinHandle(); - } - } - - return { - wait: function() { - // wait for async operations to complete - var thread = Cc['@mozilla.org/thread-manager;1'].getService(Ci.nsIThreadManager).currentThread; - while (! done) thread.processNextEvent(true) - return exitCode; - }, - kill: function(hardKill) { - var rv = kill(pid, (hardKill ? 9: 15)); - cleanup(-1); - return rv; - } - } -} - - -module.exports = subprocess;
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/lib/subprocess_worker_unix.js +++ /dev/null @@ -1,248 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -/* - * ChromeWorker Object subprocess.jsm on Unix-like systems (Linux, Mac OS X, ...) - * to process stdin/stdout/stderr on separate threads. - * - */ - -// Being a ChromeWorker object, implicitly uses the following: -// Components.utils.import("resource://gre/modules/ctypes.jsm"); - -'use strict'; - -const BufferSize = 1024; - -var libc = null; -var libcFunc = {}; - - -/* - struct pollfd { - int fd; // file descriptor - short events; // events to look for - short revents; // events returned - }; -*/ - -var pollfd = new ctypes.StructType("pollfd", - [ {'fd': ctypes.int}, - {'events': ctypes.short}, - {'revents': ctypes.short} - ]); - -var WriteBuffer = ctypes.uint8_t.array(BufferSize); -var ReadBuffer = ctypes.char.array(BufferSize); - - -const POLLIN = 0x0001; -const POLLOUT = 0x0004; - -const POLLERR = 0x0008; // some poll error occurred -const POLLHUP = 0x0010; // file descriptor was "hung up" -const POLLNVAL = 0x0020; // requested events "invalid" - -const WNOHANG = 0x01; - -const pid_t = ctypes.int32_t; - -const INDEFINITE = -1; -const NOWAIT = 0; -const WAITTIME = 200 // wait time for poll() in ms - -function initLibc(libName) { - postMessage({msg: "debug", data: "initialising library with "+ libName}); - - libc = ctypes.open(libName); - - libcFunc.pollFds = pollfd.array(1); - - // int poll(struct pollfd fds[], nfds_t nfds, int timeout); - libcFunc.poll = libc.declare("poll", - ctypes.default_abi, - ctypes.int, - libcFunc.pollFds, - ctypes.unsigned_int, - ctypes.int); - - //ssize_t write(int fd, const void *buf, size_t count); - // NOTE: buf is declared as array of unsigned int8 instead of char to avoid - // implicit charset conversion - libcFunc.write = libc.declare("write", - ctypes.default_abi, - ctypes.int, - ctypes.int, - WriteBuffer, - ctypes.int); - - //int read(int fd, void *buf, size_t count); - libcFunc.read = libc.declare("read", - ctypes.default_abi, - ctypes.int, - ctypes.int, - ReadBuffer, - ctypes.int); - - //int pipe(int pipefd[2]); - libcFunc.pipefd = ctypes.int.array(2); - - //int close(int fd); - libcFunc.close = libc.declare("close", - ctypes.default_abi, - ctypes.int, - ctypes.int); - - //pid_t waitpid(pid_t pid, int *status, int options); - libcFunc.waitpid = libc.declare("waitpid", - ctypes.default_abi, - pid_t, - pid_t, - ctypes.int.ptr, - ctypes.int); -} - -function closePipe(pipe) { - libcFunc.close(pipe); -} - -function writePipe(pipe, data) { - - postMessage({msg: "debug", data: "trying to write to "+pipe}); - - let numChunks = Math.floor(data.length / BufferSize); - let pData = new WriteBuffer(); - - for (var chunk = 0; chunk <= numChunks; chunk ++) { - let numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize; - for (var i=0; i < numBytes; i++) { - pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256; - } - - let bytesWritten = libcFunc.write(pipe, pData, numBytes); - if (bytesWritten != numBytes) { - closePipe(); - libc.close(); - postMessage({ msg: "error", data: "error: wrote "+bytesWritten+" instead of "+numBytes+" bytes"}); - close(); - } - } - postMessage({msg: "info", data: "wrote "+data.length+" bytes of data"}); -} - - -function readString(data, length, charset) { - var string = '', bytes = []; - for(var i = 0;i < length; i++) { - if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data - break; - - bytes.push(data[i]); - } - - return bytes; -} - -function readPipe(pipe, charset, pid) { - var p = new libcFunc.pollFds; - p[0].fd = pipe; - p[0].events = POLLIN | POLLERR | POLLHUP; - p[0].revents = 0; - var pollTimeout = WAITTIME; - var exitCode = -1; - var readCount = 0; - var result, status = ctypes.int(); - result = 0; - - - const i=0; - while (true) { - if (result == 0) { - result = libcFunc.waitpid(pid, status.address(), WNOHANG); - if (result > 0) { - pollTimeout = NOWAIT; - exitCode = parseInt(status.value); - postMessage({msg: "debug", data: "waitpid signaled subprocess stop, exitcode="+status.value }); - } - } - var r = libcFunc.poll(p, 1, pollTimeout); - if (r > 0) { - if (p[i].revents & POLLIN) { - postMessage({msg: "debug", data: "reading next chunk"}); - readCount = readPolledFd(p[i].fd, charset); - if (readCount == 0) break; - } - - if (p[i].revents & POLLHUP) { - postMessage({msg: "debug", data: "poll returned HUP"}); - break; - } - else if (p[i].revents & POLLERR) { - postMessage({msg: "error", data: "poll returned error"}); - break; - } - else if (p[i].revents != POLLIN) { - postMessage({msg: "error", data: "poll returned "+p[i]}); - break; - } - } - else - if (pollTimeout == 0 || r < 0) break; - } - - // continue reading until the buffer is empty - while (readCount > 0) { - readCount = readPolledFd(pipe, charset); - } - - libcFunc.close(pipe); - postMessage({msg: "done", data: exitCode }); - libc.close(); - close(); -} - -function readPolledFd(pipe, charset) { - var line = new ReadBuffer(); - var r = libcFunc.read(pipe, line, BufferSize); - - if (r > 0) { - var c = readString(line, r, charset); - postMessage({msg: "data", data: c, count: c.length}); - } - return r; -} - -onmessage = function (event) { - switch (event.data.msg) { - case "init": - initLibc(event.data.libc); - break; - case "read": - initLibc(event.data.libc); - readPipe(event.data.pipe, event.data.charset, event.data.pid); - break; - case "write": - // data contents: - // msg: 'write' - // data: the data (string) to write - // pipe: ptr to pipe - writePipe(event.data.pipe, event.data.data); - postMessage({msg: "info", data: "WriteOK"}); - break; - case "close": - postMessage({msg: "debug", data: "closing stdin\n"}); - - closePipe(event.data.pipe); - postMessage({msg: "info", data: "ClosedOK"}); - break; - case "stop": - libc.close(); // do not use libc after this point - close(); - break; - default: - throw("error: Unknown command"+event.data.msg+"\n"); - } - return; -};
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/lib/subprocess_worker_win.js +++ /dev/null @@ -1,206 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -/* - * ChromeWorker Object subprocess.jsm on Windows to process stdin/stdout/stderr - * on separate threads. - * - */ - -// Being a ChromeWorker object, implicitly uses the following: -// Components.utils.import("resource://gre/modules/ctypes.jsm"); - -'use strict'; - -const BufferSize = 1024; - -const BOOL = ctypes.bool; -const HANDLE = ctypes.size_t; -const DWORD = ctypes.uint32_t; -const LPDWORD = DWORD.ptr; -const PVOID = ctypes.voidptr_t; -const LPVOID = PVOID; - -/* -typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - PVOID Pointer; - }; - HANDLE hEvent; -} OVERLAPPED, *LPOVERLAPPED; -*/ -const OVERLAPPED = new ctypes.StructType("OVERLAPPED"); - -var ReadFileBuffer = ctypes.char.array(BufferSize); -var WriteFileBuffer = ctypes.uint8_t.array(BufferSize); - -var kernel32dll = null; -var libFunc = {}; - -function initLib(libName) { - if (ctypes.size_t.size == 8) { - var WinABI = ctypes.default_abi; - } else { - var WinABI = ctypes.winapi_abi; - } - - kernel32dll = ctypes.open(libName); - - /* - BOOL WINAPI WriteFile( - __in HANDLE hFile, - __in LPCVOID lpBuffer, - __in DWORD nNumberOfBytesToWrite, - __out_opt LPDWORD lpNumberOfBytesWritten, - __inout_opt LPOVERLAPPED lpOverlapped - ); - - NOTE: lpBuffer is declared as array of unsigned int8 instead of char to avoid - implicit charset conversion - */ - libFunc.WriteFile = kernel32dll.declare("WriteFile", - WinABI, - BOOL, - HANDLE, - WriteFileBuffer, - DWORD, - LPDWORD, - OVERLAPPED.ptr - ); - - /* - BOOL WINAPI ReadFile( - __in HANDLE hFile, - __out LPVOID ReadFileBuffer, - __in DWORD nNumberOfBytesToRead, - __out_opt LPDWORD lpNumberOfBytesRead, - __inout_opt LPOVERLAPPED lpOverlapped - ); - */ - libFunc.ReadFile = kernel32dll.declare("ReadFile", - WinABI, - BOOL, - HANDLE, - ReadFileBuffer, - DWORD, - LPDWORD, - OVERLAPPED.ptr - ); - - /* - BOOL WINAPI CloseHandle( - __in HANDLE hObject - ); - */ - libFunc.CloseHandle = kernel32dll.declare("CloseHandle", - WinABI, - BOOL, - HANDLE - ); -} - - -function writePipe(pipe, data) { - var bytesWritten = DWORD(0); - - var pData = new WriteFileBuffer(); - - var numChunks = Math.floor(data.length / BufferSize); - for (var chunk = 0; chunk <= numChunks; chunk ++) { - var numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize; - for (var i=0; i < numBytes; i++) { - pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256; - } - - var r = libFunc.WriteFile(pipe, pData, numBytes, bytesWritten.address(), null); - if (bytesWritten.value != numBytes) - throw("error: wrote "+bytesWritten.value+" instead of "+numBytes+" bytes"); - } - postMessage("wrote "+data.length+" bytes of data"); -} - -function readString(data, length, charset) { - var string = '', bytes = []; - for(var i = 0;i < length; i++) { - if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data - break; - - bytes.push(data[i]); - } - - return bytes; -} - -function readPipe(pipe, charset) { - while (true) { - var bytesRead = DWORD(0); - var line = new ReadFileBuffer(); - var r = libFunc.ReadFile(pipe, line, BufferSize, bytesRead.address(), null); - - if (!r) { - // stop if we get an error (such as EOF reached) - postMessage({msg: "info", data: "ReadFile failed"}); - break; - } - - if (bytesRead.value > 0) { - var c = readString(line, bytesRead.value, charset); - postMessage({msg: "data", data: c, count: c.length}); - } - else { - break; - } - } - libFunc.CloseHandle(pipe); - postMessage({msg: "done"}); - kernel32dll.close(); - close(); -} - -onmessage = function (event) { - let pipePtr; - switch (event.data.msg) { - case "init": - initLib(event.data.libc); - break; - case "write": - // data contents: - // msg: 'write' - // data: the data (string) to write - // pipe: ptr to pipe - pipePtr = HANDLE.ptr(event.data.pipe); - writePipe(pipePtr.contents, event.data.data); - postMessage("WriteOK"); - break; - case "read": - initLib(event.data.libc); - pipePtr = HANDLE.ptr(event.data.pipe); - readPipe(pipePtr.contents, event.data.charset); - break; - case "close": - pipePtr = HANDLE.ptr(event.data.pipe); - postMessage("closing stdin\n"); - - if (libFunc.CloseHandle(pipePtr.contents)) { - postMessage("ClosedOK"); - } - else - postMessage("Could not close stdin handle"); - break; - case "stop": - kernel32dll.close(); - close(); - break; - default: - throw("error: Unknown command"+event.data.msg+"\n"); - } - return; -};
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "subprocess", - "license": "MPL 1.1/GPL 2.0/LGPL 2.1", - "author": "Alexandre Poirot", - "contributors": [ - "Jan Gerber (original creator) <j@mailb.org>", - "Patrick Brunschwig (author of almost all code) <patrick@mozilla-enigmail.org>", - "Ramalingam Saravanan (from enigmail team) <svn@xmlterm.org>" - ], - "version": "0.1.1", - "dependencies": [ - "api-utils" - ], - "description": "Addon-sdk package for subprocess xpcom components from enigmail. Allow to run process, manipulate stdin/out and kill it." -}
deleted file mode 100644 --- a/b2g/simulator/packages/subprocess/tests/test-subprocess.js +++ /dev/null @@ -1,144 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -const { Cc, Ci } = require("chrome"); -const subprocess = require("subprocess"); -const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - -// For now, only test on windows -if (env.get('OS') && env.get('OS').match(/Windows/)) { - -exports.testWindows = function (test) { - test.waitUntilDone(); - let envTestValue = "OK"; - let gotStdout = false; - - var p = subprocess.call({ - // Retrieve windows cmd.exe path from env - command: env.get('ComSpec'), - // In order to execute a simple "echo" function - arguments: ['/C', 'echo %ENV_TEST%'], // ' & type CON' should display stdin, but doesn't work - // Printing an environnement variable set here by the parent process - environment: ['ENV_TEST='+envTestValue], - - stdin: function(stdin) { - // Win32 command line is not really made for stdin - // So it doesn't seems to work as it's hard to retrieve stdin - stdin.write("stdin"); - stdin.close(); - }, - stdout: function(data) { - test.assert(!gotStdout,"don't get stdout twice"); - test.assertEqual(data,envTestValue+"\r\n","stdout contains the environment variable"); - gotStdout = true; - }, - stderr: function(data) { - test.fail("shouldn't get stderr"); - }, - done: function() { - test.assert(gotStdout, "got stdout before finished"); - test.done(); - }, - mergeStderr: false - }); - -} - -exports.testWindowsStderr = function (test) { - test.waitUntilDone(); - let gotStderr = false; - - var p = subprocess.call({ - command: env.get('ComSpec'), - arguments: ['/C', 'nonexistent'], - - stdout: function(data) { - test.fail("shouldn't get stdout"); - }, - stderr: function(data) { - test.assert(!gotStderr,"don't get stderr twice"); - test.assertEqual( - data, - "'nonexistent' is not recognized as an internal or external command,\r\n" + - "operable program or batch file.\r\n", - "stderr contains the error message" - ); - gotStderr = true; - }, - done: function() { - test.assert(gotStderr, "got stderr before finished"); - test.done(); - }, - mergeStderr: false - }); - -} - -} - -if (env.get('USER') && env.get('SHELL')) { - -exports.testUnix = function (test) { - test.waitUntilDone(); - let envTestValue = "OK"; - let gotStdout = false; - - var p = subprocess.call({ - command: '/bin/sh', - // Print stdin and our env variable - //arguments: ['-c', 'echo $@ $ENV_TEST'], - environment: ['ENV_TEST='+envTestValue], - - stdin: function(stdin) { - stdin.write("echo $ENV_TEST"); - stdin.close(); - }, - stdout: function(data) { - test.assert(!gotStdout,"don't get stdout twice"); - test.assertEqual(data,envTestValue+"\n","stdout contains the environment variable"); - gotStdout = true; - }, - stderr: function(data) { - test.fail("shouldn't get stderr"); - }, - done: function() { - test.assert(gotStdout, "got stdout before finished"); - test.done(); - }, - mergeStderr: false - }); -} - -exports.testUnixStderr = function (test) { - test.waitUntilDone(); - let gotStderr = false; - - var p = subprocess.call({ - // Hope that we don't have to give absolute path on linux ... - command: '/bin/sh', - arguments: ['nonexistent'], - - stdout: function(data) { - test.fail("shouldn't get stdout"); - }, - stderr: function(data) { - test.assert(!gotStderr,"don't get stderr twice"); - // There is two variant of error message - if (data == "/bin/sh: 0: Can't open nonexistent\n") - test.pass("stderr containes the expected error message"); - else - test.assertEqual(data, "/bin/sh: nonexistent: No such file or directory\n", - "stderr contains the error message"); - gotStderr = true; - }, - done: function() { - test.assert(gotStderr, "got stderr before finished"); - test.done(); - }, - mergeStderr: false - }); -} - -}
--- a/configure.in +++ b/configure.in @@ -160,30 +160,21 @@ fi AC_SUBST(L10NBASEDIR) dnl Check for Perl first -- needed for win32 SDK checks MOZ_PATH_PROGS(PERL, $PERL perl5 perl ) if test -z "$PERL" -o "$PERL" = ":"; then AC_MSG_ERROR([perl not found in \$PATH]) fi -if test -n "$GAIADIR" -a ! -d "$GAIADIR" ; then - AC_MSG_ERROR([GAIADIR '$GAIADIR' isn't a valid directory]) -fi - AC_SUBST(GAIADIR) if test -n "$GAIADIR" ; then AC_DEFINE(PACKAGE_GAIA) fi -if test -n "$FXOS_SIMULATOR" -a -z "$GAIADIR" ; then - AC_MSG_ERROR([FXOS_SIMULATOR=1 requires GAIADIR to be defined]) -fi -AC_SUBST(FXOS_SIMULATOR) - MOZ_ARG_WITH_STRING(gonk, [ --with-gonk=DIR location of gonk dir], gonkdir=$withval) MOZ_ARG_WITH_STRING(gonk-toolchain-prefix, [ --with-gonk-toolchain-prefix=DIR prefix to gonk toolchain commands], @@ -4245,17 +4236,16 @@ b2g) AC_DEFINE(MOZ_B2G) ;; esac AC_SUBST(MOZ_BUILD_APP) AC_SUBST(MOZ_PHOENIX) AC_SUBST(MOZ_XULRUNNER) AC_SUBST(MOZ_B2G) -AC_SUBST(MOZ_B2G_VERSION) AC_DEFINE_UNQUOTED(MOZ_BUILD_APP,$MOZ_BUILD_APP) dnl ======================================================== dnl Check android sdk version depending on mobile target dnl ======================================================== if test -z "$gonkdir" ; then