UNPKG

jiny

Version:

Jiny - runs tests/jobs in parallel

205 lines (138 loc) 4.54 kB
var Class = require('plus.class'); var Slaves = new Class({ init: function () { var self = this; this.slaves = []; this.underscore = require('underscore'); this.async = require('async'); this.child_process = require('child_process'); this.queueStream = require('async-queue-stream'); var Events = require('events').EventEmitter; this.events = new Events(); this.initQueue(); }, initQueue: function () { var self = this; this.jobQueue = this.async.queue(function (command, next) { self.execute(command.toString(), function () { next(); }); }); this.jobQueue.drain = function () { setTimeout(function () { if (!self.jobQueue.length()) { self.events.emit('jobs.done'); } }, 500); } self.resultStream = self.queueStream(); this.events.on('jobs.done', function () { self.resultStream.end(); self.resultStream = self.queueStream(); }); this.events.on('slaves.changed', function () { self.jobQueue.concurrency = self.count(); }); }, count: function () { return this.slaves.length; }, add: function (slave) { this.slaves.push(slave); slave.id = this.slaves.length; this.events.emit('slaves.changed'); }, getFree: function () { return this.underscore.find(this.slaves, function (slave) { return !slave.busy; }); }, getFreeAsync: function (next) { var slave = this.getFree(); if (slave) return next(null, slave); var interval = setInterval(function () { var slave = this.getFree(); if (slave) { clearInterval(interval); next(null, slave) } }.bind(this), 500); }, getBySocket: function (socket) { return this.underscore.find(this.slaves, function (slave) { return slave.api.socket == socket; }); }, remove: function (slave) { var idx = this.slaves.indexOf(slave); if (idx >= 0) { this.slaves.splice(idx, 1); this.events.emit('slaves.changed'); } }, removeBySocket: function (socket) { var slave = this.getBySocket(socket); if (slave) { this.remove(slave); } }, upload: function (dir, next) { var spawn = this.child_process.spawn; var packer = spawn('tar', ['-C', dir, '-cz', '.']); var fileStream = packer.stdout; this.async.map(this.slaves, function (slave, next) { console.log('#' + slave.id, slave.ip, 'uploading...'); slave.upload(fileStream, function (err, info) { next(err, info); }); }, next); }, run: function (command, next) { this.async.map(this.slaves, function (slave, next) { slave.command(command, function (error, info) { next(null, info); }); }, next); }, job: function (command, next) { this.jobQueue.push(command, function () { }); next(null, command); }, jobs: function (jobsStream, next) { jobsStream.pipe(this.queueStream(function (command, next) { this.job(command, next); }.bind(this))); this.events.on('jobs.done', function () { setTimeout(next, 500); }); }, execute: function (command, next) { var self = this; this.getFreeAsync(function (err, slave) { slave.busy = true; slave.command(command, function (error, info) { slave.busy = false; self.resultStream.write(info); next(null, info) }); }); }, stop: function (next) { if(!this.count()) return next(); this.async.map(this.slaves, function (slave, next) { slave.stop(next); }, next); }, waitSlaves: function (quantity, next) { var handle = function () { if (this.count() >= quantity) { this.events.removeListener('slaves.changed', handle); next(); } }.bind(this); this.events.on('slaves.changed', handle); handle(); } }); module.exports = Slaves;