Skip to content

Instantly share code, notes, and snippets.

@Psvensso
Last active November 8, 2015 17:10
Show Gist options
  • Save Psvensso/06cdb960d1cf08eff002 to your computer and use it in GitHub Desktop.
Save Psvensso/06cdb960d1cf08eff002 to your computer and use it in GitHub Desktop.
No dependency filewatcher
var EventEmitter = require('events').EventEmitter;
var path = require('path');
var fs = require('fs');
var exec = require('child_process').exec;
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var settings = {
dir: __dirname,
filter: function(path){return true},
onChange: debounce(function(){
console.log("########################################################################## \n");
exec("elixir sublist_test.exs",function(error, stdout, stderr) {
if(stdout.indexOf("tests, 0 failures") > -1){
console.log("\x1b[32m########################################################################## \n");
} else {
console.log("\x1b[31m########################################################################## \n");
}
console.log('\x1b[0mmstdout: ' + stdout);
console.log(stderr);
if(stdout.indexOf("tests, 0 failures") > -1){
console.log("\x1b[32m########################################################################## \n");
} else {
console.log("\x1b[31m########################################################################## \n");
}
console.log("");
if (error !== null) {
console.log('exec error: ' + error);
}
});
}, 100)
}
function Watcher(opts) {
EventEmitter.call(this);
this.filter = opts && typeof opts.filter == 'function' && opts.filter || null;
this.root = opts && opts.root || null;
this.dir = null;
}
Watcher.prototype = Object.create(EventEmitter.prototype);
Watcher.prototype.watch = function(dir, cb) {
var self = this;
this.root = dir || this.root;
if(typeof this.root != 'string') {
var e = new Error('Must pass a file or directory to Watcher.watch');
if(typeof cb == 'function') return cb(e);
throw e;
}
fs.stat(this.root, function(err, stats) {
if(err) {
return cb(err);
}
if(stats.isDirectory()) {
self.dir = new Dir(self, '.', stats);
}
else {
cb(new Error("Root must be a directory"));
//this.watch = fs.watch(file, onChange.bind(self, self.file = new File(self, path.join('.', path.basename(file)), stats)));
}
});
};
function onChange(src, event, filename) {
var self = this;
var file = filename === null && src.path || path.join(src.path, filename);
fs.stat(path.join(self.root, file), function(err, stats) {
var ev, _f = src.files[filename];
if(err) {
// file deleted
if(err.code == 'ENOENT') {
if(_f) {
if(_f instanceof Dir) {
_f.stop();
}
ev = new Event(_f.stats, file, null, null);
self.emit('delete', ev);
self.emit('any', 'delete', ev);
}
delete src.files[filename];
}
// error ?
else {
self.emit('error', err);
}
}
// file created
else if(event == 'rename') {
if(_f === false) return;
if((self.filter || defaultFilter).call(self, file, stats)) {
if(stats.isDirectory()) {
src.files[filename] = new Dir(self, file, stats);
}
else {
src.files[filename] = new File(file, stats);
}
ev = new Event(null, null, stats, file);
self.emit('create', ev);
self.emit('any', 'create', ev);
}
else {
src.files[filename] = false;
}
}
// file changed
else if(event == 'change' && _f) {
ev = new Event(_f.stats, file, stats, file);
_f.stats = stats;
self.emit('change', ev);
self.emit('any', 'change', ev);
}
});
}
function defaultFilter() {return true;}
function Event(oldStats, oldPath, newStats, newPath) {
this.oldStats = oldStats;
this.oldPath = oldPath;
this.newStats = newStats;
this.newPath = newPath;
}
function File(path, stats) {
this.path = path;
this.stats = stats;
}
function Dir(self, _path, stats) {
File.call(this, _path, stats);
this.root = self;
this.watcher = fs.watch(path.join(self.root, _path), onChange.bind(self, this));
this.files = {};
// scan
var dir = this;
fs.readdir(path.join(self.root, _path), function(err, files) {
if(err) {
return self.emit('error', err);
}
files.forEach(function(file) {
fs.stat(path.join(self.root, dir.path, file), function(err, stats) {
if(err) {
return self.emit('error', err);
}
if((self.filter || defaultFilter).call(self, path.join(dir.path, file), stats)) {
if(stats.isDirectory()) {
dir.files[file] = new Dir(self, path.join(dir.path, file), stats);
}
else {
dir.files[file] = new File(path.join(dir.path, file), stats);
}
}
else {
dir.files[file] = false;
}
});
});
});
}
Dir.prototype = Object.create(File.prototype);
Dir.prototype.stop = function() {
this.watcher.close();
for(var file in this.files) {
if(this.files[file] && this.files[file] instanceof Dir) {
this.files[file].stop();
}
}
};
var watcher = new Watcher({
root: settings.dir,
filter: settings.filter || function(){return true}
});
watcher.on('change', settings.onChange);
watcher.watch();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment