GithubHelp home page GithubHelp logo

sane's Introduction

Try on repl.it CI

sane

I've been driven to insanity by node filesystem watcher wrappers. Sane aims to be fast, small, and reliable file system watcher. It does that by:

  • By default stays away from fs polling because it's very slow and cpu intensive
  • Uses fs.watch by default and sensibly works around the various issues
  • Maintains a consistent API across different platforms
  • Where fs.watch is not reliable you have the choice of using the following alternatives:

Install

$ npm install sane

How to choose a mode

Don't worry too much about choosing the correct mode upfront because sane maintains the same API across all modes and will be easy to switch.

  • If you're only supporting Linux and OS X, watchman would be the most reliable mode
  • If you're using node > v0.10.0 use the default mode
  • If you're running OS X and you're watching a lot of directories and you're running into nodejs/node-v0.x-archive#5463, use watchman
  • If you're in an environment where native file system events aren't available (like Vagrant), you should use polling
  • Otherwise, the default mode should work well for you

API

sane(dir, options)

Watches a directory and all its descendant directories for changes, deletions, and additions on files and directories.

var watcher = sane('path/to/dir', {glob: ['**/*.js', '**/*.css']});
watcher.on('ready', function () { console.log('ready') });
watcher.on('change', function (filepath, root, stat) { console.log('file changed', filepath); });
watcher.on('add', function (filepath, root, stat) { console.log('file added', filepath); });
watcher.on('delete', function (filepath, root) { console.log('file deleted', filepath); });
// close
watcher.close();

options:

  • glob: a single string glob pattern or an array of them.
  • poll: puts the watcher in polling mode. Under the hood that means fs.watchFile.
  • watchman: makes the watcher use watchman.
  • watchmanPath: sets a custom path for watchman binary.
  • watchexec: makes the watcher use watchexec.
  • dot: enables watching files/directories that start with a dot.
  • ignored: a glob, regex, function, or array of any combination.

For the glob pattern documentation, see micromatch. If you choose to use watchman you'll have to install watchman yourself). If you choose to use watchexec you'll have to install watchexec yourself). For the ignored options, see anymatch.

sane.NodeWatcher(dir, options)

The default watcher class. Uses fs.watch under the hood, and takes the same options as sane(dir, options).

sane.WatchmanWatcher(dir, options)

The watchman watcher class. Takes the same options as sane(dir, options).

sane.Watchexec(dir, options)

The watchexec watcher class. Takes the same options as sane(dir, options).

sane.PollWatcher(dir, options)

The polling watcher class. Takes the same options as sane(dir, options) with the addition of:

  • interval: indicates how often the files should be polled. (passed to fs.watchFile)

sane.{Node|Watchman|Watchexec|Poll}Watcher#close

Stops watching.

sane.{Node|Watchman|Watchexec|Poll}Watcher events

Emits the following events:

All events are passed the file/dir path relative to the root directory

  • ready when the program is ready to detect events in the directory
  • change when a file changes
  • add when a file or directory has been added
  • delete when a file or directory has been deleted

CLI

This module includes a simple command line interface, which you can install with npm install sane -g.

Usage: sane <command> [...directory] [--glob=<filePattern>] [--poll] [--watchman] [--watchman-path=<watchmanBinaryPath>] [--dot] [--wait=<seconds>]

OPTIONS:
    --glob=<filePattern>
      A single string glob pattern or an array of them.

    --ignored=<filePattern>
      A glob, regex, function, or array of any combination.

    --poll, -p
      Use polling mode.

    --watchman, -w
      Use watchman (if available).

    --watchman-path=<watchmanBinaryPath>
      Sets a custom path for watchman binary (if using this mode).

    --dot, -d
      Enables watching files/directories that start with a dot.

    --wait=<seconds>
      Duration, in seconds, that watching will be disabled
      after running <command>. Setting this option will
      throttle calls to <command> for the specified duration.
    --quiet, -q
      Disables sane's console output

    --changes-only, -o
      Runs <command> only when a change occur. Skips running <command> at startup

It will watch the given directory and run the given every time a file changes.

CLI example usage

  • sane 'echo "A command ran"'
  • sane 'echo "A command ran"' --glob='**/*.css'
  • sane 'echo "A command ran"' site/assets/css --glob='**/*.css'
  • sane 'echo "A command ran"' --glob='**/*.css' --ignored='**/ignore.css'
  • sane 'echo "A command ran"' --wait=3
  • sane 'echo "A command ran"' -p

License

MIT

Credits

The CLI was originally based on the watch CLI. Watch is licensed under the Apache License Version 2.0.

sane's People

Contributors

amasad avatar bguiz avatar bruce-one avatar callumlocke avatar ccheever avatar chmanie avatar coscholl avatar cpojer avatar dcombslinkedin avatar dependabot[bot] avatar frankie567 avatar jonathanong avatar kelonye avatar m-allanson avatar maicki avatar marcello3d avatar marcioapm avatar mndvns avatar moudy avatar okuryu avatar olsonpm avatar ro-savage avatar stefanpenner avatar tcoopman avatar tomccabe avatar wez avatar wtgtybhertgeghgtwtg avatar xcambar avatar xdissent avatar yungsters avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sane's Issues

10% utilization on a single core

not sure how i can help. let me know what you need. seems to happen after a while and not immediately. i only can tell because my cpu fans start spinning. it comes up as node in my activity monitor.

got about the same utilization with gaze, but this is written better and works with added files, so...

i'm on OS X 10.9.2

this isn't a big deal since i only use this in development

Save and provide stat's to emitted events.

Currently, sane is stat'ing both on initial walk (when registering files by way of the walker callback), and when change events happen (here). It could be very useful to downstream consumers to have access to the result of those fs.stat calls. I propose, adding the prior stat value to the CHANGE_EVENT and DELETE_EVENT events, and the new stat to the ADD_EVENT.

A super hacky and likely horrible diff showing what kind of thing I am talking about:

diff --git a/index.js b/index.js
index 7811b28..66a7831 100644
--- a/index.js
+++ b/index.js
@@ -113,7 +113,7 @@ Watcher.prototype.isFileIncluded = function(relativePath) {
  * @private
  */

-Watcher.prototype.register = function(filepath) {
+Watcher.prototype.register = function(filepath, stat) {
   var relativePath = path.relative(this.root, filepath);
   if (!this.isFileIncluded(relativePath)) {
     return false;
@@ -125,7 +125,7 @@ Watcher.prototype.register = function(filepath) {
   }

   var filename = path.basename(filepath);
-  this.dirRegistery[dir][filename] = true;
+  this.dirRegistery[dir][filename] = stat;

   return true;
 };
@@ -306,22 +306,22 @@ Watcher.prototype.processChange = function(dir, event, file) {
       // win32 emits usless change events on dirs.
       if (event !== 'change') {
         this.watchdir(fullPath);
-        this.emitEvent(ADD_EVENT, relativePath);
+        this.emitEvent(ADD_EVENT, relativePath, stat);
       }
     } else {
-      var registered = this.registered(fullPath);
+      var registeredStat = this.registered(fullPath);
       if (error && error.code === 'ENOENT') {
         this.unregister(fullPath);
         this.stopWatching(fullPath);
         this.unregisterDir(fullPath);
-        if (registered) {
-          this.emitEvent(DELETE_EVENT, relativePath);
+        if (registeredStat) {
+          this.emitEvent(DELETE_EVENT, relativePath, registeredStat, stat);
         }
-      } else if (registered) {
-        this.emitEvent(CHANGE_EVENT, relativePath);
+      } else if (registeredStat) {
+        this.emitEvent(CHANGE_EVENT, relativePath, registeredStat, stat);
       } else {
         if (this.register(fullPath)) {
-          this.emitEvent(ADD_EVENT, relativePath);
+          this.emitEvent(ADD_EVENT, relativePath, stat);
         }
       }
     }
@@ -340,7 +340,7 @@ Watcher.prototype.emitEvent = function(type, file) {
   clearTimeout(this.changeTimers[key]);
   this.changeTimers[key] = setTimeout(function() {
     delete this.changeTimers[key];
-    this.emit(type, file);
+    this.emit.apply(this, arguments);
   }.bind(this), DEFAULT_DELAY);
 };

My particular use-case is that I need to filter certain events out by way of comparing the before/after stat's. Specifically, on Windows when you hardlink a file (unlike on *nix) a change event is triggered in the source directory as well as the destination directory. Using the nlink count or even the mtime in the stats would be enough information to know if we should filter the given event.

Thoughts?

sane not detect moved directory

Directory structure:

  • example1
  • example2
    • text.txt

var watcher = sane('example1', { glob: ['**/*.txt'] });

Sane not detect move example2 to example1.

installing this module causes warnings

npm WARN engine makeerror@1.0.10: wanted: {"node":"0.6.x"} (current: {"node":"1.6.2","npm":"2.7.3"})
npm WARN engine tmpl@1.0.3: wanted: {"node":"0.6.x"} (current: {"node":"1.6.2","npm":"2.7.3"})

I've submitted PR's to the offending dependencies

Once they update, someone (me if I notice it) should update this module accordingly.

Uncaught lstat EPERM errors—potential error handling bug in node_watcher

I have been having a problem where uncaught lstat EPERM errors are cropping up on Windows for some users when using the node watcher.

While I have not been able to reproduce the error on my own machine, I did find one potential bug that could cause the symptoms I'm seeing:

  1. node_watcher's recReaddir function (node_watcher.js#L338) calls a library walker, which returns an EventEmitter
  2. This emitter will emit 'error' events for lstat, readdir, and other errors: walker.js#L52
  3. node_watcher isn't listening for error events on the emitter, so if/when they happen, they get thrown: events.js#L161

It's not clear to me what the correct behavior is in this scenario, should it be logic similar to node_watcher.js#L223?

changelog

I'm using sane v1.0.2 and want to upgrade to the newest version v1.3.0. As there is no changelog and nothing mentioned about semantic versioning, can you tell me if there are any braking changes?

files not included in the globs are still being watched

here's what i have so far:

Jonathans-MacBook-Pro:test jong$ DEBUG=component-watcher component build -w
  component-watcher watching globs: component.json, index.js, lib/**/*.js, lib/**/*.json, lib/**/*.html, lib/**/*.css +0ms
[ 'component.json',
  'index.js',
  'lib/**/*.js',
  'lib/**/*.json',
  'lib/**/*.html',
  'lib/**/*.css' ]
[ '/Users/jong/Workspace/test',
  '/Users/jong/Workspace/test/build',
  '/Users/jong/Workspace/test/components',
  '/Users/jong/Workspace/test/lib',
  '/Users/jong/Workspace/test/components/component',
  '/Users/jong/Workspace/test/components/discore',
  '/Users/jong/Workspace/test/components/ianstormtaylor',
  '/Users/jong/Workspace/test/components/matthewp',
  '/Users/jong/Workspace/test/components/visionmedia',
  '/Users/jong/Workspace/test/components/yields',
  '/Users/jong/Workspace/test/lib/test',
  '/Users/jong/Workspace/test/components/component/classes',
  '/Users/jong/Workspace/test/components/component/css',
  '/Users/jong/Workspace/test/components/component/delegate',
  '/Users/jong/Workspace/test/components/component/dom',
  '/Users/jong/Workspace/test/components/component/domify',
  '/Users/jong/Workspace/test/components/component/each',
  '/Users/jong/Workspace/test/components/component/emitter',
  '/Users/jong/Workspace/test/components/component/event',
  '/Users/jong/Workspace/test/components/component/indexof',
  '/Users/jong/Workspace/test/components/component/matches-selector',
  '/Users/jong/Workspace/test/components/component/path-to-regexp',
  '/Users/jong/Workspace/test/components/component/props',
  '/Users/jong/Workspace/test/components/component/query',
  '/Users/jong/Workspace/test/components/component/to-function',
  '/Users/jong/Workspace/test/components/component/trim',
  '/Users/jong/Workspace/test/components/component/type',
  '/Users/jong/Workspace/test/components/component/value',
  '/Users/jong/Workspace/test/components/component/within-document',
  '/Users/jong/Workspace/test/components/discore/closest',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-camel-case',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-no-case',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-space-case',
  '/Users/jong/Workspace/test/components/matthewp/keys',
  '/Users/jong/Workspace/test/components/matthewp/text',
  '/Users/jong/Workspace/test/components/visionmedia/debug',
  '/Users/jong/Workspace/test/components/yields/isarray',
  '/Users/jong/Workspace/test/components/yields/traverse',
  '/Users/jong/Workspace/test/components/component/classes/1.1.2',
  '/Users/jong/Workspace/test/components/component/css/0.0.4',
  '/Users/jong/Workspace/test/components/component/delegate/0.2.1',
  '/Users/jong/Workspace/test/components/component/dom/1.0.5',
  '/Users/jong/Workspace/test/components/component/domify/1.2.2',
  '/Users/jong/Workspace/test/components/component/each/0.2.2',
  '/Users/jong/Workspace/test/components/component/emitter/1.1.2',
  '/Users/jong/Workspace/test/components/component/event/0.1.2',
  '/Users/jong/Workspace/test/components/component/indexof/0.0.3',
  '/Users/jong/Workspace/test/components/component/matches-selector/0.1.1',
  '/Users/jong/Workspace/test/components/component/path-to-regexp/v0.1.2',
  '/Users/jong/Workspace/test/components/component/props/1.1.2',
  '/Users/jong/Workspace/test/components/component/query/0.0.1',
  '/Users/jong/Workspace/test/components/component/to-function/2.0.0',
  '/Users/jong/Workspace/test/components/component/trim/0.0.1',
  '/Users/jong/Workspace/test/components/component/type/1.0.0',
  '/Users/jong/Workspace/test/components/component/value/1.1.0',
  '/Users/jong/Workspace/test/components/component/within-document/0.0.1',
  '/Users/jong/Workspace/test/components/discore/closest/0.1.2',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-camel-case/0.2.1',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-no-case/0.1.0',
  '/Users/jong/Workspace/test/components/ianstormtaylor/to-space-case/0.1.2',
  '/Users/jong/Workspace/test/components/matthewp/keys/0.0.3',
  '/Users/jong/Workspace/test/components/matthewp/text/0.0.2',
  '/Users/jong/Workspace/test/components/visionmedia/debug/0.7.4',
  '/Users/jong/Workspace/test/components/yields/isarray/1.0.0',
  '/Users/jong/Workspace/test/components/yields/traverse/0.1.1',
  '/Users/jong/Workspace/test/components/component/css/0.0.4/lib',
  '/Users/jong/Workspace/test/components/component/dom/1.0.5/lib' ]

i didn't specify build or components to be watched, but they are being watched anyways, creating an infinite loop for my build process :(

Sane is insanely slow

mkdir files_watched
for i in {1..1000}; do touch files_watched/$i; done
npm install sane

In node:

var sane = require('sane');
var files = (new Array(1000)).fill().map(function(_, i) { return (i + 1).toString() })
var time = Date.now();
var watcher = sane('.', { glob: files });
watcher.on('ready', function() {
  console.log((Date.now() - time)/1000 + " seconds elapsed");
});

Here's what is printed:

22.705 seconds elapsed

What's that? 22 seconds for 1000 files?
What if we just use * pattern?

var sane = require('sane');
var time = Date.now();
var watcher = sane('.', { glob: '*' });
watcher.on('ready', function() {
  console.log((Date.now() - time)/1000 + " seconds elapsed");
});

0.091 seconds elapsed

Wow, that's much better.

What's the case here?

[question] Interest in a ChokidarWatcher?

Hi-

I wrote a mostly complete ChokidarWatcher for sane.
I can see reasons why you wouldn't want this to be integrated into the main sane, (npm installing the native modules chokidar depends on can get hairy on certain platforms), but there does seem to be a bunch of interest in combining or having these projects work together, so I wanted to float the idea out there.

The code is here:
https://github.com/exponentjs/sane

The ChokidarWatcher isn't entirely complete; it can only handle one glob at a time. I can fix that but I don't need it for my own use, so I may not bother unless there is interest in the ChokidarWatcher in the main project.

I don't have a particular agenda or anything that I want this project to do -- just wanted to let you know that a mostly working chokidar backend is out there now in case that leads anywhere good.

Issues with sublime3, broccoli & ember-cli setup

I've posted this answer on SO, for a problem I am experiencing myself.

The mentioned hack seem to solve the problem for now. I would like to understand it better though, as the error directory exists (but is not in the dirRegistry) and the error only occurs when I save the file with sublime 3 and not with any other editor.

Any ideas?

Oh, yeah.. I'm running on Win7 64 bit for what is worth ..

Deprecate and favor chokidar

The title is just the nuts and bolts of the proposal, my suggestion is much more kind 😄

chokidar (followed closely by gaze) is probably the standard file watcher favored by the node community (at large). I think we can agree the benefits of having one package less to debug / browser for issues whenever a problem occurs.

sane is the watcher used by ember-cli so perhaps I should open an issue there instead, but I thought of asking here first and see what you think.

No ill intentions!

Regards

`[email protected]` fails` npm shrinkwrap`

Seems like trying to shrink-wrap dependencies when sane is included in the project fails in npm@3 with this error message:

 $ npm shrinkwrap --dev
npm ERR! Darwin 15.3.0
npm ERR! argv "/Users/sterpe/.nvm/versions/node/v4.3.2/bin/node" "/Users/sterpe/git/Video/vpaid/.node_modules/.bin/npm" "shrinkwrap" "--dev"
npm ERR! node v4.3.2
npm ERR! npm  v3.8.1

npm ERR! Problems were encountered
npm ERR! Please correct and try again.
npm ERR! missing: watch@~0.10.0, required by [email protected]
npm ERR! 
npm ERR! If you need help, you may report this error at:
npm ERR!     <https://github.com/npm/npm/issues>

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/sterpe/git/Video/vpaid/npm-debug.log

Not-globs seem to match everything.

I have a glob list that looks like:

    templates: ['**/*.html', '!**/*index.html'],

(angular templatecache, I don't want to template my index.html, just all the child html). The problem is this watcher actually fires on all file changes - I am 98% sure it's because the !**/*index.html matches almost all the files in my build tree (including .js files, .scss files, and so on). In other uses of arrays-of-minimatch, the notted conditions tend to be anded together with the regular conditions, like "match when (C1 or C2 or C3) AND (N4 and N5)" for something like ['C1', 'C2', 'C3', '!N4', '!N5'] if that makes sense.

Excluding node_modules in watcher

If running the Node native watcher on a folder that contains a large node_modules directory, we want the ability to ignore this folder.

Is there any way in this project (or with the Node native watcher for that matter), to handle use cases like this?

See jspm/jspm-cli#1999 for more info.

Files not watched unless poll:true option is set.

Here is our full scss build file:

#!/usr/bin/env node

var fs = require('fs');
var sane = require('sane');
var sass = require('node-sass');

var watcher = new sane.Watcher('./components', {glob: ['**/*.scss'], poll: true});

var buildSass = function () {
  sass.render({
    file: './components/app.scss',
    sourceMap: true,
    success: function (css) {
      fs.writeFile('./public/public_assets/css/built.css', css, function (error) {
        if (error) return console.log(error);
        console.log('CSS built');
      });
    },
    error: function (error) {
      console.log(error);
    }
  });
};

if (!fs.existsSync('./public/public_assets/css')) {
  fs.mkdirSync('./public/public_assets/css/');
}

watcher.on('ready', function () {
  console.log('SCSS being watched');
  buildSass();
});
watcher.on('change', function (filepath) {
  console.log('file changed', filepath);
  buildSass();
});
watcher.on('add', function (filepath) {
  console.log('file added', filepath);
  buildSass();
});
watcher.on('delete', function (filepath) {
  console.log('file deleted', filepath);
  buildSass();
});

This line seems to be the issue:

var watcher = new sane.Watcher('./components', {glob: ['**/*.scss'], poll: true});

If poll: true is removed or set to false the build task does not run when a file is saved even though the watcher.on('ready') is being fired. When poll: true is set though it builds on save like it should.

All dirs in the watch dir are opened, easily causing too many open files

I noticed from #3 that there's a deliberate design decision to watch all dirs in case any new files appear that might match the glob. I can see why this would be helpful in some cases, but it breaks things in others, so a choice would be excellent.

var sane = require('sane');
// Wouldn't actually watch anything, but will crash immediately
sane('/Users/nick/', ['**/fdjsaiofjidosafjioadsfjidosa*']);

As far as I can tell, there's no reasonable way to prevent that from crashing, because there are simply too many dirs opened for watching at once (even with a massive ulimit increase).

My request is that a flag be added to make only files matching the glob on startup get watched. My core use case is for fb-flo, where I want to watch projectdir/static/minified/js/**/*.js and projectdir/static/templates/**/*.html, but there are simply too many dirs under projectdir/static to open them all at once.

Thanks!

example in README.md is broken

var watcher = sane('path/to/dir', ['**/*.js', '**/*.css']); doesn't work out of the box. I had to change it to var watcher = sane('path/to/dir', {glob: ['**/*.js', '**/*.css']}); to make it stop reporting changes to .DS_Store.

Unhandled EPERM error on Windows when dir deleted

On Windows, when a watched directory is deleted, an EPERM error is thrown when attempting to stat the change. This can be observed by running the test suite on Windows:

> [email protected] test 'C:\path\to\sane'
> mocha --bail


  ....................

  19 passing (26s)
  1 failing

  1) sane in normal mode sane(file) removing a dir will emit delete event:
     Uncaught Error: EPERM, stat 'C:\temp\path\to\sane_test\sub_9\file_0'

This happens because fs.stat on win32 will receive an EPERM error instead of ENOENT when attempting to stat a non-existent directory. As far as I can tell, this is similar but not related to nodejs/node-v0.x-archive#4337.

A pull request fixing the issue will be forthcoming.

Do not throw on missing directory/file.

From this comment.
Trying to watch a file that does not exist with node_watcher terminates the process. chokidar handles this by wrapping fs.watch in a try-catch block and swallowing the error if it's an ENOENT or ENOTDIR.
Does something like that sound okay?

optionally support `--no-save-state`

a watchman does not age-out watchers yet, some use-cases would prefer a restart to blow away watching state.

I suspect either this project of fb-watchman needs some tweaking to support this option.

TypeError: Object.keys called on non-object

The problem

When editing a file (on sublime text 3 + Windows 8.1 64 bits) I got some errors saying

Object.keys(this.dirRegistery[dir]).forEach(function(file, i, arr) {
^
TypeError: Object.keys called on non-object
at Function.keys (native)
at Watcher.detectChangedFile (D:\Sites\site.com\node_modules\fb-flo\node_modules\sane\index.js:249:10)
at Watcher.normalizeChange (D:\Sites\site.com\node_modules\fb-flo\node_modules\sane\index.js:283:10)
at FSWatcher.emit (events.js:98:17)
at FSEvent.FSWatcher._handle.onchange (fs.js:1044:12)

The cause

After some investigation I found that Sublime text (or some IDE) creates some tmp file that completely mess up how sane watch files. Even with atomic_save to false it seems to create strange file.

Solution (but dunno if it's a good solution)

I found a fix doing a test on file but I think it would break things doing this. The problem is this file variable being null for random reasons. I can do a PR if you want but I need to know if I broke something with this edit ^^.

Watcher.prototype.normalizeChange = function(dir, event, file) {
  if (!file && file !== null) {

`add` without `change`.

Currently, creating and writing to a file in a watched directory with a method like fs.writeFileSync causes both an add and a change event to be fired. Is there a way to config sane to only trigger the add event in cases like this? I have a repository demonstrating the issue.

close race condition with watch and readdir

Calling close on a watcher closes currently watched directories but does not account for asynchronous callbacks.

Easiest way to reproduce is to create a watcher and try to close it right away.

TypeError('Arguments to path.join must be strings'); on windows

On windows, while using flo I get following error:

path.js:204
        throw new TypeError('Arguments to path.join must be strings');
              ^
TypeError: Arguments to path.join must be strings
    at f (path.js:204:15)
    at Object.filter (native)
    at Object.exports.join (path.js:209:40)
    at Watcher.processChange (c:\Workspace\fb-flo-gulp\node_modules\fb-flo\node_modules\sane\index.js:203:23)
    at FSWatcher.EventEmitter.emit (events.js:98:17)
    at FSEvent.FSWatcher._handle.onchange (fs.js:1039:12)

Using node v0.10.28.

I've debugged a bit:

Watcher.prototype.processChange = function(dir, event, file) {
  console.log(dir);
  console.log(file);
  console.log(event);

output:

c:\Workspace\fb-flo-gulp\app
.subl49b.tmp
rename
c:\Workspace\fb-flo-gulp\app
.subl49b.tmp
change
c:\Workspace\fb-flo-gulp\app
.subl49b.tmp
change
c:\Workspace\fb-flo-gulp\app
.subl49b.tmp
change
c:\Workspace\fb-flo-gulp\app
index.html~RF1c4a5795.TMP
rename
c:\Workspace\fb-flo-gulp\app
null
rename

So it seems that proccessChange receives null files now and then and crashes on these.

Allow a custom filter function instead of glob

  1. I want to be able to pass a custom function that examines filenames and returns true/false
  2. I propose renaming the glob option to filter (and keeping glob as an alias, for back compatibility)

let me know if you agree with one or both of the above, and I'll PR!

What's the difference to chokidar?

Diversity is good, fragmentation is bad. I'm wondering what the advantage of this package are over chokidar, which seems pretty well maintained and, for now, much more popular. Maybe another fs.watch wrapper isn't actually needed? Or if it is, can you at least document the differences?

`npm install` jshint: command not found

±master → npm install
/
> [email protected] prepublish /Users/aylott/src/amasad:sane
> jshint --config=.jshintrc src/ index.js && mocha --bail

sh: jshint: command not found
±master → npm install

> [email protected] prepublish /Users/aylott/src/amasad:sane
> jshint --config=.jshintrc src/ index.js && mocha --bail

sh: mocha: command not found

Question about 'persistent' mode

this module looks perfect, thank you for writing it.

I'm confused about the persistent option.. how could watching files ever not be persistent?

Watcher plugin API

Branching off the discussion about the chokidar watcher in #53, I've been thinking that a plugin API could be useful to let users of sane (e.g. me) use custom watchers without bloating the sane package or adding too much maintenance cost.

My end goal is to be able to use a custom watcher with the RN packager where the pieces are layered like this:

(The packager would also expose a flag to set the watcher implementation.)

At a high level is this something you'd be open to?

Individual watchers have different construction API from index.js entry point

The individual watchers NodeWatcher PollWatcher etc expect to be used with the new operator. The sane function on does that, but switching from var watch = require('sane'); to var watch = require('sane').NodeWatcher; is not a valid transformation. Can the Watcher ctors be made to instantiate themselves, if ! this instanceof Watcher?

No way to watch dotfiles

Currently sane doesn't pick up files starting with a dot.

minimatch has a dot: true option.

Could you either turn this option on in minimatch, or provide a way for me to pass in minimatch options when invoking sane?

Document reliability

I'm glad someone's concerned about reliability with file watching. I've had so many reliability problems with things like webpack's watcher and chokidar. What I'm not seeing here is any notes on when this is reliable and when it isn't. When i see things like "watchmen is probably the most reliable mode" I want to know what that means very specifically. What scenarios can't this library catch?

ENOENT on emacs interlock files.

I'm using sane + watchman (via ember-cli) to watch a directory. As I edit files in those directories, emacs creates "interlock" symlinks with weird contents; this is what ls reports on one of them:

lrwxrwxrwx 1 sohum sohum    38 Dec 10 15:34 .#menus-test.js -> [email protected]:1418204054

When these files are deleted, sane crashes on an ENOENT error.

The error appears to be coming from WatchmanWatcher.prototype.handleFileChange, as it seems to be treating the stat error as a failure instead of a deletion.

Thanks!

On windows, when a directory is deleted sane crashes

This seems to be causing issues in fb-flo for me. Deleting a folder crashes the fb-flo session due to the following unhandled exception:

C:\SourceCLS\CLS\Src\Dev\fb-flo\node_modules\fb-flo\node_modules\sane\index.js:242
  Object.keys(this.dirRegistery[dir]).forEach(function(file, i, arr) {
         ^
TypeError: Object.keys called on non-object
    at Function.keys (native)
    at Watcher.detectChangedFile (C:\SourceCLS\CLS\Src\Dev\fb-flo\node_modules\fb-flo\node_modules\sane\index.js:242:10)
    at Watcher.normalizeChange (C:\SourceCLS\CLS\Src\Dev\fb-flo\node_modules\fb-flo\node_modules\sane\index.js:276:10)
    at FSWatcher.EventEmitter.emit (events.js:98:17)
    at FSEvent.FSWatcher._handle.onchange (fs.js:1039:12)

"add" event on directories does not check glob patterns

When committing to git while watching, the ALL_EVENT is fired on .git/objects and those files are wrongly acted upon (it also causes some recursive actions on my build folder...essentially my globs are ignored for some files). Removing line 314 of node_watcher.js solves this problem and I can't really see what that line is there for in the first place?

sane Node Watcher doesn't always close properly.

This problem came up as part of react-native and jest 0.9.

To repro: make node-haste use the NodeWatcher in jest's HasteResolver, see https://github.com/facebook/jest/blob/master/src/resolvers/HasteResolver.js#L23

Run any JS test on react-native. The tests will pass but afterwards the process won't exit and just hang. end is being called properly. Make sure not to use watchman, of course :)

Wanted to open this up here to track the issue. This has caused a few bumps on FB's test infra where watching was accidentally used and then timed out the processes. Ideally, even if watching is used there, the process should properly exit :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.