Skip to content

Commit

Permalink
A better workaround for atomic writes (#791)
Browse files Browse the repository at this point in the history
* A better workaround for atomic writes.

* Adding comments.
  • Loading branch information
mitar authored and paulmillr committed Mar 7, 2019
1 parent 20cb767 commit 8f56261
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 30 deletions.
10 changes: 3 additions & 7 deletions README.md
Expand Up @@ -132,7 +132,7 @@ chokidar.watch('file', {
},

ignorePermissionErrors: false,
atomic: true // or a custom 'atomicity delay', in milliseconds (default 100)
atomic: true
});

```
Expand Down Expand Up @@ -221,12 +221,8 @@ Use with caution.
that don't have read permissions if possible. If watching fails due to `EPERM`
or `EACCES` with this set to `true`, the errors will be suppressed silently.
* `atomic` (default: `true` if `useFsEvents` and `usePolling` are `false`).
Automatically filters out artifacts that occur when using editors that use
"atomic writes" instead of writing directly to the source file. If a file is
re-added within 100 ms of being deleted, Chokidar emits a `change` event
rather than `unlink` then `add`. If the default of 100 ms does not work well
for you, you can override it by setting `atomic` to a custom value, in
milliseconds.
Uses a workaround to handle file changes by editors that use
"atomic writes" instead of writing directly to the source file.

### Methods & Events

Expand Down
42 changes: 19 additions & 23 deletions index.js
Expand Up @@ -113,9 +113,8 @@ function FSWatcher(_opts) {
opts.interval = parseInt(envInterval);
}

// Editor atomic write normalization enabled by default with fs.watch
// Editor atomic write handling enabled by default with fs.watch
if (undef('atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents;
if (opts.atomic) this._pendingUnlinks = Object.create(null);

if (undef('followSymlinks')) opts.followSymlinks = true;

Expand Down Expand Up @@ -176,25 +175,6 @@ FSWatcher.prototype._emit = function(event, path, val1, val2, val3) {
return this;
}

if (this.options.atomic) {
if (event === 'unlink') {
this._pendingUnlinks[path] = args;
setTimeout(function() {
Object.keys(this._pendingUnlinks).forEach(function(path) {
this.emit.apply(this, this._pendingUnlinks[path]);
this.emit.apply(this, ['all'].concat(this._pendingUnlinks[path]));
delete this._pendingUnlinks[path];
}.bind(this));
}.bind(this), typeof this.options.atomic === "number"
? this.options.atomic
: 100);
return this;
} else if (event === 'add' && this._pendingUnlinks[path]) {
event = args[0] = 'change';
delete this._pendingUnlinks[path];
}
}

var emitEvent = function() {
this.emit.apply(this, args);
if (event !== 'error') this.emit.apply(this, ['all'].concat(args));
Expand Down Expand Up @@ -355,8 +335,6 @@ FSWatcher.prototype._awaitWriteFinish = function(path, threshold, event, awfEmit
// Returns boolean
var dotRe = /\..*\.(sw[px])$|\~$|\.subl.*\.tmp/;
FSWatcher.prototype._isIgnored = function(path, stats) {
if (this.options.atomic && dotRe.test(path)) return true;

if (!this._userIgnored) {
var cwd = this.options.cwd;
var ignored = this.options.ignored;
Expand Down Expand Up @@ -620,6 +598,24 @@ FSWatcher.prototype.add = function(paths, _origAdd, _internal) {
}
});

if (this.options.atomic) {
paths = paths.map(function(path) {
// If `path` is already a glob, we do not have to do anything.
if (isGlob(path)) {
return path;
}
else {
var splits = path.split(sysPath.sep);
if (splits.length && splits[splits.length - 1]) {
// We make the last segment of the path a glob pattern.
// This type of a glob pattern is equivalent to the original name.
splits[splits.length - 1] = '@(' + splits[splits.length - 1] + ')';
}
return splits.join(sysPath.sep);
}
});
}

// set aside negated glob strings
paths = paths.filter(function(path) {
if (path[0] === '!') {
Expand Down

0 comments on commit 8f56261

Please sign in to comment.