fs: make fs.watchFile() work on windows
This commit is contained in:
parent
d98a8578d6
commit
f0ce98441f
12
lib/fs.js
12
lib/fs.js
@ -876,7 +876,13 @@ function StatWatcher() {
|
|||||||
var self = this;
|
var self = this;
|
||||||
this._handle = new binding.StatWatcher();
|
this._handle = new binding.StatWatcher();
|
||||||
|
|
||||||
this._handle.onchange = function(current, previous) {
|
// uv_fs_poll is a little more powerful than ev_stat but we curb it for
|
||||||
|
// the sake of backwards compatibility
|
||||||
|
var oldStatus = -1;
|
||||||
|
|
||||||
|
this._handle.onchange = function(current, previous, newStatus) {
|
||||||
|
if (oldStatus == -1 && newStatus == -1) return;
|
||||||
|
oldStatus = newStatus;
|
||||||
self.emit('change', current, previous);
|
self.emit('change', current, previous);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -905,10 +911,6 @@ function inStatWatchers(filename) {
|
|||||||
|
|
||||||
|
|
||||||
fs.watchFile = function(filename) {
|
fs.watchFile = function(filename) {
|
||||||
if (isWindows) {
|
|
||||||
throw new Error('use fs.watch api instead');
|
|
||||||
}
|
|
||||||
|
|
||||||
var stat;
|
var stat;
|
||||||
var options;
|
var options;
|
||||||
var listener;
|
var listener;
|
||||||
|
2
node.gyp
2
node.gyp
@ -82,6 +82,7 @@
|
|||||||
'src/node_main.cc',
|
'src/node_main.cc',
|
||||||
'src/node_os.cc',
|
'src/node_os.cc',
|
||||||
'src/node_script.cc',
|
'src/node_script.cc',
|
||||||
|
'src/node_stat_watcher.cc',
|
||||||
'src/node_string.cc',
|
'src/node_string.cc',
|
||||||
'src/node_zlib.cc',
|
'src/node_zlib.cc',
|
||||||
'src/pipe_wrap.cc',
|
'src/pipe_wrap.cc',
|
||||||
@ -208,7 +209,6 @@
|
|||||||
'defines': [ '__POSIX__' ],
|
'defines': [ '__POSIX__' ],
|
||||||
'sources': [
|
'sources': [
|
||||||
'src/node_signal_watcher.cc',
|
'src/node_signal_watcher.cc',
|
||||||
'src/node_stat_watcher.cc',
|
|
||||||
'src/node_io_watcher.cc',
|
'src/node_io_watcher.cc',
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
|
@ -69,7 +69,6 @@ typedef int mode_t;
|
|||||||
#include "node_http_parser.h"
|
#include "node_http_parser.h"
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
# include "node_signal_watcher.h"
|
# include "node_signal_watcher.h"
|
||||||
# include "node_stat_watcher.h"
|
|
||||||
#endif
|
#endif
|
||||||
#include "node_constants.h"
|
#include "node_constants.h"
|
||||||
#include "node_javascript.h"
|
#include "node_javascript.h"
|
||||||
|
@ -22,9 +22,7 @@
|
|||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "node_file.h"
|
#include "node_file.h"
|
||||||
#include "node_buffer.h"
|
#include "node_buffer.h"
|
||||||
#ifdef __POSIX__
|
#include "node_stat_watcher.h"
|
||||||
# include "node_stat_watcher.h"
|
|
||||||
#endif
|
|
||||||
#include "req_wrap.h"
|
#include "req_wrap.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -984,9 +982,7 @@ void InitFs(Handle<Object> target) {
|
|||||||
|
|
||||||
oncomplete_sym = NODE_PSYMBOL("oncomplete");
|
oncomplete_sym = NODE_PSYMBOL("oncomplete");
|
||||||
|
|
||||||
#ifdef __POSIX__
|
|
||||||
StatWatcher::Initialize(target);
|
StatWatcher::Initialize(target);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace node
|
} // end namespace node
|
||||||
|
@ -25,6 +25,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Poll interval in milliseconds. 5007 is what libev used to use. It's a little
|
||||||
|
// on the slow side but let's stick with it for now, keep behavioral changes to
|
||||||
|
// a minimum.
|
||||||
|
#define DEFAULT_POLL_INTERVAL 5007
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
@ -33,6 +38,7 @@ Persistent<FunctionTemplate> StatWatcher::constructor_template;
|
|||||||
static Persistent<String> onchange_sym;
|
static Persistent<String> onchange_sym;
|
||||||
static Persistent<String> onstop_sym;
|
static Persistent<String> onstop_sym;
|
||||||
|
|
||||||
|
|
||||||
void StatWatcher::Initialize(Handle<Object> target) {
|
void StatWatcher::Initialize(Handle<Object> target) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
@ -48,18 +54,24 @@ void StatWatcher::Initialize(Handle<Object> target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatWatcher::Callback(EV_P_ ev_stat *watcher, int revents) {
|
void StatWatcher::Callback(uv_fs_poll_t* handle,
|
||||||
assert(revents == EV_STAT);
|
int status,
|
||||||
StatWatcher *handler = static_cast<StatWatcher*>(watcher->data);
|
const uv_statbuf_t* prev,
|
||||||
assert(watcher == &handler->watcher_);
|
const uv_statbuf_t* curr) {
|
||||||
|
StatWatcher* wrap = container_of(handle, StatWatcher, watcher_);
|
||||||
|
assert(handle == &wrap->watcher_);
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
Local<Value> argv[2];
|
Local<Value> argv[3];
|
||||||
argv[0] = BuildStatsObject(&watcher->attr);
|
argv[0] = BuildStatsObject(curr);
|
||||||
argv[1] = BuildStatsObject(&watcher->prev);
|
argv[1] = BuildStatsObject(prev);
|
||||||
|
argv[2] = Integer::New(status);
|
||||||
|
if (status == -1) {
|
||||||
|
SetErrno(uv_last_error(wrap->watcher_.loop));
|
||||||
|
}
|
||||||
if (onchange_sym.IsEmpty()) {
|
if (onchange_sym.IsEmpty()) {
|
||||||
onchange_sym = NODE_PSYMBOL("onchange");
|
onchange_sym = NODE_PSYMBOL("onchange");
|
||||||
}
|
}
|
||||||
MakeCallback(handler->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
|
MakeCallback(wrap->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +81,7 @@ Handle<Value> StatWatcher::New(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
StatWatcher *s = new StatWatcher();
|
StatWatcher* s = new StatWatcher();
|
||||||
s->Wrap(args.Holder());
|
s->Wrap(args.Holder());
|
||||||
return args.This();
|
return args.This();
|
||||||
}
|
}
|
||||||
@ -82,27 +94,23 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
|
|||||||
return ThrowException(Exception::TypeError(String::New("Bad arguments")));
|
return ThrowException(Exception::TypeError(String::New("Bad arguments")));
|
||||||
}
|
}
|
||||||
|
|
||||||
StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
|
StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
|
||||||
String::Utf8Value path(args[0]);
|
String::Utf8Value path(args[0]);
|
||||||
|
|
||||||
assert(handler->path_ == NULL);
|
uint32_t interval = DEFAULT_POLL_INTERVAL;
|
||||||
handler->path_ = strdup(*path);
|
if (args[2]->IsUint32()) {
|
||||||
|
interval = args[2]->Uint32Value();
|
||||||
ev_tstamp interval = 0.;
|
|
||||||
if (args[2]->IsInt32()) {
|
|
||||||
interval = NODE_V8_UNIXTIME(args[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ev_stat_set(&handler->watcher_, handler->path_, interval);
|
uv_fs_poll_start(&wrap->watcher_, Callback, *path, interval);
|
||||||
ev_stat_start(EV_DEFAULT_UC_ &handler->watcher_);
|
|
||||||
|
|
||||||
handler->persistent_ = args[1]->IsTrue();
|
wrap->persistent_ = args[1]->IsTrue();
|
||||||
|
|
||||||
if (!handler->persistent_) {
|
if (!wrap->persistent_) {
|
||||||
ev_unref(EV_DEFAULT_UC);
|
uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->watcher_));
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->Ref();
|
wrap->Ref();
|
||||||
|
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
@ -110,24 +118,20 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
|
|||||||
|
|
||||||
Handle<Value> StatWatcher::Stop(const Arguments& args) {
|
Handle<Value> StatWatcher::Stop(const Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
|
StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
|
||||||
if (onstop_sym.IsEmpty()) {
|
if (onstop_sym.IsEmpty()) {
|
||||||
onstop_sym = NODE_PSYMBOL("onstop");
|
onstop_sym = NODE_PSYMBOL("onstop");
|
||||||
}
|
}
|
||||||
MakeCallback(handler->handle_, onstop_sym, 0, NULL);
|
MakeCallback(wrap->handle_, onstop_sym, 0, NULL);
|
||||||
handler->Stop();
|
wrap->Stop();
|
||||||
return Undefined();
|
return Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StatWatcher::Stop () {
|
void StatWatcher::Stop () {
|
||||||
if (watcher_.active) {
|
if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&watcher_))) return;
|
||||||
if (!persistent_) ev_ref(EV_DEFAULT_UC);
|
uv_fs_poll_stop(&watcher_);
|
||||||
ev_stat_stop(EV_DEFAULT_UC_ &watcher_);
|
Unref();
|
||||||
free(path_);
|
|
||||||
path_ = NULL;
|
|
||||||
Unref();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#define NODE_STAT_WATCHER_H_
|
#define NODE_STAT_WATCHER_H_
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "uv-private/ev.h"
|
#include "uv.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
@ -36,14 +36,11 @@ class StatWatcher : ObjectWrap {
|
|||||||
|
|
||||||
StatWatcher() : ObjectWrap() {
|
StatWatcher() : ObjectWrap() {
|
||||||
persistent_ = false;
|
persistent_ = false;
|
||||||
path_ = NULL;
|
uv_fs_poll_init(uv_default_loop(), &watcher_);
|
||||||
ev_init(&watcher_, StatWatcher::Callback);
|
|
||||||
watcher_.data = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~StatWatcher() {
|
~StatWatcher() {
|
||||||
Stop();
|
Stop();
|
||||||
assert(path_ == NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
||||||
@ -51,13 +48,15 @@ class StatWatcher : ObjectWrap {
|
|||||||
static v8::Handle<v8::Value> Stop(const v8::Arguments& args);
|
static v8::Handle<v8::Value> Stop(const v8::Arguments& args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void Callback(EV_P_ ev_stat *watcher, int revents);
|
static void Callback(uv_fs_poll_t* handle,
|
||||||
|
int status,
|
||||||
|
const uv_statbuf_t* prev,
|
||||||
|
const uv_statbuf_t* curr);
|
||||||
|
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
ev_stat watcher_;
|
uv_fs_poll_t watcher_;
|
||||||
bool persistent_;
|
bool persistent_;
|
||||||
char *path_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -19,12 +19,6 @@
|
|||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
// fs.watchFile is not available on Windows
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
@ -19,11 +19,6 @@
|
|||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
// fs.watchFile is not available on Windows
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user