Skip to content

Commit

Permalink
fs: add recursive watch to linux
Browse files Browse the repository at this point in the history
PR-URL: nodejs#45098
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
anonrig authored and lucshi committed Nov 9, 2022
1 parent 82173c1 commit 978d933
Show file tree
Hide file tree
Showing 13 changed files with 801 additions and 109 deletions.
7 changes: 3 additions & 4 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4320,6 +4320,9 @@ The `atime` and `mtime` arguments follow these rules:
<!-- YAML
added: v0.5.10
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/45098
description: Added recursive support for Linux, AIX and IBMi.
- version:
- v15.9.0
- v14.17.0
Expand Down Expand Up @@ -4377,10 +4380,6 @@ the returned {fs.FSWatcher}.
The `fs.watch` API is not 100% consistent across platforms, and is
unavailable in some situations.
The recursive option is only supported on macOS and Windows.
An `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM` exception will be thrown
when the option is used on a platform that does not support it.
On Windows, no events will be emitted if the watched directory is moved or
renamed. An `EPERM` error is reported when the watched directory is deleted.
Expand Down
26 changes: 17 additions & 9 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const {

const pathModule = require('path');
const { isArrayBufferView } = require('internal/util/types');
const nonNativeWatcher = require('internal/fs/recursive_watch');

// We need to get the statValues from the binding at the callsite since
// it's re-initialized after deserialization.
Expand All @@ -68,7 +69,6 @@ const {
codes: {
ERR_FS_FILE_TOO_LARGE,
ERR_INVALID_ARG_VALUE,
ERR_FEATURE_UNAVAILABLE_ON_PLATFORM,
},
AbortError,
uvErrmapGet,
Expand Down Expand Up @@ -163,7 +163,6 @@ let FileWriteStream;
const isWindows = process.platform === 'win32';
const isOSX = process.platform === 'darwin';


function showTruncateDeprecation() {
if (truncateWarn) {
process.emitWarning(
Expand Down Expand Up @@ -2297,13 +2296,22 @@ function watch(filename, options, listener) {

if (options.persistent === undefined) options.persistent = true;
if (options.recursive === undefined) options.recursive = false;
if (options.recursive && !(isOSX || isWindows))
throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively');
const watcher = new watchers.FSWatcher();
watcher[watchers.kFSWatchStart](filename,
options.persistent,
options.recursive,
options.encoding);

let watcher;

// TODO(anonrig): Remove this when/if libuv supports it.
// As of November 2022, libuv does not support recursive file watch on all platforms,
// e.g. Linux due to the limitations of inotify.
if (options.recursive && !isOSX && !isWindows) {
watcher = new nonNativeWatcher.FSWatcher(options);
watcher[watchers.kFSWatchStart](filename);
} else {
watcher = new watchers.FSWatcher();
watcher[watchers.kFSWatchStart](filename,
options.persistent,
options.recursive,
options.encoding);
}

if (listener) {
watcher.addListener('change', listener);
Expand Down
26 changes: 24 additions & 2 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ const {
} = require('internal/util');
const { EventEmitterMixin } = require('internal/event_target');
const { StringDecoder } = require('string_decoder');
const { watch } = require('internal/fs/watchers');
const { kFSWatchStart, watch } = require('internal/fs/watchers');
const nonNativeWatcher = require('internal/fs/recursive_watch');
const { isIterable } = require('internal/streams/utils');
const assert = require('internal/assert');

Expand Down Expand Up @@ -120,6 +121,7 @@ const getDirectoryEntriesPromise = promisify(getDirents);
const validateRmOptionsPromise = promisify(validateRmOptions);

const isWindows = process.platform === 'win32';
const isOSX = process.platform === 'darwin';

let cpPromises;
function lazyLoadCpPromises() {
Expand Down Expand Up @@ -917,6 +919,26 @@ async function readFile(path, options) {
return handleFdClose(readFileHandle(fd, options), fd.close);
}

async function* _watch(filename, options = kEmptyObject) {
validateObject(options, 'options');

if (options.recursive != null) {
validateBoolean(options.recursive, 'options.recursive');

// TODO(anonrig): Remove this when/if libuv supports it.
// As of November 2022, libuv does not support recursive file watch on all platforms,
// e.g. Linux due to the limitations of inotify.
if (options.recursive && !isOSX && !isWindows) {
const watcher = new nonNativeWatcher.FSWatcher(options);
await watcher[kFSWatchStart](filename);
yield* watcher;
return;
}
}

yield* watch(filename, options);
}

module.exports = {
exports: {
access,
Expand Down Expand Up @@ -947,7 +969,7 @@ module.exports = {
writeFile,
appendFile,
readFile,
watch,
watch: !isOSX && !isWindows ? _watch : watch,
constants,
},

Expand Down
Loading

0 comments on commit 978d933

Please sign in to comment.