Comparing version 1.1.3 to 1.2.0
{ | ||
"name": "sane", | ||
"version": "1.1.3", | ||
"version": "1.2.0", | ||
"description": "Sane aims to be fast, small, and reliable file system watcher.", | ||
@@ -27,3 +27,3 @@ "main": "index.js", | ||
"exec-sh": "^0.2.0", | ||
"fb-watchman": "^1.1.0", | ||
"fb-watchman": "^1.5.0", | ||
"minimatch": "~0.2.14", | ||
@@ -37,3 +37,4 @@ "minimist": "^1.1.1", | ||
"mocha": "~1.17.1", | ||
"rimraf": "~2.2.6" | ||
"rimraf": "~2.2.6", | ||
"tmp": "0.0.27" | ||
}, | ||
@@ -40,0 +41,0 @@ "engines": { |
@@ -5,3 +5,2 @@ 'use strict'; | ||
var path = require('path'); | ||
var exec = require('child_process').exec; | ||
var assert = require('assert'); | ||
@@ -40,3 +39,2 @@ var common = require('./common'); | ||
opts = common.assignOptions(this, opts); | ||
checkIfWatchmanInstalled(); | ||
this.root = path.resolve(dir); | ||
@@ -61,3 +59,5 @@ this.init(); | ||
this.client = new watchman.Client(); | ||
this.client.on('error', this.emit.bind(this)); | ||
this.client.on('error', function(error) { | ||
self.emit('error', error); | ||
}); | ||
this.client.on('subscription', this.handleChangeEvent.bind(this)); | ||
@@ -75,4 +75,5 @@ this.client.on('end', function() { | ||
function onVersion(error, resp) { | ||
function onCapability(error, resp) { | ||
if (handleError(self, error)) { | ||
// The Watchman watcher is unusable on this system, we cannot continue | ||
return; | ||
@@ -83,5 +84,5 @@ } | ||
var parts = resp.version.split('.'); | ||
self.capabilities = resp.capabilities; | ||
if (parseInt(parts[0], 10) >= 3 && parseInt(parts[1], 10) >= 1) { | ||
if (self.capabilities.relative_root) { | ||
self.client.command( | ||
@@ -133,9 +134,29 @@ ['watch-project', getWatchRoot()], onWatchProject | ||
if (self.watchProjectInfo != null) { | ||
options.expression = [ | ||
'dirname', | ||
self.watchProjectInfo.relativePath | ||
]; | ||
// If the server has the wildmatch capability available it supports | ||
// the recursive **/*.foo style match and we can offload our globs | ||
// to the watchman server. This saves both on data size to be | ||
// communicated back to us and compute for evaluating the globs | ||
// in our node process. | ||
if (self.capabilities.wildmatch) { | ||
if (self.globs.length === 0) { | ||
if (!self.dot) { | ||
// Make sure we honor the dot option if even we're not using globs. | ||
options.expression = ['match', '*', 'basename', { | ||
includedotfiles: false | ||
}]; | ||
} | ||
} else { | ||
options.expression = ['anyof']; | ||
for (var i in self.globs) { | ||
options.expression.push(['match', self.globs[i], 'wholename', { | ||
includedotfiles: self.dot | ||
}]); | ||
} | ||
} | ||
} | ||
if (self.capabilities.relative_root) { | ||
options.relative_root = self.watchProjectInfo.relativePath; | ||
} | ||
self.client.command( | ||
@@ -157,3 +178,6 @@ ['subscribe', getWatchRoot(), SUB_NAME, options], | ||
self.client.command(['version'], onVersion); | ||
self.client.capabilityCheck({ | ||
optional:['wildmatch', 'relative_root'] | ||
}, | ||
onCapability); | ||
}; | ||
@@ -183,14 +207,18 @@ | ||
var absPath; | ||
var relativePath; | ||
if (this.watchProjectInfo && this.watchProjectInfo.relativePath.length) { | ||
if (this.capabilities.relative_root) { | ||
relativePath = changeDescriptor.name; | ||
absPath = path.join( | ||
this.watchProjectInfo.root, | ||
changeDescriptor.name | ||
this.watchProjectInfo.relativePath, | ||
relativePath | ||
); | ||
} else { | ||
absPath = path.join(this.root, changeDescriptor.name); | ||
relativePath = changeDescriptor.name; | ||
} | ||
var relativePath = path.relative(this.root, absPath); | ||
if (!common.isFileIncluded(this.globs, this.dot, relativePath)) { | ||
if (!self.capabilities.wildmatch && | ||
!common.isFileIncluded(this.globs, this.dot, relativePath)) { | ||
return; | ||
@@ -251,21 +279,5 @@ } | ||
WatchmanWatcher.prototype.close = function(callback) { | ||
var self = this; | ||
function onUnsubscribe(error, resp) { | ||
if (error && callback) { | ||
callback(error); | ||
return; | ||
} else if (handleError(self, error)) { | ||
return; | ||
} | ||
handleWarning(resp); | ||
self.client.removeAllListeners(); | ||
self.client.end(); | ||
callback && callback(null, true); | ||
} | ||
self.client.command(['unsubscribe', self.root, SUB_NAME], onUnsubscribe); | ||
this.client.removeAllListeners(); | ||
this.client.end(); | ||
callback && callback(null, true); | ||
}; | ||
@@ -305,27 +317,1 @@ | ||
} | ||
/** | ||
* Checks if watchman is installed | ||
* | ||
* @private | ||
*/ | ||
var watchmanInstalled; | ||
function checkIfWatchmanInstalled() { | ||
if (watchmanInstalled == null) { | ||
exec('which watchman', function(err, out) { | ||
if (err || out.length === 0) { | ||
console.warn( | ||
'\u001b[31mIt doesn\'t look like you have `watchman` installed', | ||
'\u001b[39m\nSee', | ||
'https://facebook.github.io/watchman/docs/install.html' | ||
); | ||
process.exit(1); | ||
} else { | ||
watchmanInstalled = true; | ||
} | ||
}); | ||
} else { | ||
return true; | ||
} | ||
} |
@@ -7,8 +7,7 @@ var os = require('os'); | ||
var assert = require('assert'); | ||
var tmp = require('tmp'); | ||
var tmpdir = os.tmpdir(); | ||
tmp.setGracefulCleanup(); | ||
var jo = path.join.bind(path); | ||
var testdir = jo(tmpdir, 'sane_test'); | ||
describe('sane in polling mode', function() { | ||
@@ -23,2 +22,5 @@ harness.call(this, {poll: true}); | ||
}); | ||
describe('sane in watchman mode with offset project', function() { | ||
harness.call(this, {watchman: true, offset: true}) | ||
}); | ||
@@ -37,7 +39,28 @@ function getWatcherClass(mode) { | ||
if (mode.poll) this.timeout(5000); | ||
var global_testdir = null; | ||
var testdir = null; | ||
after(function() { | ||
if (global_testdir) { | ||
try { | ||
rimraf.sync(global_testdir.name); | ||
} catch (e) {} | ||
} | ||
}); | ||
before(function() { | ||
rimraf.sync(testdir); | ||
try { | ||
global_testdir = tmp.dirSync({ | ||
prefix: 'sane-test', | ||
unsafeCleanup: true | ||
}); | ||
testdir = fs.realpathSync(global_testdir.name); | ||
// Some Watchman deployments are restricted to watching | ||
// project roots. Let's fake one | ||
fs.mkdirSync(jo(testdir, '.git')); | ||
// If testing watchman watch-project in offset mode, create an offset dir | ||
if (mode.offset) { | ||
testdir = jo(testdir, 'offset'); | ||
fs.mkdirSync(testdir); | ||
} catch (e) {} | ||
} | ||
for (var i = 0; i < 10; i++) { | ||
@@ -67,2 +90,5 @@ fs.writeFileSync(jo(testdir, 'file_' + i), 'test_' + i); | ||
this.watcher.on('ready', done); | ||
this.watcher.on('error', function(error) { | ||
done(error); | ||
}); | ||
}); | ||
@@ -72,2 +98,5 @@ | ||
var testfile = jo(testdir, 'file_1'); | ||
this.watcher.on('error', function(error) { | ||
done(error); | ||
}); | ||
this.watcher.on('change', function(filepath, dir, stat) { | ||
@@ -74,0 +103,0 @@ assert(stat instanceof fs.Stats); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
57761
1123
0
4
Updatedfb-watchman@^1.5.0