Merge pull request #140 from humphd/issue132
Support fs.watch(), FSWatcher. Fixes #132
This commit is contained in:
commit
0cfb29eaec
48
README.md
48
README.md
|
@ -24,7 +24,6 @@ with the following differences:
|
||||||
|
|
||||||
* No synchronous versions of methods (e.g., `mkdir()` but not `mkdirSync()`).
|
* No synchronous versions of methods (e.g., `mkdir()` but not `mkdirSync()`).
|
||||||
* No permissions (e.g., no `chown()`, `chmod()`, etc.).
|
* No permissions (e.g., no `chown()`, `chmod()`, etc.).
|
||||||
* No support (yet) for `fs.watchFile()`, `fs.unwatchFile()`, `fs.watch()`.
|
|
||||||
* No support for stream-based operations (e.g., `fs.ReadStream`, `fs.WriteStream`).
|
* No support for stream-based operations (e.g., `fs.ReadStream`, `fs.WriteStream`).
|
||||||
|
|
||||||
Filer has other features lacking in node.js (e.g., swappable backend
|
Filer has other features lacking in node.js (e.g., swappable backend
|
||||||
|
@ -246,6 +245,7 @@ var fs = new Filer.FileSystem();
|
||||||
* [fs.fgetxattr(fd, name, callback)](#fgetxattr)
|
* [fs.fgetxattr(fd, name, callback)](#fgetxattr)
|
||||||
* [fs.removexattr(path, name, callback)](#removexattr)
|
* [fs.removexattr(path, name, callback)](#removexattr)
|
||||||
* [fs.fremovexattr(fd, name, callback)](#fremovexattr)
|
* [fs.fremovexattr(fd, name, callback)](#fremovexattr)
|
||||||
|
* [fs.watch(filename, [options], [listener])](#watch)
|
||||||
|
|
||||||
#### fs.rename(oldPath, newPath, callback)<a name="rename"></a>
|
#### fs.rename(oldPath, newPath, callback)<a name="rename"></a>
|
||||||
|
|
||||||
|
@ -954,6 +954,52 @@ fs.open('/myfile', 'r', function(err, fd) {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### fs.watch(filename, [options], [listener])<a name="watch"></a>
|
||||||
|
|
||||||
|
Watch for changes to a file or directory at `filename`. The object returned is an `FSWatcher`,
|
||||||
|
which is an [`EventEmitter`](http://nodejs.org/api/events.html) with the following additional method:
|
||||||
|
|
||||||
|
* `close()` - stops listening for changes, and removes all listeners from this instance. Use this
|
||||||
|
to stop watching a file or directory after calling `fs.watch()`.
|
||||||
|
|
||||||
|
The only supported option is `recursive`, which if `true` will cause a watch to be placed
|
||||||
|
on a directory, and all sub-directories and files beneath it.
|
||||||
|
|
||||||
|
The `listener` callback gets two arguments `(event, filename)`. `event` is either `'rename'` or `'change'`,
|
||||||
|
(currenty only `'rename'` is supported) and `filename` is the name of the file/dir which triggered the event.
|
||||||
|
|
||||||
|
Unlike node.js, all watch events return a path. Also, all returned paths are absolute from the root
|
||||||
|
vs. just a relative filename.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example 1: create a watcher to see when a file is created
|
||||||
|
var watcher = fs.watch('/myfile', function(event, filename) {
|
||||||
|
// event could be 'change' or 'rename' and filename will be '/myfile'
|
||||||
|
// Stop watching for changes
|
||||||
|
watcher.close();
|
||||||
|
});
|
||||||
|
fs.writeFile('/myfile', 'data');
|
||||||
|
|
||||||
|
// Example 2: add the listener via watcher.on()
|
||||||
|
var watcher = fs.watch('/myfile2');
|
||||||
|
watcher.on('change', function(event, filename) {
|
||||||
|
// event will be 'change' and filename will be '/myfile2'
|
||||||
|
// Stop watching for changes
|
||||||
|
watcher.close();
|
||||||
|
});
|
||||||
|
fs.writeFile('/myfile2', 'data2');
|
||||||
|
|
||||||
|
// Example 3: recursive watch on /data dir
|
||||||
|
var watcher = fs.watch('/data', { recursive: true }, function(event, filename) {
|
||||||
|
// event could be 'change' or 'rename' and filename will be '/data/subdir/file'
|
||||||
|
// Stop watching for changes
|
||||||
|
watcher.close();
|
||||||
|
});
|
||||||
|
fs.writeFile('/data/subdir/file', 'data');
|
||||||
|
```
|
||||||
|
|
||||||
### FileSystemShell<a name="FileSystemShell"></a>
|
### FileSystemShell<a name="FileSystemShell"></a>
|
||||||
|
|
||||||
Many common file system shell operations are available by using a `FileSystemShell` object.
|
Many common file system shell operations are available by using a `FileSystemShell` object.
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
"name": "filer",
|
"name": "filer",
|
||||||
"version": "0.0.4",
|
"version": "0.0.4",
|
||||||
"main": "dist/filer.js",
|
"main": "dist/filer.js",
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter2": "~0.4.13"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "1.17.1",
|
"mocha": "1.17.1",
|
||||||
"chai": "1.9.0"
|
"chai": "1.9.0"
|
||||||
|
|
|
@ -26,6 +26,8 @@ module.exports = function(grunt) {
|
||||||
'src/index.js',
|
'src/index.js',
|
||||||
'src/shared.js',
|
'src/shared.js',
|
||||||
'src/shell.js',
|
'src/shell.js',
|
||||||
|
'src/fswatcher.js',
|
||||||
|
'src/environment.js',
|
||||||
'src/providers/**/*.js',
|
'src/providers/**/*.js',
|
||||||
'src/adapters/**/*.js'
|
'src/adapters/**/*.js'
|
||||||
]
|
]
|
||||||
|
@ -45,7 +47,8 @@ module.exports = function(grunt) {
|
||||||
options: {
|
options: {
|
||||||
paths: {
|
paths: {
|
||||||
"src": "../src",
|
"src": "../src",
|
||||||
"build": "../build"
|
"build": "../build",
|
||||||
|
"EventEmitter": "../bower_components/eventemitter2/lib/eventemitter2"
|
||||||
},
|
},
|
||||||
baseUrl: "lib",
|
baseUrl: "lib",
|
||||||
name: "build/almond",
|
name: "build/almond",
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
define(function(require) {
|
||||||
|
|
||||||
|
// Based on https://github.com/diy/intercom.js/blob/master/lib/intercom.js
|
||||||
|
// Copyright 2012 DIY Co Apache License, Version 2.0
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
var EventEmitter = require('EventEmitter');
|
||||||
|
var guid = require('src/shared').guid;
|
||||||
|
|
||||||
|
function throttle(delay, fn) {
|
||||||
|
var last = 0;
|
||||||
|
return function() {
|
||||||
|
var now = Date.now();
|
||||||
|
if (now - last > delay) {
|
||||||
|
last = now;
|
||||||
|
fn.apply(this, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extend(a, b) {
|
||||||
|
if (typeof a === 'undefined' || !a) { a = {}; }
|
||||||
|
if (typeof b === 'object') {
|
||||||
|
for (var key in b) {
|
||||||
|
if (b.hasOwnProperty(key)) {
|
||||||
|
a[key] = b[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localStorage = (function(window) {
|
||||||
|
if (typeof window.localStorage === 'undefined') {
|
||||||
|
return {
|
||||||
|
getItem : function() {},
|
||||||
|
setItem : function() {},
|
||||||
|
removeItem : function() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return window.localStorage;
|
||||||
|
}(this));
|
||||||
|
|
||||||
|
function Intercom() {
|
||||||
|
var self = this;
|
||||||
|
var now = Date.now();
|
||||||
|
|
||||||
|
this.origin = guid();
|
||||||
|
this.lastMessage = now;
|
||||||
|
this.receivedIDs = {};
|
||||||
|
this.previousValues = {};
|
||||||
|
|
||||||
|
var storageHandler = function() {
|
||||||
|
self._onStorageEvent.apply(self, arguments);
|
||||||
|
};
|
||||||
|
if (document.attachEvent) {
|
||||||
|
document.attachEvent('onstorage', storageHandler);
|
||||||
|
} else {
|
||||||
|
window.addEventListener('storage', storageHandler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Intercom.prototype._transaction = function(fn) {
|
||||||
|
var TIMEOUT = 1000;
|
||||||
|
var WAIT = 20;
|
||||||
|
var self = this;
|
||||||
|
var executed = false;
|
||||||
|
var listening = false;
|
||||||
|
var waitTimer = null;
|
||||||
|
|
||||||
|
function lock() {
|
||||||
|
if (executed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = Date.now();
|
||||||
|
var activeLock = localStorage.getItem(INDEX_LOCK)|0;
|
||||||
|
if (activeLock && now - activeLock < TIMEOUT) {
|
||||||
|
if (!listening) {
|
||||||
|
self._on('storage', lock);
|
||||||
|
listening = true;
|
||||||
|
}
|
||||||
|
waitTimer = window.setTimeout(lock, WAIT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
executed = true;
|
||||||
|
localStorage.setItem(INDEX_LOCK, now);
|
||||||
|
|
||||||
|
fn();
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unlock() {
|
||||||
|
if (listening) {
|
||||||
|
self._off('storage', lock);
|
||||||
|
}
|
||||||
|
if (waitTimer) {
|
||||||
|
window.clearTimeout(waitTimer);
|
||||||
|
}
|
||||||
|
localStorage.removeItem(INDEX_LOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock();
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype._cleanup_emit = throttle(100, function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self._transaction(function() {
|
||||||
|
var now = Date.now();
|
||||||
|
var threshold = now - THRESHOLD_TTL_EMIT;
|
||||||
|
var changed = 0;
|
||||||
|
var messages;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messages = JSON.parse(localStorage.getItem(INDEX_EMIT) || '[]');
|
||||||
|
} catch(e) {
|
||||||
|
messages = [];
|
||||||
|
}
|
||||||
|
for (var i = messages.length - 1; i >= 0; i--) {
|
||||||
|
if (messages[i].timestamp < threshold) {
|
||||||
|
messages.splice(i, 1);
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed > 0) {
|
||||||
|
localStorage.setItem(INDEX_EMIT, JSON.stringify(messages));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Intercom.prototype._cleanup_once = throttle(100, function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self._transaction(function() {
|
||||||
|
var timestamp, ttl, key;
|
||||||
|
var table;
|
||||||
|
var now = Date.now();
|
||||||
|
var changed = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
table = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}');
|
||||||
|
} catch(e) {
|
||||||
|
table = {};
|
||||||
|
}
|
||||||
|
for (key in table) {
|
||||||
|
if (self._once_expired(key, table)) {
|
||||||
|
delete table[key];
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed > 0) {
|
||||||
|
localStorage.setItem(INDEX_ONCE, JSON.stringify(table));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Intercom.prototype._once_expired = function(key, table) {
|
||||||
|
if (!table) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!table.hasOwnProperty(key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (typeof table[key] !== 'object') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ttl = table[key].ttl || THRESHOLD_TTL_ONCE;
|
||||||
|
var now = Date.now();
|
||||||
|
var timestamp = table[key].timestamp;
|
||||||
|
return timestamp < now - ttl;
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype._localStorageChanged = function(event, field) {
|
||||||
|
if (event && event.key) {
|
||||||
|
return event.key === field;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentValue = localStorage.getItem(field);
|
||||||
|
if (currentValue === this.previousValues[field]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.previousValues[field] = currentValue;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype._onStorageEvent = function(event) {
|
||||||
|
event = event || window.event;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (this._localStorageChanged(event, INDEX_EMIT)) {
|
||||||
|
this._transaction(function() {
|
||||||
|
var now = Date.now();
|
||||||
|
var data = localStorage.getItem(INDEX_EMIT);
|
||||||
|
var messages;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messages = JSON.parse(data || '[]');
|
||||||
|
} catch(e) {
|
||||||
|
messages = [];
|
||||||
|
}
|
||||||
|
for (var i = 0; i < messages.length; i++) {
|
||||||
|
if (messages[i].origin === self.origin) continue;
|
||||||
|
if (messages[i].timestamp < self.lastMessage) continue;
|
||||||
|
if (messages[i].id) {
|
||||||
|
if (self.receivedIDs.hasOwnProperty(messages[i].id)) continue;
|
||||||
|
self.receivedIDs[messages[i].id] = true;
|
||||||
|
}
|
||||||
|
self.trigger(messages[i].name, messages[i].payload);
|
||||||
|
}
|
||||||
|
self.lastMessage = now;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._trigger('storage', event);
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype._emit = function(name, message, id) {
|
||||||
|
id = (typeof id === 'string' || typeof id === 'number') ? String(id) : null;
|
||||||
|
if (id && id.length) {
|
||||||
|
if (this.receivedIDs.hasOwnProperty(id)) return;
|
||||||
|
this.receivedIDs[id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var packet = {
|
||||||
|
id : id,
|
||||||
|
name : name,
|
||||||
|
origin : this.origin,
|
||||||
|
timestamp : Date.now(),
|
||||||
|
payload : message
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this._transaction(function() {
|
||||||
|
var data = localStorage.getItem(INDEX_EMIT) || '[]';
|
||||||
|
var delimiter = (data === '[]') ? '' : ',';
|
||||||
|
data = [data.substring(0, data.length - 1), delimiter, JSON.stringify(packet), ']'].join('');
|
||||||
|
localStorage.setItem(INDEX_EMIT, data);
|
||||||
|
self.trigger(name, message);
|
||||||
|
|
||||||
|
window.setTimeout(function() {
|
||||||
|
self._cleanup_emit();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype.emit = function(name, message) {
|
||||||
|
this._emit.apply(this, arguments);
|
||||||
|
this._trigger('emit', name, message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.prototype.once = function(key, fn, ttl) {
|
||||||
|
if (!Intercom.supported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this._transaction(function() {
|
||||||
|
var data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}');
|
||||||
|
} catch(e) {
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
if (!self._once_expired(key, data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[key] = {};
|
||||||
|
data[key].timestamp = Date.now();
|
||||||
|
if (typeof ttl === 'number') {
|
||||||
|
data[key].ttl = ttl * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem(INDEX_ONCE, JSON.stringify(data));
|
||||||
|
fn();
|
||||||
|
|
||||||
|
window.setTimeout(function() {
|
||||||
|
self._cleanup_once();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
extend(Intercom.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
|
Intercom.supported = (typeof localStorage !== 'undefined');
|
||||||
|
|
||||||
|
var INDEX_EMIT = 'intercom';
|
||||||
|
var INDEX_ONCE = 'intercom_once';
|
||||||
|
var INDEX_LOCK = 'intercom_lock';
|
||||||
|
|
||||||
|
var THRESHOLD_TTL_EMIT = 50000;
|
||||||
|
var THRESHOLD_TTL_ONCE = 1000 * 3600;
|
||||||
|
|
||||||
|
Intercom.destroy = function() {
|
||||||
|
localStorage.removeItem(INDEX_LOCK);
|
||||||
|
localStorage.removeItem(INDEX_EMIT);
|
||||||
|
localStorage.removeItem(INDEX_ONCE);
|
||||||
|
};
|
||||||
|
|
||||||
|
Intercom.getInstance = (function() {
|
||||||
|
var intercom;
|
||||||
|
return function() {
|
||||||
|
if (!intercom) {
|
||||||
|
intercom = new Intercom();
|
||||||
|
}
|
||||||
|
return intercom;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
return Intercom;
|
||||||
|
});
|
|
@ -15,8 +15,10 @@
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/js-platform/filer.git"
|
"url": "https://github.com/js-platform/filer.git"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bower": "~1.0.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bower": "~1.0.0",
|
|
||||||
"grunt": "~0.4.0",
|
"grunt": "~0.4.0",
|
||||||
"grunt-contrib-clean": "~0.4.0",
|
"grunt-contrib-clean": "~0.4.0",
|
||||||
"grunt-contrib-requirejs": "~0.4.0",
|
"grunt-contrib-requirejs": "~0.4.0",
|
||||||
|
|
333
src/fs.js
333
src/fs.js
|
@ -58,6 +58,8 @@ define(function(require) {
|
||||||
var providers = require('src/providers/providers');
|
var providers = require('src/providers/providers');
|
||||||
var adapters = require('src/adapters/adapters');
|
var adapters = require('src/adapters/adapters');
|
||||||
var Shell = require('src/shell');
|
var Shell = require('src/shell');
|
||||||
|
var Intercom = require('intercom');
|
||||||
|
var FSWatcher = require('src/fswatcher');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DirectoryEntry
|
* DirectoryEntry
|
||||||
|
@ -192,10 +194,17 @@ define(function(require) {
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function complete(error) {
|
||||||
|
// Queue this change so we can send watch events.
|
||||||
|
// Unlike node.js, we send the full path vs. basename/dirname only.
|
||||||
|
context.changes.push({ event: 'change', path: path });
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
|
||||||
if(update) {
|
if(update) {
|
||||||
context.put(node.id, node, callback);
|
context.put(node.id, node, complete);
|
||||||
} else {
|
} else {
|
||||||
callback();
|
complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1649,21 +1658,66 @@ define(function(require) {
|
||||||
queue = null;
|
queue = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We support the optional `options` arg from node, but ignore it
|
||||||
|
this.watch = function(filename, options, listener) {
|
||||||
|
if(isNullPath(filename)) {
|
||||||
|
throw new Error('Path must be a string without null bytes.');
|
||||||
|
}
|
||||||
|
if(typeof options === 'function') {
|
||||||
|
listener = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
listener = listener || nop;
|
||||||
|
|
||||||
|
var watcher = new FSWatcher();
|
||||||
|
watcher.start(filename, false, options.recursive);
|
||||||
|
watcher.on('change', listener);
|
||||||
|
|
||||||
|
return watcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Let other instances (in this or other windows) know about
|
||||||
|
// any changes to this fs instance.
|
||||||
|
function broadcastChanges(changes) {
|
||||||
|
if(!changes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var intercom = Intercom.getInstance();
|
||||||
|
changes.forEach(function(change) {
|
||||||
|
intercom.emit(change.event, change.event, change.path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Open file system storage provider
|
// Open file system storage provider
|
||||||
provider.open(function(err, needsFormatting) {
|
provider.open(function(err, needsFormatting) {
|
||||||
function complete(error) {
|
function complete(error) {
|
||||||
// Wrap the provider so we can extend the context with fs flags.
|
|
||||||
// From this point forward we won't call open again, so drop it.
|
function wrappedContext(methodName) {
|
||||||
|
var context = provider[methodName]();
|
||||||
|
context.flags = flags;
|
||||||
|
context.changes = [];
|
||||||
|
|
||||||
|
// When the context is finished, let the fs deal with any change events
|
||||||
|
context.close = function() {
|
||||||
|
var changes = context.changes;
|
||||||
|
broadcastChanges(changes);
|
||||||
|
changes.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the provider so we can extend the context with fs flags and
|
||||||
|
// an array of changes (e.g., watch event 'change' and 'rename' events
|
||||||
|
// for paths updated during the lifetime of the context). From this
|
||||||
|
// point forward we won't call open again, so it's safe to drop it.
|
||||||
fs.provider = {
|
fs.provider = {
|
||||||
getReadWriteContext: function() {
|
openReadWriteContext: function() {
|
||||||
var context = provider.getReadWriteContext();
|
return wrappedContext('getReadWriteContext');
|
||||||
context.flags = flags;
|
|
||||||
return context;
|
|
||||||
},
|
},
|
||||||
getReadOnlyContext: function() {
|
openReadOnlyContext: function() {
|
||||||
var context = provider.getReadOnlyContext();
|
return wrappedContext('getReadOnlyContext');
|
||||||
context.flags = flags;
|
|
||||||
return context;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2334,14 +2388,30 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_open(fs, context, path, flags, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_open(fs, context, path, flags, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
};
|
};
|
||||||
FileSystem.prototype.close = function(fd, callback) {
|
FileSystem.prototype.close = function(fd, callback) {
|
||||||
_close(this, fd, maybeCallback(callback));
|
callback = maybeCallback(callback);
|
||||||
|
var fs = this;
|
||||||
|
var error = fs.queueOrRun(
|
||||||
|
function() {
|
||||||
|
var context = fs.provider.openReadWriteContext();
|
||||||
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_close(fs, fd, complete);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if(error) callback(error);
|
||||||
};
|
};
|
||||||
FileSystem.prototype.mkdir = function(path, mode, callback) {
|
FileSystem.prototype.mkdir = function(path, mode, callback) {
|
||||||
// Support passing a mode arg, but we ignore it internally for now.
|
// Support passing a mode arg, but we ignore it internally for now.
|
||||||
|
@ -2352,8 +2422,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_mkdir(context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_mkdir(context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2363,8 +2437,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_rmdir(context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_rmdir(context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2374,8 +2452,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_stat(context, fs.name, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_stat(context, fs.name, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2385,8 +2467,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_fstat(fs, context, fd, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_fstat(fs, context, fd, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2396,8 +2482,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_link(context, oldpath, newpath, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_link(context, oldpath, newpath, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2407,8 +2497,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_unlink(context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_unlink(context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2423,8 +2517,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_read(fs, context, fd, buffer, offset, length, position, wrapper);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
wrapper.apply(this, arguments);
|
||||||
|
}
|
||||||
|
_read(fs, context, fd, buffer, offset, length, position, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2434,8 +2532,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_readFile(fs, context, path, options, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_readFile(fs, context, path, options, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2445,11 +2547,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_write(fs, context, fd, buffer, offset, length, position, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_write(fs, context, fd, buffer, offset, length, position, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
};
|
};
|
||||||
FileSystem.prototype.writeFile = function(path, data, options, callback_) {
|
FileSystem.prototype.writeFile = function(path, data, options, callback_) {
|
||||||
|
@ -2457,8 +2562,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_writeFile(fs, context, path, data, options, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_writeFile(fs, context, path, data, options, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2468,8 +2577,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_appendFile(fs, context, path, data, options, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_appendFile(fs, context, path, data, options, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2479,8 +2592,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_exists(context, fs.name, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_exists(context, fs.name, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2490,8 +2607,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_lseek(fs, context, fd, offset, whence, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_lseek(fs, context, fd, offset, whence, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2501,8 +2622,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_readdir(context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_readdir(context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2512,8 +2637,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_rename(context, oldpath, newpath, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_rename(context, oldpath, newpath, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2523,8 +2652,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_readlink(context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_readlink(context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2535,8 +2668,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_symlink(context, srcpath, dstpath, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_symlink(context, srcpath, dstpath, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2546,8 +2683,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_lstat(fs, context, path, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_lstat(fs, context, path, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2563,8 +2704,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_truncate(context, path, length, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_truncate(context, path, length, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2574,8 +2719,12 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function() {
|
function() {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_ftruncate(fs, context, fd, length, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_ftruncate(fs, context, fd, length, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
|
@ -2585,11 +2734,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_utimes(context, path, atime, mtime, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_utimes(context, path, atime, mtime, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2599,11 +2751,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_futimes(fs, context, fd, atime, mtime, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_futimes(fs, context, fd, atime, mtime, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2614,11 +2769,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_setxattr(context, path, name, value, _flag, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_setxattr(context, path, name, value, _flag, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2628,11 +2786,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_getxattr(context, path, name, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_getxattr(context, path, name, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2643,11 +2804,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_fsetxattr(fs, context, fd, name, value, _flag, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_fsetxattr(fs, context, fd, name, value, _flag, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2657,11 +2821,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_fgetxattr(fs, context, fd, name, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_fgetxattr(fs, context, fd, name, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2671,11 +2838,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_removexattr(context, path, name, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_removexattr(context, path, name, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
@ -2685,11 +2855,14 @@ define(function(require) {
|
||||||
var fs = this;
|
var fs = this;
|
||||||
var error = fs.queueOrRun(
|
var error = fs.queueOrRun(
|
||||||
function () {
|
function () {
|
||||||
var context = fs.provider.getReadWriteContext();
|
var context = fs.provider.openReadWriteContext();
|
||||||
_fremovexattr(fs, context, fd, name, callback);
|
function complete() {
|
||||||
|
context.close();
|
||||||
|
callback.apply(fs, arguments);
|
||||||
|
}
|
||||||
|
_fremovexattr(fs, context, fd, name, complete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
define(function(require) {
|
||||||
|
|
||||||
|
var EventEmitter = require('EventEmitter');
|
||||||
|
var isNullPath = require('src/path').isNull;
|
||||||
|
var Intercom = require('intercom');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FSWatcher based on node.js' FSWatcher
|
||||||
|
* see https://github.com/joyent/node/blob/master/lib/fs.js
|
||||||
|
*/
|
||||||
|
function FSWatcher() {
|
||||||
|
EventEmitter.call(this);
|
||||||
|
var self = this;
|
||||||
|
var recursive = false;
|
||||||
|
var filename;
|
||||||
|
|
||||||
|
function onchange(event, path) {
|
||||||
|
// Watch for exact filename, or parent path when recursive is true
|
||||||
|
if(filename === path || (recursive && path.indexOf(filename + '/') === 0)) {
|
||||||
|
self.emit('change', 'change', path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We support, but ignore the second arg, which node.js uses.
|
||||||
|
self.start = function(filename_, persistent_, recursive_) {
|
||||||
|
// Bail if we've already started (and therefore have a filename);
|
||||||
|
if(filename) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isNullPath(filename_)) {
|
||||||
|
throw new Error('Path must be a string without null bytes.');
|
||||||
|
}
|
||||||
|
// TODO: get realpath for symlinks on filename...
|
||||||
|
filename = filename_;
|
||||||
|
|
||||||
|
// Whether to watch beneath this path or not
|
||||||
|
recursive = recursive_ === true;
|
||||||
|
|
||||||
|
var intercom = Intercom.getInstance();
|
||||||
|
intercom.on('change', onchange);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.close = function() {
|
||||||
|
var intercom = Intercom.getInstance();
|
||||||
|
intercom.off('change', onchange);
|
||||||
|
self.removeAllListeners('change');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
FSWatcher.prototype = new EventEmitter();
|
||||||
|
FSWatcher.prototype.constructor = FSWatcher;
|
||||||
|
|
||||||
|
return FSWatcher;
|
||||||
|
});
|
|
@ -58,7 +58,8 @@ var config = (function() {
|
||||||
"spec": "../tests/spec",
|
"spec": "../tests/spec",
|
||||||
"bugs": "../tests/bugs",
|
"bugs": "../tests/bugs",
|
||||||
"util": "../tests/lib/test-utils",
|
"util": "../tests/lib/test-utils",
|
||||||
"Filer": "../src/index"
|
"Filer": "../src/index",
|
||||||
|
"EventEmitter": "../bower_components/eventemitter2/lib/eventemitter2"
|
||||||
},
|
},
|
||||||
baseUrl: "../lib",
|
baseUrl: "../lib",
|
||||||
optimize: "none",
|
optimize: "none",
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
describe('fs.watch', function() {
|
||||||
|
beforeEach(util.setup);
|
||||||
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
|
it('should be a function', function() {
|
||||||
|
var fs = util.fs();
|
||||||
|
expect(typeof fs.watch).to.equal('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a change event when writing a file', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
var watcher = fs.watch('/myfile', function(event, filename) {
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
expect(filename).to.equal('/myfile');
|
||||||
|
watcher.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile('/myfile', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a change event when writing a file in a dir with recursive=true', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
var watcher = fs.watch('/', { recursive: true }, function(event, filename) {
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
expect(filename).to.equal('/');
|
||||||
|
watcher.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile('/myfile', 'data', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: unlike node.js, which either doesn't give filenames (e.g., in case of
|
||||||
|
* fd vs. path) for events, or gives only a portion thereof (e.g., basname),
|
||||||
|
* we give full, abs paths always.
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe("node.js tests: https://github.com/joyent/node/blob/master/test/simple/test-fs-watch-recursive.js", function() {
|
||||||
|
|
||||||
|
beforeEach(util.setup);
|
||||||
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
|
it('should get change event for writeFile() under a recursive watched dir', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
|
||||||
|
fs.mkdir('/test', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
fs.mkdir('/test/subdir', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
var watcher = fs.watch('/test', {recursive: true});
|
||||||
|
watcher.on('change', function(event, filename) {
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
// Expect to see that a new file was created in /test/subdir
|
||||||
|
expect(filename).to.equal('/test/subdir');
|
||||||
|
watcher.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile('/test/subdir/watch.txt', 'world');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,74 @@
|
||||||
|
define(["Filer", "util"], function(Filer, util) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: unlike node.js, which either doesn't give filenames (e.g., in case of
|
||||||
|
* fd vs. path) for events, or gives only a portion thereof (e.g., basname),
|
||||||
|
* we give full, abs paths always.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var filenameOne = '/watch.txt';
|
||||||
|
var filenameTwo = '/hasOwnProperty';
|
||||||
|
|
||||||
|
describe("node.js tests: https://github.com/joyent/node/blob/master/test/simple/test-fs-watch.js", function() {
|
||||||
|
|
||||||
|
beforeEach(util.setup);
|
||||||
|
afterEach(util.cleanup);
|
||||||
|
|
||||||
|
it('should get change event for writeFile() using FSWatcher object', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var changes = 0;
|
||||||
|
|
||||||
|
var watcher = fs.watch(filenameOne);
|
||||||
|
watcher.on('change', function(event, filename) {
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
expect(filename).to.equal(filenameOne);
|
||||||
|
|
||||||
|
// Make sure only one change event comes in (i.e., close() works)
|
||||||
|
changes++;
|
||||||
|
watcher.close();
|
||||||
|
|
||||||
|
fs.writeFile(filenameOne, 'hello again', function(error) {
|
||||||
|
expect(changes).to.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile(filenameOne, 'hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get change event for writeFile() using fs.watch() only', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
var changes = 0;
|
||||||
|
|
||||||
|
var watcher = fs.watch(filenameTwo, function(event, filename) {
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
expect(filename).to.equal(filenameTwo);
|
||||||
|
|
||||||
|
watcher.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile(filenameTwo, 'pardner');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow watches on dirs', function(done) {
|
||||||
|
var fs = util.fs();
|
||||||
|
fs.mkdir('/tmp', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
var watcher = fs.watch('/tmp', function(event, filename) {
|
||||||
|
// TODO: node thinks this should be 'rename', need to add rename along with change.
|
||||||
|
expect(event).to.equal('change');
|
||||||
|
expect(filename).to.equal('/tmp');
|
||||||
|
watcher.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.open('/tmp/newfile.txt', 'w', function(error, fd) {
|
||||||
|
if(error) throw error;
|
||||||
|
fs.close(fd);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -35,6 +35,7 @@ define([
|
||||||
"spec/path-resolution.spec",
|
"spec/path-resolution.spec",
|
||||||
"spec/times.spec",
|
"spec/times.spec",
|
||||||
"spec/time-flags.spec",
|
"spec/time-flags.spec",
|
||||||
|
"spec/fs.watch.spec",
|
||||||
|
|
||||||
// Filer.FileSystem.providers.*
|
// Filer.FileSystem.providers.*
|
||||||
"spec/providers/providers.spec",
|
"spec/providers/providers.spec",
|
||||||
|
@ -58,6 +59,8 @@ define([
|
||||||
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||||
"spec/node-js/simple/test-fs-mkdir",
|
"spec/node-js/simple/test-fs-mkdir",
|
||||||
"spec/node-js/simple/test-fs-null-bytes",
|
"spec/node-js/simple/test-fs-null-bytes",
|
||||||
|
"spec/node-js/simple/test-fs-watch",
|
||||||
|
"spec/node-js/simple/test-fs-watch-recursive",
|
||||||
|
|
||||||
// Regressions, Bugs
|
// Regressions, Bugs
|
||||||
"bugs/issue105",
|
"bugs/issue105",
|
||||||
|
|
Loading…
Reference in New Issue