UNPKG

watch_r-structr-lock

Version:

This is watch_r 0.0.14 but locks down structr

283 lines (185 loc) 4.67 kB
var EventEmitter = require('events').EventEmitter, fs = require('fs'), Structr = require('structr'), _ = require("underscore"); function eachAsync(target, callback) { var n = target.length; function next() { n--; callback(target[n], n); if(n) process.nextTick(next); } if(n) process.nextTick(next); }; var Watchr = Structr({ /** */ '__construct': function(ops) { this._em = new EventEmitter(); //resolved path to given file this.path = ops.path; this._children = {}; //files that are currently being watched - only *one* watcher this._watching = ops.watching; this.created = ops.created; this._watch = ops.watch; this.parent(ops.parent); this.init(); }, /** */ 'on': function(event, callback) { this._em.addListener(event, callback); }, /** */ 'parent': function(value) { if(value) { this._parent = value; } return this._parent; }, /** */ 'root': function() { var p = this; while(p._parent) { p = p._parent; }; return p; }, /** */ 'dispose': function() { this.change('remove', this); delete this._watching[this.path]; fs.unwatchFile(this.path); this._em = new EventEmitter(); if(this.isDirectory) { for(var file in this._children) { var watcher = this._watching[this.path + '/' + file]; if(watcher) watcher.dispose(); } } }, /** */ 'init': function() { var path = this.path, self = this; try { var stat = fs.statSync(path); } catch(e) { this.dispose(); return; } var isDir = stat.isDirectory(), onFileChange; if(this.isDirectory = stat.isDirectory()) { onFileChange = function(cur, prev) { self._watchDirFiles(!!cur); } onFileChange(); } else { onFileChange = function(cur, prev) { if(cur.nlink != 0 && cur.mtime.getTime() == prev.mtime.getTime()) return; if(cur.nlink == 0) self.dispose(); else self.change(); }; if(this.created) { this.change("new", this); } this.change('file', this); } if(this.root()._watch !== false) { fs.watchFile(path, { persistent: true, interval: 500 }, onFileChange); } }, /** */ 'change': function(event, target) { if(!event) event = 'change'; if(!target) target = this; this._em.emit(event, target); if(this.parent()) { this.parent().change(event, target); } else if(event == 'change') { for(var path in this._watching) { var watcher = this._watching[path]; if(!watcher.isDirectory) continue; watcher._watchDirFiles(); } } }, /** */ '_scanForNewFiles': function() { for(path in this._watching) { var watcher = this._watching[path]; if(!watcher.isDirectory) continue; watcher._watchDirFiles(); } }, /** */ '_watchDirFiles': function(triggerFromWatch) { var self = this, path = self.path; process.nextTick(function() { fs.readFile(path + '/.ignorewatch', 'utf8', function(err, content) { var ignore = {}; if(content != undefined) { var n = 0; content.split(/[\s\r\n\t]+/g).forEach(function(file) { if(!file.match(/\w+/g)) return; n++; ignore[file] = 1; }) //nothing specified, or star if(!n || ignore['*']) return; } fs.readdir(path, function(err, files) { if(err) return; files.forEach(function(file, i) { if(file.substr(0,1) == '.' || ignore[file]) return; var filePath = path + '/' + file; self._children[file] = 1; Watchr.watch({ path: filePath, resolved: true, parent: self, watching: self._watching, created: triggerFromWatch }); }); }); }); }); }, /** * called by user */ 'static watch': function(ops, callback) { if(!callback) callback = function() { }; function onResolvedPath(err, resolvedPath) { var watcher = ops.watching[resolvedPath]; if(watcher) { return callback(false, watcher); } callback(false, ops.watching[resolvedPath] = new Watchr(ops)); } if(!ops.resolved) { fs.realpath(ops.path, onResolvedPath); } else { onResolvedPath(false, ops.path); } } }); var watching = {}; module.exports = function(file, ops, callback) { if(arguments.length == 2) { callback = ops; ops = {}; } if(file instanceof Array) { return file.forEach(function(f) { module.exports(f, callback); }); } Watchr.watch(_.extend(ops, { path: file, watching: watching }), callback); }