rocess is successfully launched, but exits with
   * a non-zero exit code, the promise will still resolve successfully.
   */
  call(options) {
    options = Object.assign({}, options);

    options.stderr = options.stderr || "ignore";
    options.workdir = options.workdir || null;
    options.disclaim = options.disclaim || false;

    let environment = {};
    if (!options.environment || options.environmentAppend) {
      environment = this.getEnvironment();
    }

    if (options.environment) {
      Object.assign(environment, options.environment);
    }

    options.environment = Object.entries(environment)
      .map(([key, val]) => (val !== null ? encodeEnvVar(key, val) : null))
      .filter(s => s);

    options.arguments = Array.from(options.arguments || []);

    if (options.disclaim && !platformSupportsDisclaimedSpawn()) {
      options.disclaim = false;
    }

    return Promise.resolve(
      lazy.SubprocessImpl.isExecutableFile(options.command)
    ).then(isExecutable => {
      if (!isExecutable) {
        let error = new Error(
          `File at path "${options.command}" does not exist, or is not executable`
        );
        error.errorCode = SubprocessConstants.ERROR_BAD_EXECUTABLE;
        throw error;
      }

      options.arguments.unshift(options.command);

      return lazy.SubprocessImpl.call(options);
    });
  },

  /**
   * Returns an object with a key-value pair for every variable in the process's
   * current environment.
   *
   * @returns {object}
   */
  getEnvironment() {
    let environment = Object.create(null);
    for (let [k, v] of lazy.SubprocessImpl.getEnvironment()) {
      environment[k] = v;
    }
    return environment;
  },

  /**
   * Searches for the given executable file in the system executable
   * file paths as specified by the PATH environment variable.
   *
   * On Windows, if the unadorned filename cannot be found, the
   * extensions in the semicolon-separated list in the PATHSEP
   * environment variable are successively appended to the original
   * name and searched for in turn.
   *
   * @param {string} command
   *        The name of the executable to find.
   * @param {object} [environment]
   *        An object containing a key for each environment variable to be used
   *        in the search. If not provided, full the current process environment
   *        is used.
   * @returns {Promise<string>}
   */
  pathSearch(command, environment = this.getEnvironment()) {
    // Promise.resolve lets us get around returning one of the Promise.jsm
    // pseudo-promises returned by Task.jsm.
    let path = lazy.SubprocessImpl.pathSearch(command, environment);
    return Promise.resolve(path);
  },

  /**
   * Connect to an already-running subprocess
   * given the file descriptors for its stdin, stdout and stderr.
   *
   * @param {number[]} fds
   *        A list of three file descriptors [stdin, stdout, stderr].
   *
   * @returns {Promise<Process>}
   */
  connectRunning(fds) {
    return lazy.SubprocessImpl.connectRunning(fds);
  },
};

Object.assign(Subprocess, SubprocessConstants);
Object.freeze(Subprocess);

export function getSubprocessImplForTest() {
  return lazy.SubprocessImpl;
}
PK