Skip to content

Commit 9f5e7a9

Browse files
fix(watcher): handles associated events (#1379)
* Handles associated events. * triggers pipeline * Adjusts comment. * Uses fixed version. * Update watch_pattern_test.go --------- Co-authored-by: Alliballibaba <alliballibaba@gmail.com> Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
1 parent a5ca60d commit 9f5e7a9

4 files changed

Lines changed: 37 additions & 9 deletions

File tree

.github/actions/watcher/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ runs:
1919
name: Compile e-dant/watcher
2020
run: |
2121
mkdir watcher
22-
gh release download --repo e-dant/watcher -A tar.gz -O - | tar -xz -C watcher --strip-components 1
22+
gh release download 0.13.2 --repo e-dant/watcher -A tar.gz -O - | tar -xz -C watcher --strip-components 1
2323
cd watcher
2424
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
2525
cmake --build build

internal/watcher/watch_pattern_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package watcher
55
import (
66
"path/filepath"
77
"testing"
8+
"time"
89

910
"github.com/stretchr/testify/assert"
1011
)
@@ -145,6 +146,20 @@ func TestInValidExtendedPatterns(t *testing.T) {
145146
shouldNotMatch(t, "/path/{dir1,dir2}/**/*.php", "/path/dir1/subpath/file.txt")
146147
}
147148

149+
func TestAnAssociatedEventTriggersTheWatcher(t *testing.T) {
150+
watchPattern, err := parseFilePattern("/**/*.php")
151+
assert.NoError(t, err)
152+
watchPattern.trigger = make(chan struct{})
153+
154+
go handleWatcherEvent(watchPattern, "/path/temorary_file", "/path/file.php", 0, 0)
155+
156+
select {
157+
case <-watchPattern.trigger:
158+
case <-time.After(2 * time.Second):
159+
assert.Fail(t, "associated watchPattern did not trigger after 2s")
160+
}
161+
}
162+
148163
func relativeDir(t *testing.T, relativePath string) string {
149164
dir, err := filepath.Abs("./" + relativePath)
150165
assert.NoError(t, err)

internal/watcher/watcher.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
#include "wtr/watcher-c.h"
66

77
void handle_event(struct wtr_watcher_event event, void *data) {
8-
go_handle_file_watcher_event((char *)event.path_name, event.effect_type,
9-
event.path_type, (uintptr_t)data);
8+
go_handle_file_watcher_event(
9+
(char *)event.path_name, (char *)event.associated_path_name,
10+
event.effect_type, event.path_type, (uintptr_t)data);
1011
}
1112

1213
uintptr_t start_new_watcher(char const *const path, uintptr_t data) {

internal/watcher/watcher.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func retryWatching(watchPattern *watchPattern) {
8282
failureMu.Lock()
8383
defer failureMu.Unlock()
8484
if watchPattern.failureCount >= maxFailureCount {
85+
logger.Warn("gave up watching", zap.String("dir", watchPattern.dir))
8586
return
8687
}
8788
logger.Info("watcher was closed prematurely, retrying...", zap.String("dir", watchPattern.dir))
@@ -152,17 +153,28 @@ func stopSession(session C.uintptr_t) {
152153
}
153154

154155
//export go_handle_file_watcher_event
155-
func go_handle_file_watcher_event(path *C.char, eventType C.int, pathType C.int, handle C.uintptr_t) {
156+
func go_handle_file_watcher_event(path *C.char, associatedPath *C.char, eventType C.int, pathType C.int, handle C.uintptr_t) {
156157
watchPattern := cgo.Handle(handle).Value().(*watchPattern)
157-
goPath := C.GoString(path)
158+
handleWatcherEvent(watchPattern, C.GoString(path), C.GoString(associatedPath), int(eventType), int(pathType))
159+
}
160+
161+
func handleWatcherEvent(watchPattern *watchPattern, path string, associatedPath string, eventType int, pathType int) {
162+
// If the watcher prematurely sends the die@ event, retry watching
163+
if pathType == 4 && strings.HasPrefix(path, "e/self/die@") && watcherIsActive.Load() {
164+
retryWatching(watchPattern)
165+
return
166+
}
158167

159-
if watchPattern.allowReload(goPath, int(eventType), int(pathType)) {
168+
if watchPattern.allowReload(path, eventType, pathType) {
160169
watchPattern.trigger <- struct{}{}
170+
return
161171
}
162172

163-
// If the watcher prematurely sends the die@ event, retry watching
164-
if pathType == 4 && strings.HasPrefix(goPath, "e/self/die@") && watcherIsActive.Load() {
165-
retryWatching(watchPattern)
173+
// some editors create temporary files and never actually modify the original file
174+
// so we need to also check the associated path of an event
175+
// see https://github.com/dunglas/frankenphp/issues/1375
176+
if associatedPath != "" && watchPattern.allowReload(associatedPath, eventType, pathType) {
177+
watchPattern.trigger <- struct{}{}
166178
}
167179
}
168180

0 commit comments

Comments
 (0)