introduce command classes

This commit is contained in:
oleg 2014-05-10 14:19:47 +04:00
parent da9d4a5c25
commit b1f91ebca4
6 changed files with 103 additions and 54 deletions

23
lib/command/base.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
var EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits;
function Command(params) {
params = params || {};
this.isEmit = params.isEmit;
}
exports.BaseCommand = Command;
inherits(Command, EventEmitter);
Command.prototype.enableEmitter = function() {
this.isEmit = true;
return this;
};
Command.prototype.disableEmitter = function() {
this.isEmit = false;
return this;
};

37
lib/command/spawn.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
var spawn = require('child_process').spawn,
ParentCommand = require('./base').BaseCommand,
inherits = require('util').inherits;
function Command(params) {
params = params || {};
ParentCommand.call(this, params);
this.cwd = params.cwd;
}
exports.SpawnCommand = Command;
inherits(Command, ParentCommand);
Command.prototype.exec = function(params, callback) {
var self = this,
stdout = '';
var cmd = spawn(params.cmd, params.args, {cwd: this.cwd});
cmd.stdout.on('data', function(data) {
if (self.isEmit) self.emit('stdout', data);
stdout += data;
});
cmd.stderr.on('data', function(data) {
callback(new Error('Scm outputs to stderr: ' + data));
cmd.kill();
});
cmd.on('exit', function(code) {
var err = null;
if (code !== 0) err = new Error(
'Scm command exits with non-zero code: ' + code
);
callback(err, stdout);
});
return cmd;
};

View File

@ -1,70 +1,47 @@
'use strict'; 'use strict';
var spawn = require('child_process').spawn, var ParentCommand = require('../command/spawn').SpawnCommand,
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits; inherits = require('util').inherits;
function BaseScm(params) { function Scm(params) {
ParentCommand.call(this, params);
this.repository = params.repository; this.repository = params.repository;
this.cwd = params.cwd;
if (!this.repository && !this.cwd) throw new Error( if (!this.repository && !this.cwd) throw new Error(
'`repository` or `cwd` must be set' '`repository` or `cwd` must be set'
); );
} }
module.exports = BaseScm; exports.BaseScm = Scm;
inherits(BaseScm, EventEmitter); inherits(Scm, ParentCommand);
BaseScm.prototype._exec = function(command, args, callback) {
var self = this,
stdout = '';
var cmd = spawn(command, args, {cwd: this.cwd});
cmd.stdout.on('data', function(data) {
if (self.isEmit) self.emit('stdout', data);
stdout += data;
});
cmd.stderr.on('data', function(data) {
callback(new Error('Scm outputs to stderr: ' + data));
cmd.kill();
});
cmd.on('exit', function(code) {
var err = null;
if (code !== 0) err = new Error(
'Scm command exits with non-zero code: ' + code
);
callback(err, stdout);
});
return cmd;
};
/** /**
* Clone repository to the `dst` update to `rev` and set `this.cwd` to `dst` * Clone repository to the `dst` update to `rev` and set `this.cwd` to `dst`
*/ */
BaseScm.prototype.clone = function(dst, rev, callback) { Scm.prototype.clone = function(dst, rev, callback) {
}; };
/** /**
* Pull changes from remote repository without update * Pull changes from remote repository without update
*/ */
BaseScm.prototype.pull = function(rev, callback) { Scm.prototype.pull = function(rev, callback) {
}; };
/** /**
* Returns string id of current revision * Returns string id of current revision
*/ */
BaseScm.prototype.getId = function(callback) { Scm.prototype.getId = function(callback) {
}; };
/** /**
* Returns array of changes between revisions * Returns array of changes between revisions
*/ */
BaseScm.prototype.getChanges = function(rev1, rev2, callback) { Scm.prototype.getChanges = function(rev1, rev2, callback) {
}; };
/** /**
* Updates to revision * Updates to revision
*/ */
BaseScm.prototype.update = function(rev, callback) { Scm.prototype.update = function(rev, callback) {
}; };

View File

@ -2,7 +2,11 @@
var path = require('path'); var path = require('path');
var typesHash = {
'mercurial': require('./mercurial').MercurialScm
};
exports.createScm = function(config) { exports.createScm = function(config) {
var Constructor = require(path.join(__dirname, config.type)); var Constructor = typesHash[config.type];
return new Constructor(config); return new Constructor(config);
}; };

View File

@ -1,41 +1,44 @@
'use strict'; 'use strict';
var BaseScm = require('./base'), var ParentScm = require('./base').BaseScm,
inherits = require('util').inherits; inherits = require('util').inherits;
function MercurialScm(params) { function Scm(params) {
BaseScm.call(this, params); ParentScm.call(this, params);
} }
module.exports = MercurialScm; exports.MercurialScm = Scm;
inherits(MercurialScm, BaseScm); inherits(Scm, ParentScm);
MercurialScm.prototype.defaultRev = 'default'; Scm.prototype.defaultRev = 'default';
MercurialScm.prototype.clone = function(dst, rev, callback) { Scm.prototype.clone = function(dst, rev, callback) {
var self = this; var self = this;
this._exec('hg', ['clone', '--rev', rev, this.repository, dst], function(err) { this.exec({
cmd: 'hg',
args: ['clone', '--rev', rev, this.repository, dst]
}, function(err) {
self.cwd = dst; self.cwd = dst;
callback(err); callback(err);
}); });
}; };
MercurialScm.prototype.pull = function(rev, callback) { Scm.prototype.pull = function(rev, callback) {
this._exec('hg', ['pull', '--rev', rev], callback); this.exec({cmd: 'hg', args: ['pull', '--rev', rev]}, callback);
}; };
MercurialScm.prototype.getId = function(callback) { Scm.prototype.getId = function(callback) {
this._exec('hg', ['id', '--id'], function(err, stdout) { this.exec({cmd: 'hg', args: ['id', '--id']}, function(err, stdout) {
callback(err, !err && stdout.replace('\n', '')); callback(err, !err && stdout.replace('\n', ''));
}); });
}; };
MercurialScm.prototype.getChanges = function(rev1, rev2, callback) { Scm.prototype.getChanges = function(rev1, rev2, callback) {
this._exec('hg', [ this.exec({cmd: 'hg', args: [
'log', '--rev', rev2 + ':' + rev1, 'log', '--rev', rev2 + ':' + rev1,
'--template', '{node|short};;;{author};;;{date|date};;;{desc}\n' '--template', '{node|short};;;{author};;;{date|date};;;{desc}\n'
], function(err, stdout) { ]}, function(err, stdout) {
callback(err, !err && stdout.split('\n').slice(0, -2).map(function(str) { callback(err, !err && stdout.split('\n').slice(0, -2).map(function(str) {
var parts = str.split(';;;'); var parts = str.split(';;;');
return { return {
@ -48,6 +51,6 @@ MercurialScm.prototype.getChanges = function(rev1, rev2, callback) {
}); });
}; };
MercurialScm.prototype.update = function(rev, callback) { Scm.prototype.update = function(rev, callback) {
this._exec('hg', ['up', rev], callback); this.exec({cmd: 'hg', args: ['up', rev]}, callback);
}; };

View File

@ -3,7 +3,8 @@
var expect = require('expect.js'), var expect = require('expect.js'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
createScm = require('../lib/scm').createScm; createScm = require('../lib/scm').createScm,
SpawnCommand = require('../lib/command/spawn').SpawnCommand;
['mercurial'].forEach(function(type) { ['mercurial'].forEach(function(type) {
@ -12,10 +13,14 @@ var expect = require('expect.js'),
repositoryName = 'test-repository', repositoryName = 'test-repository',
repositoryPath = path.join(path.join(__dirname, 'repos'), repositoryName); repositoryPath = path.join(path.join(__dirname, 'repos'), repositoryName);
function rmdir(dir, callback) {
new SpawnCommand().exec({cmd: 'rm', args: ['-R', dir]}, callback);
}
it('remove test repository dir if it exists', function(done) { it('remove test repository dir if it exists', function(done) {
if (fs.exists(repositoryPath, function(isExists) { if (fs.exists(repositoryPath, function(isExists) {
if (isExists) { if (isExists) {
scm._exec('rm', ['-R', repositoryPath], done); rmdir(repositoryPath, done);
} else { } else {
done(); done();
} }
@ -101,7 +106,7 @@ var expect = require('expect.js'),
}); });
it('remove test repository dir', function(done) { it('remove test repository dir', function(done) {
scm._exec('rm', ['-R', repositoryPath], done); rmdir(repositoryPath, done);
}); });
}); });
}); });