mirror of
https://github.com/samsonjs/batteries.git
synced 2026-03-25 09:15:46 +00:00
add FileFollower for tail -f functionality
This commit is contained in:
parent
5295fe8f20
commit
1652d2a782
2 changed files with 88 additions and 4 deletions
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
var fs = require('fs')
|
||||
, ArrayExt = require('./array-ext')
|
||||
, FileFollower = require('./file-follower')
|
||||
, LineEmitter = require('./line-emitter')
|
||||
, ObjectExt = require('./object-ext')
|
||||
, constants = require('constants')
|
||||
|
|
@ -12,6 +13,7 @@ var fs = require('fs')
|
|||
FileExt =
|
||||
{ eachLine: eachLine
|
||||
, exists: exists
|
||||
, follow: follow
|
||||
, grep: grep
|
||||
, home: home
|
||||
, readLines: readLines
|
||||
|
|
@ -58,14 +60,22 @@ function eachLine(f, optionsOrLineFn, endFn) {
|
|||
|
||||
function exists(f) {
|
||||
try {
|
||||
fs.statSync(f)
|
||||
return true
|
||||
fs.statSync(f);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e.errno === constants.ENOENT) return false
|
||||
throw e
|
||||
if (e.errno === constants.ENOENT) return false;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function follow(f, lineFn) {
|
||||
var ff = new FileFollower(f);
|
||||
ff.on('line', lineFn);
|
||||
return {
|
||||
stop: ff.stopFollowing.bind(ff)
|
||||
};
|
||||
}
|
||||
|
||||
function grep(regex, f, callback) {
|
||||
if (!callback) throw new Error('grep requires a callback');
|
||||
var results = [];
|
||||
|
|
|
|||
74
lib/file-follower.js
Normal file
74
lib/file-follower.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// batteries
|
||||
// Copyright 2010 - 2011 Sami Samhuri <sami@samhuri.net>
|
||||
|
||||
var fs = require('fs')
|
||||
, util = require('util')
|
||||
, EventEmitter = require('events').EventEmitter
|
||||
, FileExt = require('./file-ext')
|
||||
;
|
||||
|
||||
module.exports = FileFollower;
|
||||
|
||||
// TODO: option to act like tail and only show the last N lines, N >= 0
|
||||
function FileFollower(file, options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
this.file = file;
|
||||
this.currSize = fs.statSync(file).size;
|
||||
this.prevSize = this.currSize;
|
||||
this.interval = options.interval || 1000;
|
||||
FileExt.eachLine(file,
|
||||
{ line: function(line) {
|
||||
self.emit('line', line);
|
||||
}
|
||||
, end: function() {
|
||||
self.startFollowing();
|
||||
}
|
||||
});
|
||||
}
|
||||
util.inherits(FileFollower, EventEmitter);
|
||||
|
||||
FileFollower.prototype.startFollowing = function() {
|
||||
if (this._interval) {
|
||||
console.warn('already following');
|
||||
return;
|
||||
}
|
||||
this.buffer = '';
|
||||
this.fd = fs.openSync(this.file, 'r');
|
||||
this._interval = setInterval(this.checkForLine.bind(this), this.interval);
|
||||
};
|
||||
|
||||
FileFollower.prototype.stopFollowing = function() {
|
||||
if (!this._interval) {
|
||||
console.warn('not following');
|
||||
return;
|
||||
}
|
||||
delete this.buffer;
|
||||
clearInterval(this._interval);
|
||||
delete this._interval;
|
||||
fs.closeSync(this.fd);
|
||||
delete this.fd;
|
||||
};
|
||||
|
||||
FileFollower.prototype.checkForLine = function() {
|
||||
this.currSize = fs.statSync(this.file).size;
|
||||
if (this.currSize > this.prevSize) {
|
||||
var n = this.currSize - this.prevSize
|
||||
, buf = new Buffer(n + 1)
|
||||
, self = this
|
||||
;
|
||||
fs.read(this.fd, buf, 0, n, this.prevSize, function(err, bytesRead, buffer) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
self.buffer += buf.slice(0, bytesRead);
|
||||
self.prevSize += bytesRead;
|
||||
var i;
|
||||
while ((i = self.buffer.indexOf('\n')) !== -1) {
|
||||
self.emit('line', self.buffer.slice(0, i));
|
||||
self.buffer = self.buffer.slice(i + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue