Bug 1350646: Part 3 - Remove sdk/system/child_process modules. r?Mossop draft
authorKris Maglione <maglione.k@gmail.com>
Wed, 02 Aug 2017 13:52:47 -0700
changeset 641183 767779632b6d666499168e93fa612d0ff17ca828
parent 641182 48f82cd8e5ad9d8e18138255f23997638a5942f4
child 641184 61eb59c45332b9357a2e6b7fa03b63847acefb20
push id72469
push usermaglione.k@gmail.com
push dateSun, 06 Aug 2017 07:23:41 +0000
reviewersMossop
bugs1350646
milestone57.0a1
Bug 1350646: Part 3 - Remove sdk/system/child_process modules. r?Mossop MozReview-Commit-ID: LQgUe8E8M4k
addon-sdk/moz.build
addon-sdk/source/lib/sdk/system/child_process.js
addon-sdk/source/lib/sdk/system/child_process/subprocess.js
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -179,18 +179,16 @@ modules = [
     'sdk/request.js',
     'sdk/selection.js',
     'sdk/self.js',
     'sdk/simple-prefs.js',
     'sdk/simple-storage.js',
     'sdk/stylesheet/style.js',
     'sdk/stylesheet/utils.js',
     'sdk/system.js',
-    'sdk/system/child_process.js',
-    'sdk/system/child_process/subprocess.js',
     'sdk/system/environment.js',
     'sdk/system/events-shimmed.js',
     'sdk/system/events.js',
     'sdk/system/globals.js',
     'sdk/system/process.js',
     'sdk/system/runtime.js',
     'sdk/system/unload.js',
     'sdk/system/xul-app.js',
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/system/child_process.js
+++ /dev/null
@@ -1,332 +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';
-
-module.metadata = {
-  'stability': 'experimental'
-};
-
-var { Ci } = require('chrome');
-var subprocess = require('./child_process/subprocess');
-var { EventTarget } = require('../event/target');
-var { Stream } = require('../io/stream');
-var { on, emit, off } = require('../event/core');
-var { Class } = require('../core/heritage');
-var { platform } = require('../system');
-var { isFunction, isArray } = require('../lang/type');
-var { delay } = require('../lang/functional');
-var { merge } = require('../util/object');
-var { setTimeout, clearTimeout } = require('../timers');
-var isWindows = platform.indexOf('win') === 0;
-
-var processes = new WeakMap();
-
-
-/**
- * The `Child` class wraps a subprocess command, exposes
- * the stdio streams, and methods to manipulate the subprocess
- */
-var Child = Class({
-  implements: [EventTarget],
-  initialize: function initialize (options) {
-    let child = this;
-    let proc;
-
-    this.killed = false;
-    this.exitCode = undefined;
-    this.signalCode = undefined;
-
-    this.stdin = Stream();
-    this.stdout = Stream();
-    this.stderr = Stream();
-
-    try {
-      proc = subprocess.call({
-        command: options.file,
-        arguments: options.cmdArgs,
-        environment: serializeEnv(options.env),
-        workdir: options.cwd,
-        charset: options.encoding,
-        stdout: data => emit(child.stdout, 'data', data),
-        stderr: data => emit(child.stderr, 'data', data),
-        stdin: stream => {
-          child.stdin.on('data', pumpStdin);
-          child.stdin.on('end', function closeStdin () {
-            child.stdin.off('data', pumpStdin);
-            child.stdin.off('end', closeStdin);
-            stream.close();
-          });
-          function pumpStdin (data) {
-            stream.write(data);
-          }
-        },
-        done: function (result, error) {
-          if (error)
-            return handleError(error);
-
-          // Only emit if child is not killed; otherwise,
-          // the `kill` method will handle this
-          if (!child.killed) {
-            child.exitCode = result.exitCode;
-            child.signalCode = null;
-
-            // If process exits with < 0, there was an error
-            if (child.exitCode < 0) {
-              handleError(new Error('Process exited with exit code ' + child.exitCode));
-            }
-            else {
-              // Also do 'exit' event as there's not much of
-              // a difference in our implementation as we're not using
-              // node streams
-              emit(child, 'exit', child.exitCode, child.signalCode);
-            }
-
-            // Emit 'close' event with exit code and signal,
-            // which is `null`, as it was not a killed process
-            emit(child, 'close', child.exitCode, child.signalCode);
-          }
-        }
-      });
-      processes.set(child, proc);
-    } catch (e) {
-      // Delay the error handling so an error handler can be set
-      // during the same tick that the Child was created
-      delay(() => handleError(e));
-    }
-
-    // `handleError` is called when process could not even
-    // be spawned
-    function handleError (e) {
-      // If error is an nsIObject, make a fresh error object
-      // so we're not exposing nsIObjects, and we can modify it
-      // with additional process information, like node
-      let error = e;
-      if (e instanceof Ci.nsISupports) {
-        error = new Error(e.message, e.filename, e.lineNumber);
-      }
-      emit(child, 'error', error);
-      child.exitCode = -1;
-      child.signalCode = null;
-      emit(child, 'close', child.exitCode, child.signalCode);
-    }
-  },
-  kill: function kill (signal) {
-    let proc = processes.get(this);
-    proc.kill(signal);
-    this.killed = true;
-    this.exitCode = null;
-    this.signalCode = signal;
-    emit(this, 'exit', this.exitCode, this.signalCode);
-    emit(this, 'close', this.exitCode, this.signalCode);
-  },
-  get pid() { return processes.get(this, {}).pid || -1; }
-});
-
-function spawn (file, ...args) {
-  let cmdArgs = [];
-  // Default options
-  let options = {
-    cwd: null,
-    env: null,
-    encoding: 'UTF-8'
-  };
-
-  if (args[1]) {
-    merge(options, args[1]);
-    cmdArgs = args[0];
-  }
-  else {
-    if (isArray(args[0]))
-      cmdArgs = args[0];
-    else
-      merge(options, args[0]);
-  }
-
-  if ('gid' in options)
-    console.warn('`gid` option is not yet supported for `child_process`');
-  if ('uid' in options)
-    console.warn('`uid` option is not yet supported for `child_process`');
-  if ('detached' in options)
-    console.warn('`detached` option is not yet supported for `child_process`');
-
-  options.file = file;
-  options.cmdArgs = cmdArgs;
-
-  return Child(options);
-}
-
-exports.spawn = spawn;
-
-/**
- * exec(command, options, callback)
- */
-function exec (cmd, ...args) {
-  let file, cmdArgs, callback, options = {};
-
-  if (isFunction(args[0]))
-    callback = args[0];
-  else {
-    merge(options, args[0]);
-    callback = args[1];
-  }
-
-  if (isWindows) {
-    file = 'C:\\Windows\\System32\\cmd.exe';
-    cmdArgs = ['/S/C', cmd || ''];
-  }
-  else {
-    file = '/bin/sh';
-    cmdArgs = ['-c', cmd];
-  }
-
-  // Undocumented option from node being able to specify shell
-  if (options && options.shell)
-    file = options.shell;
-
-  return execFile(file, cmdArgs, options, callback);
-}
-exports.exec = exec;
-/**
- * execFile (file, args, options, callback)
- */
-function execFile (file, ...args) {
-  let cmdArgs = [], callback;
-  // Default options
-  let options = {
-    cwd: null,
-    env: null,
-    encoding: 'utf8',
-    timeout: 0,
-    maxBuffer: 204800,    //200 KB (200*1024 bytes)
-    killSignal: 'SIGTERM'
-  };
-
-  if (isFunction(args[args.length - 1]))
-    callback = args[args.length - 1];
-
-  if (isArray(args[0])) {
-    cmdArgs = args[0];
-    merge(options, args[1]);
-  } else if (!isFunction(args[0]))
-    merge(options, args[0]);
-
-  let child = spawn(file, cmdArgs, options);
-  let exited = false;
-  let stdout = '';
-  let stderr = '';
-  let error = null;
-  let timeoutId = null;
-
-  child.stdout.setEncoding(options.encoding);
-  child.stderr.setEncoding(options.encoding);
-
-  on(child.stdout, 'data', pumpStdout);
-  on(child.stderr, 'data', pumpStderr);
-  on(child, 'close', exitHandler);
-  on(child, 'error', errorHandler);
-
-  if (options.timeout > 0) {
-    setTimeout(() => {
-      kill();
-      timeoutId = null;
-    }, options.timeout);
-  }
-
-  function exitHandler (code, signal) {
-
-    // Return if exitHandler called previously, occurs
-    // when multiple maxBuffer errors thrown and attempt to kill multiple
-    // times
-    if (exited) return;
-    exited = true;
-
-    if (!isFunction(callback)) return;
-
-    if (timeoutId) {
-      clearTimeout(timeoutId);
-      timeoutId = null;
-    }
-
-    if (!error && (code !== 0 || signal !== null))
-      error = createProcessError(new Error('Command failed: ' + stderr), {
-        code: code,
-        signal: signal,
-        killed: !!child.killed
-      });
-
-    callback(error, stdout, stderr);
-
-    off(child.stdout, 'data', pumpStdout);
-    off(child.stderr, 'data', pumpStderr);
-    off(child, 'close', exitHandler);
-    off(child, 'error', errorHandler);
-  }
-
-  function errorHandler (e) {
-    error = e;
-    exitHandler();
-  }
-
-  function kill () {
-    try {
-      child.kill(options.killSignal);
-    } catch (e) {
-      // In the scenario where the kill signal happens when
-      // the process is already closing, just abort the kill fail
-      if (/library is not open/.test(e))
-        return;
-      error = e;
-      exitHandler(-1, options.killSignal);
-    }
-  }
-
-  function pumpStdout (data) {
-    stdout += data;
-    if (stdout.length > options.maxBuffer) {
-      error = new Error('stdout maxBuffer exceeded');
-      kill();
-    }
-  }
-
-  function pumpStderr (data) {
-    stderr += data;
-    if (stderr.length > options.maxBuffer) {
-      error = new Error('stderr maxBuffer exceeded');
-      kill();
-    }
-  }
-
-  return child;
-}
-exports.execFile = execFile;
-
-exports.fork = function fork () {
-  throw new Error("child_process#fork is not currently supported");
-};
-
-function serializeEnv (obj) {
-  return Object.keys(obj || {}).map(prop => prop + '=' + obj[prop]);
-}
-
-function createProcessError (err, options = {}) {
-  // If code and signal look OK, this was probably a failure
-  // attempting to spawn the process (like ENOENT in node) -- use
-  // the code from the error message
-  if (!options.code && !options.signal) {
-    let match = err.message.match(/(NS_ERROR_\w*)/);
-    if (match && match.length > 1)
-      err.code = match[1];
-    else {
-      // If no good error message found, use the passed in exit code;
-      // this occurs when killing a process that's already closing,
-      // where we want both a valid exit code (0) and the error
-      err.code = options.code != null ? options.code : null;
-    }
-  }
-  else
-    err.code = options.code != null ? options.code : null;
-  err.signal = options.signal || null;
-  err.killed = options.killed || false;
-  return err;
-}
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/system/child_process/subprocess.js
+++ /dev/null
@@ -1,184 +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 { Ci, Cu } = require("chrome");
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Subprocess.jsm");
-
-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);
-}
-
-function awaitPromise(promise) {
-  let value;
-  let resolved = null;
-  promise.then(val => {
-    resolved = true;
-    value = val;
-  }, val => {
-    resolved = false;
-    value = val;
-  });
-
-  Services.tm.spinEventLoopUntil(() => resolved !== null);
-
-  if (resolved === true)
-    return value;
-  throw value;
-}
-
-let readAllData = async function(pipe, read, callback) {
-  let string;
-  while (string = await read(pipe))
-    callback(string);
-};
-
-let write = (pipe, data) => {
-  let buffer = new Uint8Array(Array.from(data, c => c.charCodeAt(0)));
-  return pipe.write(data);
-};
-
-var subprocess = {
-  call: function(options) {
-    var result;
-
-    let procPromise = (async function() {
-      let opts = {};
-
-      if (options.mergeStderr) {
-        opts.stderr = "stdout"
-      } else if (options.stderr) {
-        opts.stderr = "pipe";
-      }
-
-      if (options.command instanceof Ci.nsIFile) {
-        opts.command = options.command.path;
-      } else {
-        opts.command = await Subprocess.pathSearch(options.command);
-      }
-
-      if (options.workdir) {
-        opts.workdir = options.workdir;
-      }
-
-      opts.arguments = options.arguments || [];
-
-
-      // Set up environment
-
-      let envVars = options.environment || DEFAULT_ENVIRONMENT;
-      if (envVars.length) {
-        let environment = {};
-        for (let val of envVars) {
-          let idx = val.indexOf("=");
-          if (idx >= 0)
-            environment[val.slice(0, idx)] = val.slice(idx + 1);
-        }
-
-        opts.environment = environment;
-      }
-
-
-      let proc = await Subprocess.call(opts);
-
-      Object.defineProperty(result, "pid", {
-        value: proc.pid,
-        enumerable: true,
-        configurable: true,
-      });
-
-
-      let promises = [];
-
-      // Set up IO handlers.
-
-      let read = pipe => pipe.readString();
-      if (options.charset === null) {
-        read = pipe => {
-          return pipe.read().then(buffer => {
-            return String.fromCharCode(...buffer);
-          });
-        };
-      }
-
-      if (options.stdout)
-        promises.push(readAllData(proc.stdout, read, options.stdout));
-
-      if (options.stderr && proc.stderr)
-        promises.push(readAllData(proc.stderr, read, options.stderr));
-
-      // Process stdin
-
-      if (typeof options.stdin === "string") {
-        write(proc.stdin, options.stdin);
-        proc.stdin.close();
-      }
-
-
-      // Handle process completion
-
-      if (options.done)
-        Promise.all(promises)
-          .then(() => proc.wait())
-          .then(options.done);
-
-      return proc;
-    })();
-
-    procPromise.catch(e => {
-      if (options.done)
-        options.done({exitCode: -1}, e);
-      else
-        Cu.reportError(e instanceof Error ? e : e.message || e);
-    });
-
-    if (typeof options.stdin === "function") {
-      // Unfortunately, some callers (child_process.js) depend on this
-      // being called synchronously.
-      options.stdin({
-        write(val) {
-          procPromise.then(proc => {
-            write(proc.stdin, val);
-          });
-        },
-
-        close() {
-          procPromise.then(proc => {
-            proc.stdin.close();
-          });
-        },
-      });
-    }
-
-    result = {
-      get pid() {
-        return awaitPromise(procPromise.then(proc => {
-          return proc.pid;
-        }));
-      },
-
-      wait() {
-        return awaitPromise(procPromise.then(proc => {
-          return proc.wait().then(({exitCode}) => exitCode);
-        }));
-      },
-
-      kill(hard = false) {
-        procPromise.then(proc => {
-          proc.kill(hard ? 0 : undefined);
-        });
-      },
-    };
-
-    return result;
-  },
-};
-
-module.exports = subprocess;