From f174f957f0fdd3f31fc784318e30cdd58df878f1 Mon Sep 17 00:00:00 2001 From: Arne Groskurth Date: Sun, 31 Jul 2022 21:16:05 +0200 Subject: [PATCH] windows: update watch paths when renaming directories with sub-watches (#370) Fixes #259 Fixes #243 Co-authored-by: Martin Tournoij --- helpers_test.go | 6 ++++++ integration_test.go | 30 ++++++++++++++++++++++++++++++ windows.go | 13 +++++++++++++ 3 files changed, 49 insertions(+) diff --git a/helpers_test.go b/helpers_test.go index cb2f1212..08164fd0 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -411,6 +411,12 @@ func newEvents(t *testing.T, s string) Events { if e, ok := events[runtime.GOOS]; ok { return e } + switch runtime.GOOS { + case "freebsd", "netbsd", "openbsd", "dragonfly", "darwin": + if e, ok := events["kqueue"]; ok { + return e + } + } return events[""] } diff --git a/integration_test.go b/integration_test.go index 6ae1ae07..28b846c6 100644 --- a/integration_test.go +++ b/integration_test.go @@ -164,6 +164,36 @@ func TestWatchRename(t *testing.T) { windows: create /renamed `}, + + {"rename watched directory", func(t *testing.T, w *Watcher, tmp string) { + addWatch(t, w, tmp) + + dir := filepath.Join(tmp, "dir") + mkdir(t, dir) + addWatch(t, w, dir) + + mv(t, dir, tmp, "dir-renamed") + touch(t, tmp, "dir-renamed/file") + }, ` + CREATE "/dir" # mkdir + RENAME "/dir" # mv + CREATE "/dir-renamed" + RENAME "/dir" + CREATE "/dir/file" # touch + + windows: + CREATE "/dir" # mkdir + RENAME "/dir" # mv + CREATE "/dir-renamed" + CREATE "/dir-renamed/file" # touch + + # TODO: no results for the touch; this is probably a bug; windows + # was fixed in #370. + kqueue: + CREATE "/dir" # mkdir + CREATE "/dir-renamed" # mv + REMOVE|RENAME "/dir" + `}, } for _, tt := range tests { diff --git a/windows.go b/windows.go index ecae0ce1..c8899048 100644 --- a/windows.go +++ b/windows.go @@ -14,6 +14,7 @@ import ( "path/filepath" "reflect" "runtime" + "strings" "sync" "syscall" "unsafe" @@ -500,6 +501,18 @@ func (w *Watcher) readEvents() { case syscall.FILE_ACTION_RENAMED_OLD_NAME: watch.rename = name case syscall.FILE_ACTION_RENAMED_NEW_NAME: + // Update saved path of all sub-watches. + old := filepath.Join(watch.path, watch.rename) + w.mu.Lock() + for _, watchMap := range w.watches { + for _, ww := range watchMap { + if strings.HasPrefix(ww.path, old) { + ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) + } + } + } + w.mu.Unlock() + if watch.names[watch.rename] != 0 { watch.names[name] |= watch.names[watch.rename] delete(watch.names, watch.rename)