Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
168 commits
Select commit Hold shift + click to select a range
be03d1c
Rewrite the native binding in N-API; add context safety in the process.
savetheclocktower Oct 7, 2024
3002a74
Convert the specs to JavaScript.
savetheclocktower Oct 7, 2024
847e2fe
Update `binding.gyp`
savetheclocktower Oct 7, 2024
5ab1832
Fix import
savetheclocktower Oct 7, 2024
aad8e4d
Rewrite Linux approach to allow for graceful stopping
savetheclocktower Oct 7, 2024
92ad3c7
Fix failing test
savetheclocktower Oct 7, 2024
751f987
Redefine the `test` script in `package.json`
savetheclocktower Oct 7, 2024
b88a91f
Fix import
savetheclocktower Oct 7, 2024
48dfc4a
Attempt to modernize GitHub actions workflow
savetheclocktower Oct 7, 2024
5c6a79f
Fix README type (testing CI)
savetheclocktower Oct 7, 2024
53b2ef8
Testing a possible Windows fix
savetheclocktower Oct 7, 2024
2945228
Skip Node 14
savetheclocktower Oct 7, 2024
b66d0c3
(oops)
savetheclocktower Oct 7, 2024
07ea897
Trying a different fix
savetheclocktower Oct 8, 2024
0df653c
Attempt to load debug binding first
savetheclocktower Oct 8, 2024
e72daa3
Don't try to stop a worker we're about to replace
savetheclocktower Oct 8, 2024
0756a65
Maybe I don’t actually need this?
savetheclocktower Oct 8, 2024
670f97a
Attempt to rewrite the Nan stuff in the Windows implementation
savetheclocktower Oct 8, 2024
9093d7a
(oops)
savetheclocktower Oct 8, 2024
912a658
(Claude thinks this might help)
savetheclocktower Oct 8, 2024
3ed47b6
Fix signature
savetheclocktower Oct 8, 2024
1ca28b7
Fix typos
savetheclocktower Oct 8, 2024
ad61888
Typo
savetheclocktower Oct 8, 2024
ed7e13a
Fix old API usage
savetheclocktower Oct 8, 2024
cb8df27
Fix typo on Windows
savetheclocktower Oct 8, 2024
9fdabd8
Fix ordering of conditional test
savetheclocktower Oct 8, 2024
062001a
Fix expectation of number
savetheclocktower Oct 8, 2024
7faae35
Whoops
savetheclocktower Oct 8, 2024
6f92a52
Logging
savetheclocktower Oct 8, 2024
8460f45
Ugh
savetheclocktower Oct 8, 2024
390755f
Add Linux logging
savetheclocktower Oct 8, 2024
da58f0d
OK, now once again without the logging
savetheclocktower Oct 8, 2024
5bad153
Add context-safety test
savetheclocktower Oct 8, 2024
514fcb8
Get macOS context safety working…
savetheclocktower Oct 8, 2024
6c7700d
Add the context safety test to CI runs
savetheclocktower Oct 8, 2024
20b987b
Attempt to make Linux context-safe
savetheclocktower Oct 8, 2024
8f1cf55
Remove Windows `AddonData` stuff
savetheclocktower Oct 9, 2024
bc5e854
Missing argument
savetheclocktower Oct 9, 2024
b532ef8
Fix Linux omission
savetheclocktower Oct 9, 2024
b42dec1
Add some logging
savetheclocktower Oct 9, 2024
99c1595
Ugh
savetheclocktower Oct 9, 2024
92750d8
I am good at this
savetheclocktower Oct 9, 2024
dd08547
More logging, plus harmonize thread/worker IDs
savetheclocktower Oct 9, 2024
c1ec4f0
More logging; try to skip handles that we didn’t create
savetheclocktower Oct 9, 2024
e432b98
What if we have one thread that takes care of all handles?
savetheclocktower Oct 9, 2024
dace071
Match up handles to workers in the single loop
savetheclocktower Oct 9, 2024
e8f4645
Fixed, I think
savetheclocktower Oct 9, 2024
7da0cfa
Try `emplace`
savetheclocktower Oct 9, 2024
91d6c07
Fixes
savetheclocktower Oct 9, 2024
e62ed4e
sigh
savetheclocktower Oct 9, 2024
8ddae50
Add a delay when closing watchers
savetheclocktower Oct 9, 2024
7de16fe
Even more logging
savetheclocktower Oct 9, 2024
cd0b328
`break`, not `return`
savetheclocktower Oct 9, 2024
d849465
A different approach
savetheclocktower Oct 9, 2024
49ee188
Should pass now?
savetheclocktower Oct 10, 2024
1713d94
Try to promote another thread if the “boss” thread is stopped
savetheclocktower Oct 10, 2024
529af98
Typo
savetheclocktower Oct 10, 2024
a0b3f7c
Another oversight
savetheclocktower Oct 10, 2024
2c30fa0
Changes
savetheclocktower Oct 10, 2024
cf9acc2
More typos
savetheclocktower Oct 10, 2024
984e672
Sigh
savetheclocktower Oct 10, 2024
21da2c5
Reintroduce `shouldStop`
savetheclocktower Oct 10, 2024
87d8688
More verbose test
savetheclocktower Oct 10, 2024
34efc12
It is failing… but _why_?
savetheclocktower Oct 10, 2024
8e8c25f
More logging
savetheclocktower Oct 10, 2024
9be75f9
More Linux logging
savetheclocktower Oct 10, 2024
b4d0879
Windows fixes
savetheclocktower Oct 10, 2024
7af1f49
Kill the tests if they hang indefinitely
savetheclocktower Oct 10, 2024
d4e1a7b
Try again on `context-safety.js`
savetheclocktower Oct 10, 2024
3d484b1
A first pass at moving to `efsw`
savetheclocktower Oct 12, 2024
3198532
Fix some specs
savetheclocktower Oct 13, 2024
683a10a
Fix issue introduced by slight buffering of events
savetheclocktower Oct 13, 2024
e3b6d4f
Get the specs passing…
savetheclocktower Oct 13, 2024
26d1ed6
Cleanup
savetheclocktower Oct 13, 2024
caca25e
Fix open handle issue
savetheclocktower Oct 13, 2024
49758ee
Add dev dependencies
savetheclocktower Oct 13, 2024
6c610c4
Clean up specs
savetheclocktower Oct 13, 2024
3f464fb
Use 3 threads on the context-safety test
savetheclocktower Oct 13, 2024
f92eead
Checkout submodules in CI
savetheclocktower Oct 13, 2024
dd3323b
Reformat `binding.gyp`
savetheclocktower Oct 13, 2024
e73886c
Remove unnecessary files
savetheclocktower Oct 13, 2024
cc6b902
Make Visual Studio happy
savetheclocktower Oct 13, 2024
262dac6
Streamline prepublish tasks
savetheclocktower Oct 13, 2024
d55a10a
Use different URI for submodule
savetheclocktower Oct 13, 2024
640b2f4
Script should be testing file monitoring, not directory monitoring
savetheclocktower Oct 14, 2024
09809a8
Filter out too-eager creation events on macOS
savetheclocktower Oct 14, 2024
3e65274
(oops)
savetheclocktower Oct 14, 2024
04397a4
(I don't care about Node 18)
savetheclocktower Oct 14, 2024
fede406
Run the context-safety test before the unit tests
savetheclocktower Oct 14, 2024
b633337
Protect against segfaults…
savetheclocktower Oct 14, 2024
05b2849
Adjust how we react to deletions
savetheclocktower Oct 14, 2024
01ed45d
Make file specs more robust
savetheclocktower Oct 14, 2024
11cd751
Move some specs away from `done` callbacks
savetheclocktower Oct 14, 2024
4c5390a
(oops)
savetheclocktower Oct 14, 2024
018fb3a
Initialize `fileWatcher` as `nullptr`
savetheclocktower Oct 14, 2024
b22e558
Add back AtomDoc for `File` and `Directory`
savetheclocktower Oct 14, 2024
b64e564
Add some comments
savetheclocktower Oct 14, 2024
6c64f15
Convert the `Gruntfile` to JS
savetheclocktower Oct 14, 2024
a45e957
Update `.gitignore`
savetheclocktower Oct 14, 2024
c59bbb1
Amend `README`
savetheclocktower Oct 14, 2024
90fd3f0
Start replacing the Grunt tasks
savetheclocktower Oct 14, 2024
1879096
Update `README` to mention submodule init
savetheclocktower Oct 14, 2024
0ad1f4d
Add preinstall script to initialize submodules when necessary
savetheclocktower Oct 15, 2024
46087e9
Ehh, just use `child_process` instead of a new dependency
savetheclocktower Oct 15, 2024
3f7001c
Do it through Grunt instead
savetheclocktower Oct 15, 2024
95e85e1
No, we don't want Grunt to be a dependency
savetheclocktower Oct 15, 2024
4f01c56
Trial and error at this point
savetheclocktower Oct 15, 2024
3725f25
Check for directory _contents_
savetheclocktower Oct 15, 2024
f2a8ca2
Un-submodule EFSW (too many hassles)
savetheclocktower Oct 15, 2024
7e10961
Return to implicit `install` task
savetheclocktower Oct 15, 2024
84590ea
Oops? (How did this ever work?)
savetheclocktower Oct 15, 2024
28d8f5a
Lazy-load `PathWatcher` to prevent circular dependency
savetheclocktower Oct 15, 2024
05d465f
Ensure `onWillThrowWatchError` returns a `Disposable`
savetheclocktower Oct 15, 2024
cc3f707
Guard against trying to call a `tsfn` that might've been GC’d…
savetheclocktower Oct 15, 2024
82d8319
(Running out of ideas)
savetheclocktower Oct 15, 2024
0199f2b
Guard against a null `tsfn`, perhaps?
savetheclocktower Oct 15, 2024
1a447ef
Add a finalization callback to `tsfn`
savetheclocktower Oct 15, 2024
584c387
Quick test
savetheclocktower Oct 15, 2024
d2d89cd
(oops)
savetheclocktower Oct 15, 2024
d0483cf
Here's another approach that is equally futile for all the same reasons
savetheclocktower Oct 17, 2024
7ba69ea
Streamline the JS…
savetheclocktower Oct 19, 2024
a1d56d1
Remove unnecessary files
savetheclocktower Oct 19, 2024
1b4d53b
Add `.tool-versions` to `.gitignore`
savetheclocktower Oct 19, 2024
a6c5b1d
Add caveat in `README` and `engines` field in `package.json`
savetheclocktower Oct 19, 2024
0f15b6f
Guard access to the `tsfns` map with a mutex
savetheclocktower Oct 19, 2024
1aa17c1
Return to `tsfn`s as class members…
savetheclocktower Oct 19, 2024
3b75ea4
(oops)
savetheclocktower Oct 19, 2024
65761df
Reduce redundant usage of native watchers…
savetheclocktower Oct 24, 2024
0df216f
(thought I fixed this)
savetheclocktower Oct 24, 2024
7ef5a2d
Enable more logging to gain visibility into Windows test failure
savetheclocktower Oct 25, 2024
46d3e1f
Fix things
savetheclocktower Oct 25, 2024
09b2f21
Hide logging behind `DEBUG`
savetheclocktower Oct 25, 2024
79c0eb0
Filter out more spurious events on Mac…
savetheclocktower Oct 25, 2024
08fe138
Fix compilation errors on non-Mac platforms
savetheclocktower Oct 25, 2024
6044229
Fix
savetheclocktower Oct 25, 2024
afd5512
Fix compilation error on Ubuntu, maybe
savetheclocktower Oct 26, 2024
9f355ce
Native bindings changes:
savetheclocktower Oct 27, 2024
2dc5647
Adopt new strategies for reusing native watchers:
savetheclocktower Oct 27, 2024
bef3436
Add ability to configure the amount of native watcher reuse…
savetheclocktower Oct 27, 2024
be19b8a
As a sanity check, perform _no_ native watcher reuse on Linux/Windows
savetheclocktower Oct 27, 2024
bed5a1c
Update another spec to take registry settings into account
savetheclocktower Oct 27, 2024
f57ba65
Allow a platform to eschew `NativeWatcher` reuse altogether…
savetheclocktower Oct 27, 2024
b7a7a2d
Fix spec
savetheclocktower Oct 27, 2024
56ee9d2
A new approach: a custom `FSEvents` implementation on macOS
savetheclocktower Oct 27, 2024
398d408
Skip `NativeWatcherRegistry` specs
savetheclocktower Oct 27, 2024
069300a
Reduce duplication in `FSEventsFileWatcher`…
savetheclocktower Oct 28, 2024
f32158f
Remove `NativeWatcherRegistry` (unneeded at this point)
savetheclocktower Oct 28, 2024
e3f7f53
Return to previous pattern…
savetheclocktower Oct 30, 2024
c14f82e
Fix issue where we inadvertently ignore events on a directory itself
savetheclocktower Oct 30, 2024
8d71fd1
Fix failing specs
savetheclocktower Oct 31, 2024
155cc44
Too edgy and avant-garde for Windows/Linux
savetheclocktower Oct 31, 2024
84ba91f
Attempt to get new spec passing on non-macOS platforms
savetheclocktower Oct 31, 2024
c6f17e7
Untangle mutexes
savetheclocktower Oct 31, 2024
3f0de40
Fix the directory-deletion edge case on all platforms
savetheclocktower Oct 31, 2024
15c112b
Change the specs to agree with observed reality
savetheclocktower Oct 31, 2024
b710480
Deliver more consistent behavior around directory deletion
savetheclocktower Oct 31, 2024
724ac75
Change file spec to be meaningful
savetheclocktower Nov 1, 2024
9eb8beb
Logging cleanup, further native optimization on macOS
savetheclocktower Nov 1, 2024
b885578
Remove unnecessary `devDependencies` and files
savetheclocktower Nov 2, 2024
b66d621
Add some comments
savetheclocktower Nov 2, 2024
2652da2
Update README
savetheclocktower Nov 2, 2024
2c40f68
Remove `getNativeWatcherCount` (redundant and not used in the tests)
savetheclocktower Nov 2, 2024
68b378e
Report the original path on `child-rename` events
savetheclocktower Nov 27, 2024
585b76a
Change the rename-a-file fix to be more targeted
savetheclocktower Nov 28, 2024
6c3d8fe
Move lock guard inside local block
savetheclocktower Dec 24, 2024
5ea87ef
Fix exception encountered in `text-buffer` tests
savetheclocktower Dec 26, 2024
649232b
Return silently on an attempt to unwatch…
savetheclocktower Dec 26, 2024
d2281e6
Use `BigInt`s for JavaScript handles instead of numbers…
savetheclocktower Jan 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
name: ci
name: CI
on:
- pull_request
- push
push:
pull_request:

jobs:
Test:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
name: "Test"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
# - macos-latest
- macos-latest
- windows-latest
node_version:
- 10
- 12
# - 14
# - 18
- 20
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true

- name: Install Node
uses: actions/setup-node@v1
- name: Install Node ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}

- name: Install dependencies
run: npm install

- name: Run tests
run: npm run test
- name: Run context safety test
run: npm run test-context-safety

Skip:
if: contains(github.event.head_commit.message, '[skip ci]')
runs-on: ubuntu-latest
steps:
- name: Skip CI 🚫
run: echo skip ci
- name: Run tests
run: npm test
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
.DS_Store
*.swp
build/
node_modules/
lib/
.node-version
.tool-versions
npm-debug.log
api.json
package-lock.json
.cache/
compile_commands.json
4 changes: 1 addition & 3 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
build/
spec/
script/
*.coffee
scripts/
.npmignore
.travis.yml
.node-version
npm-debug.log
77 changes: 0 additions & 77 deletions Gruntfile.coffee

This file was deleted.

80 changes: 61 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Path Watcher Node module
![ci](https://github.com/atom/node-pathwatcher/workflows/ci/badge.svg)
[![Depenency Status](https://david-dm.org/atom/node-pathwatcher/status.svg)](https://david-dm.org/atom/node-pathwatcher)
# node-pathwatcher

Watch files and directories for changes.


> [!IMPORTANT]
> This library is used in [Pulsar][] in several places for compatibility reasons. The [nsfw](https://www.npmjs.com/package/nsfw) library is more robust and more widely used; it is available in Pulsar via `atom.watchPath` and is usually a better choice.
>
> If you’re here because you want a general-purpose file-watching library for Node, use `nsfw` instead.
>
> The purpose of this library’s continued inclusion in Pulsar is to provide the [File][] and [Directory][] classes that have long been available as exports via `require('atom')`.

## Installing

Expand All @@ -10,30 +18,64 @@ npm install pathwatcher

## Building

* Clone the repository
* Run `npm install` to install the dependencies
* Run `npm test` to run the specs
* Clone the repository
* `git submodule init && git submodule update`
* Run `npm install` to install the dependencies
* Run `npm test` to run the specs

## Caveats

This module is context-aware and context-safe; it can be used from multiple worker threads in the same process. If you keep a file-watcher active, though, it’ll keep the environment from closing; you must stop all watchers if you want your script or thread to finish.

If you’re using it in an Electron renderer process, you must take extra care in page reloading scenarios. Be sure to use `closeAllWatchers` well before the page environment is terminated — e.g., by attaching a `beforeunload` listener.

## Using

```coffeescript
PathWatcher = require 'pathwatcher'
```js
const PathWatcher = require('pathwatcher');
```

### PathWatcher.watch(filename, [listener])
### `watch(filename, listener)`

Watch for changes on `filename`, where `filename` is either a file or a directory. `filename` must be an absolute path and must exist at the time `watch` is called.

The listener callback gets two arguments: `(event, path)`. `event` can be `rename`, `delete` or `change`, and `path` is the path of the file which triggered the event.

Watch for changes on `filename`, where `filename` is either a file or a
directory. The returned object is a `PathWatcher`.
The watcher is not recursive; changes to the contents of subdirectories will not be detected.

The listener callback gets two arguments `(event, path)`. `event` can be `rename`,
`delete` or `change`, and `path` is the path of the file which triggered the
event.
Returns an instance of `PathWatcher`. This instance is useful primarily for the `close` method that stops the watch operation.

For directories, the `change` event is emitted when a file or directory under
the watched directory got created or deleted. And the `PathWatcher.watch` is
not recursive, so changes of subdirectories under the watched directory would
not be detected.
#### Caveats

### PathWatcher.close()
* Watching a specific file or directory will not notify you when that file or directory is created, since the file must already exist before you start watching the path.
* When watching a file, `event` can be any of `rename`, `delete`, or `change`, where `change` means that the file’s contents changed somehow.
* When watching a directory, `event` can only be `change`, and in this context `change` signifies that one or more of the directory’s children changed (by being renamed, deleted, added, or modified).
* A watched directory will not report when it is renamed or deleted. If you want to detect when a given directory is deleted, watch its parent directory and test for the child directory’s existence when you receive a `change` event.

### `PathWatcher::close()`

Stop watching for changes on the given `PathWatcher`.

### `closeAllWatchers()`

Stop watching on all subscribed paths. All existing `PathWatcher` instances will stop receiving events. Call this if you’re going to end the process; it ensures that your script will exit cleanly.

### `getWatchedPaths()`

Returns an array of strings representing the actual paths that are being watched on disk.

`pathwatcher` watches directories in all instances, since it’s easy to do so in a cross-platform manner.

### `File` and `Directory`

These are convenience wrappers around some filesystem operations. They also wrap `PathWatcher.watch` via their `onDidChange` (and similar) methods.

Documentation can be found on the Pulsar documentation site:

* [File][]
* [Directory][]


[File]: https://docs.pulsar-edit.dev/api/pulsar/latest/File/
[Directory]: https://docs.pulsar-edit.dev/api/pulsar/latest/Directory/
[Pulsar]: https://pulsar-edit.dev
6 changes: 0 additions & 6 deletions appveyor.yml

This file was deleted.

Loading
Loading