Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fs: make fs.watchFile() work on windows

  • Loading branch information...
commit f0ce98441ff7315e6a6c268dabcec58fc37da926 1 parent d98a857
Ben Noordhuis authored
12  lib/fs.js
@@ -876,7 +876,13 @@ function StatWatcher() {
876 876
   var self = this;
877 877
   this._handle = new binding.StatWatcher();
878 878
 
879  
-  this._handle.onchange = function(current, previous) {
  879
+  // uv_fs_poll is a little more powerful than ev_stat but we curb it for
  880
+  // the sake of backwards compatibility
  881
+  var oldStatus = -1;
  882
+
  883
+  this._handle.onchange = function(current, previous, newStatus) {
  884
+    if (oldStatus == -1 && newStatus == -1) return;
  885
+    oldStatus = newStatus;
880 886
     self.emit('change', current, previous);
881 887
   };
882 888
 
@@ -905,10 +911,6 @@ function inStatWatchers(filename) {
905 911
 
906 912
 
907 913
 fs.watchFile = function(filename) {
908  
-  if (isWindows) {
909  
-    throw new Error('use fs.watch api instead');
910  
-  }
911  
-
912 914
   var stat;
913 915
   var options;
914 916
   var listener;
2  node.gyp
@@ -82,6 +82,7 @@
82 82
         'src/node_main.cc',
83 83
         'src/node_os.cc',
84 84
         'src/node_script.cc',
  85
+        'src/node_stat_watcher.cc',
85 86
         'src/node_string.cc',
86 87
         'src/node_zlib.cc',
87 88
         'src/pipe_wrap.cc',
@@ -208,7 +209,6 @@
208 209
           'defines': [ '__POSIX__' ],
209 210
           'sources': [
210 211
             'src/node_signal_watcher.cc',
211  
-            'src/node_stat_watcher.cc',
212 212
             'src/node_io_watcher.cc',
213 213
           ]
214 214
         }],
1  src/node.cc
@@ -69,7 +69,6 @@ typedef int mode_t;
69 69
 #include "node_http_parser.h"
70 70
 #ifdef __POSIX__
71 71
 # include "node_signal_watcher.h"
72  
-# include "node_stat_watcher.h"
73 72
 #endif
74 73
 #include "node_constants.h"
75 74
 #include "node_javascript.h"
6  src/node_file.cc
@@ -22,9 +22,7 @@
22 22
 #include "node.h"
23 23
 #include "node_file.h"
24 24
 #include "node_buffer.h"
25  
-#ifdef __POSIX__
26  
-# include "node_stat_watcher.h"
27  
-#endif
  25
+#include "node_stat_watcher.h"
28 26
 #include "req_wrap.h"
29 27
 
30 28
 #include <fcntl.h>
@@ -984,9 +982,7 @@ void InitFs(Handle<Object> target) {
984 982
 
985 983
   oncomplete_sym = NODE_PSYMBOL("oncomplete");
986 984
 
987  
-#ifdef __POSIX__
988 985
   StatWatcher::Initialize(target);
989  
-#endif
990 986
 }
991 987
 
992 988
 }  // end namespace node
68  src/node_stat_watcher.cc
@@ -25,6 +25,11 @@
25 25
 #include <string.h>
26 26
 #include <stdlib.h>
27 27
 
  28
+// Poll interval in milliseconds. 5007 is what libev used to use. It's a little
  29
+// on the slow side but let's stick with it for now, keep behavioral changes to
  30
+// a minimum.
  31
+#define DEFAULT_POLL_INTERVAL 5007
  32
+
28 33
 namespace node {
29 34
 
30 35
 using namespace v8;
@@ -33,6 +38,7 @@ Persistent<FunctionTemplate> StatWatcher::constructor_template;
33 38
 static Persistent<String> onchange_sym;
34 39
 static Persistent<String> onstop_sym;
35 40
 
  41
+
36 42
 void StatWatcher::Initialize(Handle<Object> target) {
37 43
   HandleScope scope;
38 44
 
@@ -48,18 +54,24 @@ void StatWatcher::Initialize(Handle<Object> target) {
48 54
 }
49 55
 
50 56
 
51  
-void StatWatcher::Callback(EV_P_ ev_stat *watcher, int revents) {
52  
-  assert(revents == EV_STAT);
53  
-  StatWatcher *handler = static_cast<StatWatcher*>(watcher->data);
54  
-  assert(watcher == &handler->watcher_);
  57
+void StatWatcher::Callback(uv_fs_poll_t* handle,
  58
+                           int status,
  59
+                           const uv_statbuf_t* prev,
  60
+                           const uv_statbuf_t* curr) {
  61
+  StatWatcher* wrap = container_of(handle, StatWatcher, watcher_);
  62
+  assert(handle == &wrap->watcher_);
55 63
   HandleScope scope;
56  
-  Local<Value> argv[2];
57  
-  argv[0] = BuildStatsObject(&watcher->attr);
58  
-  argv[1] = BuildStatsObject(&watcher->prev);
  64
+  Local<Value> argv[3];
  65
+  argv[0] = BuildStatsObject(curr);
  66
+  argv[1] = BuildStatsObject(prev);
  67
+  argv[2] = Integer::New(status);
  68
+  if (status == -1) {
  69
+    SetErrno(uv_last_error(wrap->watcher_.loop));
  70
+  }
59 71
   if (onchange_sym.IsEmpty()) {
60 72
     onchange_sym = NODE_PSYMBOL("onchange");
61 73
   }
62  
-  MakeCallback(handler->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
  74
+  MakeCallback(wrap->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
63 75
 }
64 76
 
65 77
 
@@ -69,7 +81,7 @@ Handle<Value> StatWatcher::New(const Arguments& args) {
69 81
   }
70 82
 
71 83
   HandleScope scope;
72  
-  StatWatcher *s = new StatWatcher();
  84
+  StatWatcher* s = new StatWatcher();
73 85
   s->Wrap(args.Holder());
74 86
   return args.This();
75 87
 }
@@ -82,27 +94,23 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
82 94
     return ThrowException(Exception::TypeError(String::New("Bad arguments")));
83 95
   }
84 96
 
85  
-  StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
  97
+  StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
86 98
   String::Utf8Value path(args[0]);
87 99
 
88  
-  assert(handler->path_ == NULL);
89  
-  handler->path_ = strdup(*path);
90  
-
91  
-  ev_tstamp interval = 0.;
92  
-  if (args[2]->IsInt32()) {
93  
-    interval = NODE_V8_UNIXTIME(args[2]);
  100
+  uint32_t interval = DEFAULT_POLL_INTERVAL;
  101
+  if (args[2]->IsUint32()) {
  102
+    interval = args[2]->Uint32Value();
94 103
   }
95 104
 
96  
-  ev_stat_set(&handler->watcher_, handler->path_, interval);
97  
-  ev_stat_start(EV_DEFAULT_UC_ &handler->watcher_);
  105
+  uv_fs_poll_start(&wrap->watcher_, Callback, *path, interval);
98 106
 
99  
-  handler->persistent_ = args[1]->IsTrue();
  107
+  wrap->persistent_ = args[1]->IsTrue();
100 108
 
101  
-  if (!handler->persistent_) {
102  
-    ev_unref(EV_DEFAULT_UC);
  109
+  if (!wrap->persistent_) {
  110
+    uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->watcher_));
103 111
   }
104 112
 
105  
-  handler->Ref();
  113
+  wrap->Ref();
106 114
 
107 115
   return Undefined();
108 116
 }
@@ -110,24 +118,20 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
110 118
 
111 119
 Handle<Value> StatWatcher::Stop(const Arguments& args) {
112 120
   HandleScope scope;
113  
-  StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
  121
+  StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
114 122
   if (onstop_sym.IsEmpty()) {
115 123
     onstop_sym = NODE_PSYMBOL("onstop");
116 124
   }
117  
-  MakeCallback(handler->handle_, onstop_sym, 0, NULL);
118  
-  handler->Stop();
  125
+  MakeCallback(wrap->handle_, onstop_sym, 0, NULL);
  126
+  wrap->Stop();
119 127
   return Undefined();
120 128
 }
121 129
 
122 130
 
123 131
 void StatWatcher::Stop () {
124  
-  if (watcher_.active) {
125  
-    if (!persistent_) ev_ref(EV_DEFAULT_UC);
126  
-    ev_stat_stop(EV_DEFAULT_UC_ &watcher_);
127  
-    free(path_);
128  
-    path_ = NULL;
129  
-    Unref();
130  
-  }
  132
+  if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&watcher_))) return;
  133
+  uv_fs_poll_stop(&watcher_);
  134
+  Unref();
131 135
 }
132 136
 
133 137
 
15  src/node_stat_watcher.h
@@ -23,7 +23,7 @@
23 23
 #define NODE_STAT_WATCHER_H_
24 24
 
25 25
 #include "node.h"
26  
-#include "uv-private/ev.h"
  26
+#include "uv.h"
27 27
 
28 28
 namespace node {
29 29
 
@@ -36,14 +36,11 @@ class StatWatcher : ObjectWrap {
36 36
 
37 37
   StatWatcher() : ObjectWrap() {
38 38
     persistent_ = false;
39  
-    path_ = NULL;
40  
-    ev_init(&watcher_, StatWatcher::Callback);
41  
-    watcher_.data = this;
  39
+    uv_fs_poll_init(uv_default_loop(), &watcher_);
42 40
   }
43 41
 
44 42
   ~StatWatcher() {
45 43
     Stop();
46  
-    assert(path_ == NULL);
47 44
   }
48 45
 
49 46
   static v8::Handle<v8::Value> New(const v8::Arguments& args);
@@ -51,13 +48,15 @@ class StatWatcher : ObjectWrap {
51 48
   static v8::Handle<v8::Value> Stop(const v8::Arguments& args);
52 49
 
53 50
  private:
54  
-  static void Callback(EV_P_ ev_stat *watcher, int revents);
  51
+  static void Callback(uv_fs_poll_t* handle,
  52
+                       int status,
  53
+                       const uv_statbuf_t* prev,
  54
+                       const uv_statbuf_t* curr);
55 55
 
56 56
   void Stop();
57 57
 
58  
-  ev_stat watcher_;
  58
+  uv_fs_poll_t watcher_;
59 59
   bool persistent_;
60  
-  char *path_;
61 60
 };
62 61
 
63 62
 }  // namespace node
6  test/pummel/test-fs-watch-file.js
@@ -19,12 +19,6 @@
19 19
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 20
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 21
 
22  
-// fs.watchFile is not available on Windows
23  
-if (process.platform === 'win32') {
24  
-  process.exit(0);
25  
-}
26  
-
27  
-
28 22
 var common = require('../common');
29 23
 var assert = require('assert');
30 24
 var path = require('path');
5  test/pummel/test-watch-file.js
@@ -19,11 +19,6 @@
19 19
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 20
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 21
 
22  
-// fs.watchFile is not available on Windows
23  
-if (process.platform === 'win32') {
24  
-  process.exit(0);
25  
-}
26  
-
27 22
 var common = require('../common');
28 23
 var assert = require('assert');
29 24
 

0 notes on commit f0ce984

Please sign in to comment.
Something went wrong with that request. Please try again.