<commit_before>/*global require, exports, spawn: true */

var spawn = require('child_process').spawn,
    path = require('path'),
    Log = require('./log').Log;

function logBuffer(log, prefix, buffer) {
    var message = buffer.toString();
    log.puts(message, prefix);
}

function listen(process, log, callback) {
    var codes = '';
    process.stdout.addListener('data', function (data) {
        logBuffer(log, 'stdout: ', data);
    });

    process.stderr.addListener('data', function (data) {
        logBuffer(log, 'stderr: ', data);
    });

    process.addListener('exit', function (code) {
        logBuffer(log, 'exit: ', code);
        if (code === 0 && callback) {
            callback(this);
        }
    });
}

function ssh(command, callback) {
    if (!command) { 
        throw new Error(this.address + ': No command to run');
    }

    var log = this.logger,
        user = this.user,
        process = spawn('ssh', 
            ['-l' + user, this.address, "''" + command + "''"]);

    log.puts(user + ':ssh ' + command);
    listen(process, log, callback);
}

function scp(local, remote, callback) {
    if (!local) { 
        throw new Error(this.address + ': No local file path');
    }

    if (!remote) { 
        throw new Error(this.address + ': No remote file path');
    }

    var log = this.logger,
        user = this.user,
        address = this.address;
    path.exists(local, function (exists) {
        if (exists) {
            var reference = user + '@' + address + ':' + remote,
                args = [local, reference],
                process = spawn('scp', args);

            log.puts(user + ':scp: ' + local + ' ' + reference);
            listen(process, log, callback);
        } else {
            throw new Error('Local: ' + local + ' does not exist');
        }
    });
}

function log(message) {
    this.logger.puts(' ' + message);
}

var defaultLogPath = 'hosts.log';

function hostConstructor(config) {
    // This function may get called with different config objects
    // during a single config task (see deployment example). Therefore
    // we cannot define the constructor as a function declaration at module
    // scope and modify its prototype because the last config would become
    // the config for all hosts.
    function Host(address) {
        var logPath = config.log || defaultLogPath;
        this.address = address;
        this.logger = new Log(this.address + ':', logPath, true);
        this.log = log;
        this.ssh = ssh;
        this.scp = scp;

        // Allows task execution output to identify the host a task
        // is being executed for.
        this.id = address;

    }
    Host.prototype = config;
    return Host;
}

function host(config, address) {
    if (!config) {
        throw new Error("No config");
    }

    if (!address) {
        throw new Error("No remote host address");
    }

    var Host = hostConstructor(config);
    return new Host(address);
}


function hosts(config, addresses) {
    if (!config) {
        throw new Error("No config");
    }
    
    if (!addresses || !(addresses instanceof Array)) {
        throw new Error("No array of addresses");
    }

    var list = [], 
        i, length, address, host,
        Host = hostConstructor(config);
    for (i = 0, length = addresses.length; i < length; i += 1) {
        address = addresses[i];
        host = new Host(address);
        list.push(host);
    }
    return list;
}

exports.host = host;
exports.hosts = hosts;
<commit_msg>Adds sshOptions array to hosts objects and changes process variable name to avoid confusion with node process global.<commit_after>/*global require, exports, spawn: true */

var spawn = require('child_process').spawn,
    path = require('path'),
    Log = require('./log').Log;

function logBuffer(log, prefix, buffer) {
    var message = buffer.toString();
    log.puts(message, prefix);
}

function listen(subProcess, log, callback) {
    var codes = '';
    subProcess.stdout.addListener('data', function (data) {
        logBuffer(log, 'stdout: ', data);
    });

    subProcess.stderr.addListener('data', function (data) {
        logBuffer(log, 'stderr: ', data);
    });

    subProcess.addListener('exit', function (code) {
        logBuffer(log, 'exit: ', code);
        if (code === 0 && callback) {
            callback(this);
        }
    });
}

function ssh(command, callback) {
    if (!command) { 
        throw new Error(this.address + ': No command to run');
    }

    var log = this.logger,
        user = this.user,
        options = this.sshOptions,
        args = ['-l' + user, this.address, "''" + command + "''"],
        subProcess;
    
    if (options) {
        args = options.concat(args);
    }

    subProcess = spawn('ssh', args); 
    console.log('args' + args);

    log.puts(user + ':ssh ' + command);
    listen(subProcess, log, callback);
}

function scp(local, remote, callback) {
    if (!local) { 
        throw new Error(this.address + ': No local file path');
    }

    if (!remote) { 
        throw new Error(this.address + ': No remote file path');
    }

    var log = this.logger,
        user = this.user,
        address = this.address;
    path.exists(local, function (exists) {
        if (exists) {
            var reference = user + '@' + address + ':' + remote,
                args = ['-r', local, reference],
                subProcess = spawn('scp', args);

            log.puts(user + ':scp: ' + local + ' ' + reference);
            listen(subProcess, log, callback);
        } else {
            throw new Error('Local: ' + local + ' does not exist');
        }
    });
}

function log(message) {
    this.logger.puts(' ' + message);
}

var defaultLogPath = 'hosts.log';

function hostConstructor(config) {
    // This function may get called with different config objects
    // during a single config task (see deployment example). Therefore
    // we cannot define the constructor as a function declaration at module
    // scope and modify its prototype because the last config would become
    // the config for all hosts.
    function Host(address) {
        var logPath = config.log || defaultLogPath;
        this.address = address;
        this.logger = new Log(this.address + ':', logPath, true);
        this.log = log;
        this.sshOptions = [];
        this.ssh = ssh;
        this.scp = scp;

        // Allows task execution output to identify the host a task
        // is being executed for.
        this.id = address;

    }
    Host.prototype = config;
    return Host;
}

function host(config, address) {
    if (!config) {
        throw new Error("No config");
    }

    if (!address) {
        throw new Error("No remote host address");
    }

    var Host = hostConstructor(config);
    return new Host(address);
}

function hosts(config, addresses) {
    if (!config) {
        throw new Error("No config");
    }
    
    if (!addresses || !(addresses instanceof Array)) {
        throw new Error("No array of addresses");
    }

    var list = [], 
        i, length, address, host,
        Host = hostConstructor(config);
    for (i = 0, length = addresses.length; i < length; i += 1) {
        address = addresses[i];
        host = new Host(address);
        list.push(host);
    }
    return list;
}

exports.host = host;
exports.hosts = hosts;

{'fraction_non_alphanumeric': 0.13701236917221693, 'fraction_numerical': 0.0008155498165012913, 'mean_word_length': 2.2557522123893805, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '2911863', 'n_tokens_mistral': 2160, 'n_tokens_neox': 2086, 'n_words': 640}