<commit_before>var Connection = require('ssh2');
var async = require('async');

var Task = function Task(options) {
    this.connection = new Connection();
    this.connectionOptions = options;
    
    this.before = undefined;
    this.after = undefined;
    this.error = undefined;
    
    this.commands = [];
}

Task.prototype.clone = function cloneTask(options) {
    var task = new Task(options);
    
    task.before = this.before;
    task.commands = this.commands;
    task.after = this.after;
};

Task.prototype._performCommand = function _performCommand(command, callback, error) {
    if (command instanceof Function) return command(this, callback, error);
    
    this.log.info('Executing command ' + command);
    
    var _this = this;
    
    this.connection.exec(command, function(err, stream) {
        if (err) {
            _this.log.error(err.message);
            return callback(err);
        }
        
        stream.on('data', function(data, extended) {
            _this.log.info(extended + ':' + data.toString());
        });
        
        stream.on('exit', function(code, signal) {
            if (code !== 0) {
                var err = new Error('Task ' + command + ' exited with non-zero code ' + code);
                _this.log.error(err.message);
                return callback(err);
            }
            
            _this.log.info('Task exited with zero code');
            callback();
        });
    }); 
};

Task.prototype._performCommandOrSequence = function _performCommandOrSequence(command, callback) {
    if (!command || (command.length && command.length === 0)) callback();
    
    if (command instanceof Array) {
        var _this = this;
        
        async.eachSeries(
            command,
            function commandSequenceIterator(item, callback) {
                _this._performCommand.call(_this, item, callback);
            },
            function commandSequenceFinalCallback(err) {
                callback(err);
            }
        )
    } else {
        this._performCommand(command, callback);
    }
};

Task.prototype._connect = function _connect(callback) {
    var _this = this;
    
    this.connection.on('connect', function() {
        _this.log.info('Connected to remote host');
    });
    
    this.connection.on('banner', function(banner) {
        _this.log.info(banner);
    });
    
    this.connection.on('close', function() {
        _this.log.info('Connection to remote host closed.');
    })
    
    this.connection.on('ready', callback);
    this.connection.on('error', callback);
    this.connection.connect(this.connectionOptions);
};

Task.prototype._perform = function _perform(callback) {
    var _this = this;
    
    async.eachSeries(
        [ this.before, this.commands, this.after ],
        function(item, callback) {
            _this._performCommandOrSequence.call(_this, item, callback);
        },
        callback
    )
};

Task.prototype._disconnect = function _disconnect(callback) {
    this.connection.end();
};

Task.prototype.perform = function perform(callback, log) {
    var _this = this;
    
    this.log = log.child({ task : this.connectionOptions.username + '@' + this.connectionOptions.host + ':' + this.connectionOptions.port });
    
    function reportBack(err) {
        _this._disconnect.call(_this);
        callback(err);
    }
    
    async.series(
        [
            function(callback) {
                _this._connect.call(_this, callback);
            },
            function(callback) {
                _this._perform.call(_this, callback);
            },
        ],
        function(err) {
            if (err) {
                if (_this.error) {
                    _this._performCommandOrSequence.call(_this, _this.error, function() {
                        reportBack(err);
                    });
                } else {
                    reportBack(err);
                }
            } else {
                reportBack();
            }
        }
    );
};

Task.prototype.toString = function toString() {
    var result = [];
    
    function renderCommand(command) {
        if (command instanceof Function) {
            result.push('    [Function]');
        } else {
            result.push('    ' + command);
        }
    }
    <commit_msg>Session callback error object now exposes its task<commit_after>var Connection = require('ssh2');
var async = require('async');

var Task = function Task(options) {
    this.connection = new Connection();
    this.connectionOptions = options;
    
    this.before = undefined;
    this.after = undefined;
    this.error = undefined;
    
    this.commands = [];
}

Task.prototype.clone = function cloneTask(options) {
    var task = new Task(options);
    
    task.before = this.before;
    task.commands = this.commands;
    task.after = this.after;
};

Task.prototype._performCommand = function _performCommand(command, callback, error) {
    if (command instanceof Function) return command(this, callback, error);
    
    this.log.info('Executing command ' + command);
    
    var _this = this;
    
    this.connection.exec(command, function(err, stream) {
        if (err) {
            _this.log.error(err.message);
            return callback(err);
        }
        
        stream.on('data', function(data, extended) {
            _this.log.info(extended + ':' + data.toString());
        });
        
        stream.on('exit', function(code, signal) {
            if (code !== 0) {
                var err = new Error('Task ' + command + ' exited with non-zero code ' + code);
                _this.log.error(err.message);
                return callback(err);
            }
            
            _this.log.info('Task exited with zero code');
            callback();
        });
    }); 
};

Task.prototype._performCommandOrSequence = function _performCommandOrSequence(command, callback) {
    if (!command || (command.length && command.length === 0)) callback();
    
    if (command instanceof Array) {
        var _this = this;
        
        async.eachSeries(
            command,
            function commandSequenceIterator(item, callback) {
                _this._performCommand.call(_this, item, callback);
            },
            function commandSequenceFinalCallback(err) {
                callback(err);
            }
        )
    } else {
        this._performCommand(command, callback);
    }
};

Task.prototype._connect = function _connect(callback) {
    var _this = this;
    
    this.connection.on('connect', function() {
        _this.log.info('Connected to remote host');
    });
    
    this.connection.on('banner', function(banner) {
        _this.log.info(banner);
    });
    
    this.connection.on('close', function() {
        _this.log.info('Connection to remote host closed.');
    })
    
    this.connection.on('ready', callback);
    this.connection.on('error', callback);
    this.connection.connect(this.connectionOptions);
};

Task.prototype._perform = function _perform(callback) {
    var _this = this;
    
    async.eachSeries(
        [ this.before, this.commands, this.after ],
        function(item, callback) {
            _this._performCommandOrSequence.call(_this, item, callback);
        },
        callback
    )
};

Task.prototype._disconnect = function _disconnect(callback) {
    this.connection.end();
};

Task.prototype.perform = function perform(callback, log) {
    var _this = this;
    
    this.log = log.child({ task : this.connectionOptions.username + '@' + this.connectionOptions.host + ':' + this.connectionOptions.port });
    
    function reportBack(err) {
        _this._disconnect.call(_this);
        callback(err);
    }
    
    async.series(
        [
            function(callback) {
                _this._connect.call(_this, callback);
            },
            function(callback) {
                _this._perform.call(_this, callback);
            },
        ],
        function(err) {
            if (err) {
                err.task = _this;
                if (_this.error) {
                    _this._performCommandOrSequence.call(_this, _this.error, function() {
                        reportBack(err);
                    });
                } else {
                    reportBack(err);
                }
            } else {
                reportBack();
            }
        }
    );
};

Task.prototype.toString = function toString() {
    var result = [];
    
    function renderCommand(command) {
        if (command instanceof Function) {
            result.push('    [Function]');
        } else {
            result.push('    ' + command);
        }
    }
    
{'fraction_non_alphanumeric': 0.12449614188644478, 'fraction_numerical': 0.0006910054128757342, 'mean_word_length': 1.8793103448275863, 'pattern_counts': {'":': 0, '<': 3, '<?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': '5057651', 'n_tokens_mistral': 2361, 'n_tokens_neox': 2320, 'n_words': 455}