<commit_before>include('io');

function createProcess(args) {
    // make command either a single string or an array of strings
    var command = args.length == 1 ? String(args[0]) : Array.map(args, String);
    return java.lang.Runtime.getRuntime().exec(command);
}

function connect(process, output, errput) {
    spawn(function() {
        new TextStream(new Stream(process.inputStream)).copy(output);
    }).get();
    spawn(function() {
        new TextStream(new Stream(process.errorStream)).copy(errput);
    }).get();
}

/**
 * executes a given command and returns the
 * standard output.  If the exit status is non-zero,
 * throws an Error.
 * @param {String} command and optional arguments as individual strings
 * @returns String the standard output of the command
 */
exports.command = function() {
    var process = createProcess(arguments);
    var output = new TextStream(new MemoryStream());
    var error = new TextStream(new MemoryStream());
    connect(process, output, error);
    var status = process.waitFor();
    if (status != 0) {
        throw new Error("(" + status + ") " + error.content);
    }
    return output.content;
};

/**
 * executes a given command, attached to this process's
 * output and error streams, and returns the exit status.
 * @param {String} command and optional arguments as individual strings
 * @returns Number exit status
 */
exports.system = function() {
    var process = createProcess(arguments);
    connect(process, system.stdout, system.stderr);
    return process.waitFor();
};

/**
 * executes a given command quietly and returns
 * the exit status.
 * @param {String} command and optional arguments as individual strings
 * @returns Number exit status
 */
exports.status = function() {
    var process = createProcess(arguments);
    connect(process, dummyStream(), dummyStream());
    return process.waitFor();
};

function dummyStream() {
    return {
        writable: function() true,
        readable: function() false,
        seekable: function() false,
        write: function() this,
        flush: function() this,<commit_msg>Allow ringo/subprocess methods to specify environment variables and directory to run in<commit_after>/**
 * @fileOverview A module for spawning processes, connecting to their
 * input/output/errput and returning their response codes.
 */

var {Stream, MemoryStream, TextStream} = require('io');
var arrays = require('ringo/utils/arrays');

function createProcess(args) {
    // arguments may end with a {dir: "", env: {}} object
    var opts = (args.length > 1 && arrays.peek(args) instanceof Object) ?
            Array.pop(args) : {};
    // make command either a single string or an array of strings
    var command = args.length == 1 ? String(args[0]) : Array.map(args, String);
    var {dir, env} = opts;
    dir = dir ? new java.io.File(dir) : null;
    if (env && !Array.isArray(env)) {
        // convert env to an array of the form ["key=value", ...]
        env = [key + "=" + env[key] for (key in env)];
    } else if (!env) {
        env = null;
    }
    return java.lang.Runtime.getRuntime().exec(command, env, dir);
}

function connect(process, output, errput) {
    spawn(function() {
        new TextStream(new Stream(process.inputStream)).copy(output);
    }).get();
    spawn(function() {
        new TextStream(new Stream(process.errorStream)).copy(errput);
    }).get();
}

/**
 * executes a given command and returns the
 * standard output.  If the exit status is non-zero,
 * throws an Error.
 * @param {String} command... and optional arguments as individual strings
 * @param {Object} [options] options object. This may contain a `dir` string
 * property specifying the directory to run the process in and a `env`
 * object property specifying additional environment variable mappings.
 * @returns String the standard output of the command
 */
exports.command = function() {
    var process = createProcess(arguments);
    var output = new TextStream(new MemoryStream());
    var error = new TextStream(new MemoryStream());
    connect(process, output, error);
    var status = process.waitFor();
    if (status != 0) {
        throw new Error("(" + status + ") " + error.content);
    }
    return output.content;
};

/**
 * executes a given command, attached to this process's
 * output and error streams, and returns the exit status.
 * @param {String} command... and optional arguments as individual strings
 * @param {Object} [options] options object. This may contain a `dir` string
 * property specifying the directory to run the process in and a `env`
 * object property specifying additional environment variable mappings.
 * @returns Number exit status
 */
exports.system = function() {
    var process = createProcess(arguments);
    connect(process, system.stdout, system.stderr);
    return process.waitFor();
};

/**
 * executes a given command quietly and returns
 * the exit status.
 * @param {String} command... and optional arguments as individual strings
 * @param {Object} [options] options object. This may contain a `dir` string
 * property specifying the directory to run the process in and a `env`
 * object property specifying additional environment variable mappings.
 * @returns Number exit status
 */
exports.status = function() {
    var process = createProcess(arguments);
    connect(process, dummyStream(), dummyStream());
    return process.waitFor();
};

function dummyStream() {
    return {
        writable: function() true,
        readable: function() false,
        seekable: function() false,
        write: function() this,
        flush: function() this,
{'fraction_non_alphanumeric': 0.11955168119551682, 'fraction_numerical': 0.0012453300124533001, 'mean_word_length': 3.5192926045016075, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6315478', 'n_tokens_mistral': 1486, 'n_tokens_neox': 1463, 'n_words': 562}