Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recursive watcher for Windows backend #540

Merged
merged 5 commits into from
Dec 20, 2022
Merged

Add recursive watcher for Windows backend #540

merged 5 commits into from
Dec 20, 2022

Conversation

arp242
Copy link
Member

@arp242 arp242 commented Nov 17, 2022

Recursive watches can be added by using a "/..." parameter, similar to the Go command:

w.Add("dir")         // Behaves as before.
w.Add("dir/...")     // Watch dir and all paths underneath it.

w.Remove("dir")      // Remove the watch for dir and, if
                     // recursive, all paths underneath it too

w.Remove("dir/...")  // Behaves like just "dir" if the path was
                     // recursive, error otherwise (probably
                     // want to add recursive remove too at some
                     // point).

The advantage of using "/..." vs. an option is that it can be easily specified in configuration files and the like; for example from a TOML file:

[watches]
dirs = ["/tmp/one", "/tmp/two/..."]

Options for this were previously discussed at:
#339 (comment)

This should be expanded to other backends too; I started with Windows because the implementation is the both the easiest and has the least amount of control (just setting a boolean parameter), and we can focus mostly on writing tests and documentation and the for it, and we can then match the inotify and kqueue behaviour to the Windows one.

Fixes #21

Recursive watches can be added by using a "/..." parameter, similar to
the Go command:

	w.Add("dir")         // Behaves as before.
	w.Add("dir/...")     // Watch dir and all paths underneath it.

	w.Remove("dir")      // Remove the watch for dir and, if
	                     // recursive, all paths underneath it too

	w.Remove("dir/...")  // Behaves like just "dir" if the path was
	                     // recursive, error otherwise (probably
	                     // want to add recursive remove too at some
	                     // point).

The advantage of using "/..." vs. an option is that it can be easily
specified in configuration files and the like; for example from a TOML
file:

	[watches]
	dirs = ["/tmp/one", "/tmp/two/..."]

Options for this were previously discussed at:
#339 (comment)

This should be expanded to other backends too; I started with Windows
because the implementation is the both the easiest and has the least
amount of control (just setting a boolean parameter), and we can focus
mostly on writing tests and documentation and the for it, and we can
then match the inotify and kqueue behaviour to the Windows one.

Fixes #21
@@ -166,6 +174,8 @@ events=$(<<EOF
// you may get hundreds of Write events, so you
// probably want to wait until you've stopped receiving
// them (see the dedup example in cmd/fsnotify).
// Some systems may send Write event for directories
// when the directory content changes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behaviour is kind of annoying, IMO; if you create a new file or directory it sends a Write on the directory, too:

>  fsnotify watch ./test/...

> md NEWDIR
19:36:19.7176   1 CREATE        "test\\NEWDIR"

> cd NEWDIR
> md SUBDIR
19:36:29.4840   2 CREATE        "test\\NEWDIR\\SUBDIR"
19:36:30.4888   3 WRITE         "test\\NEWDIR"

> cd SUBDIR
> echo x >newfile
19:36:56.9763   4 CREATE        "test\\NEWDIR\\SUBDIR\\newfile"
19:36:56.9786   5 WRITE         "test\\NEWDIR\\SUBDIR\\newfile"
19:36:58.2154   6 WRITE         "test\\NEWDIR\\SUBDIR"

> cd ../..
> echo asd >zxczxc
19:38:40.8707   7 CREATE        "test\\zxczxc"
19:38:40.8741   8 WRITE         "test\\zxczxc"

This is also the case with non-recursirve watches:

> fsnotify watch ./test2

> md asd
19:45:37.6129   1 CREATE        "test2\\asd"

> echo zxc > zxczxc
19:45:42.9015   2 CREATE        "test2\\zxczxc"
19:45:42.9045   3 WRITE         "test2\\zxczxc"

> cd asd
> echo zxc > zxczxc
19:45:49.0316   4 WRITE         "test2\\asd"

It's also inconsistent: you don't get this Write event on the root directory.

The reason is because it seems to use timestamps:

FILE_NOTIFY_CHANGE_LAST_WRITE

Any change to the last write-time of files in the watched directory or subtree
causes a change notification wait operation to return. The operating system
detects a change to the last write-time only when the file is written to the
disk. For operating systems that use extensive caching, detection occurs only
when the cache is sufficiently flushed.

FILE_ACTION_MODIFIED

The file was modified. This can be a change in the time stamp or attributes.

I don't see any way to change or disable this. So ... it is what it is, I guess :-/

@arp242 arp242 marked this pull request as ready for review November 28, 2022 20:01
@arp242 arp242 requested review from nshalman and a team November 28, 2022 20:01
@arp242
Copy link
Member Author

arp242 commented Nov 28, 2022

CC: @nicks @milas

@horahoradev
Copy link
Member

will review tomorrow if someone doesn't get to it first, thanks

@nshalman
Copy link
Contributor

nshalman commented Dec 1, 2022

I will try to find some time to review this as soon as I can.

backend_fen.go Outdated Show resolved Hide resolved
backend_inotify.go Outdated Show resolved Hide resolved
backend_other.go Outdated Show resolved Hide resolved
backend_windows.go Outdated Show resolved Hide resolved
@@ -1,6 +1,10 @@
//go:build windows
// +build windows

// Windows backend based on ReadDirectoryChangesW()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RE: Godoc, might be worth changing all instances of "/some/path/..." to be "/some/path/... or X:\some\path\... depending upon platform" or similar

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a note in the "Windows notes" section for this. I think using "/some/path/... or X:\some\path... depending upon platform" on every case where a path is mentioned would get a bit long, and I don't really expect people to be confused by it. Besides, forward slashes work well on Windows, and have since at least Windows 2000 AFAIK so it's not even needed to use \ instead of /.

backend_kqueue.go Outdated Show resolved Hide resolved
backend_windows.go Outdated Show resolved Hide resolved
@milas
Copy link
Contributor

milas commented Dec 1, 2022

(Oops - submitted review without comment.)

The reasoning for using /... seems fine to me & logic is sound. My suggestions were all pedantic grammatical / error-related & safe to ignore 🙃

@arp242
Copy link
Member Author

arp242 commented Dec 14, 2022

I'll probably merge this in the weekend, so if someone still wants to do a review: now's your chance 😅

@arp242 arp242 merged commit 736c884 into main Dec 20, 2022
@arp242 arp242 deleted the recurse-win branch December 20, 2022 12:50
@arp242 arp242 mentioned this pull request Dec 21, 2022
@tigerinus
Copy link

tigerinus commented Apr 21, 2023

@arp242 - this is recursive watcher still valid?

README.md says that:

you must add watches for any directory you want to watch
(a recursive watcher is on the roadmap: https://github.com/fsnotify/fsnotify/issues/18)

If it is still valid, for Windows, should it be C:\\some\\directory\\... or C:/some/directory/...?

@arp242 arp242 mentioned this pull request May 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Subtree watch on Windows
5 participants