-
Notifications
You must be signed in to change notification settings - Fork 3
/
watch.go
102 lines (88 loc) · 2.16 KB
/
watch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package reload
import (
"errors"
"io/fs"
"log"
"path"
"path/filepath"
"strings"
"time"
"github.com/bep/debounce"
"github.com/fsnotify/fsnotify"
)
// WatchDirectories listens for changes in directories and
// broadcasts on write.
func (reload *Reloader) WatchDirectories() {
if len(reload.directories) == 0 {
reload.Log.Println("no directories provided (reload.Directories is empty)")
return
}
w, err := fsnotify.NewWatcher()
if err != nil {
reload.Log.Printf("error initializing fsnotify watcher: %s\n", err)
}
defer w.Close()
for _, path := range reload.directories {
directories, err := recursiveWalk(path)
if err != nil {
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
reload.Log.Printf("directory doesn't exist: %s\n", pathErr.Path)
} else {
reload.Log.Printf("error walking directories: %s\n", err)
}
return
}
for _, dir := range directories {
w.Add(dir)
}
}
reload.Log.Println("watching", strings.Join(reload.directories, ","), "for changes")
debounce := debounce.New(100 * time.Millisecond)
callback := func(path string) func() {
return func() {
reload.Log.Println("Edit", path)
if reload.OnReload != nil {
reload.OnReload()
}
reload.cond.Broadcast()
}
}
for {
select {
case err := <-w.Errors:
reload.Log.Println("error watching: ", err)
case e := <-w.Events:
switch {
case e.Has(fsnotify.Create):
// Watch any created file/directory
if err := w.Add(e.Name); err != nil {
log.Printf("error watching %s: %s\n", e.Name, err)
}
debounce(callback(path.Base(e.Name)))
case e.Has(fsnotify.Write):
debounce(callback(path.Base(e.Name)))
case e.Has(fsnotify.Rename), e.Has(fsnotify.Remove):
// a renamed file might be outside the specified paths
directories, _ := recursiveWalk(e.Name)
for _, v := range directories {
w.Remove(v)
}
w.Remove(e.Name)
}
}
}
}
func recursiveWalk(path string) ([]string, error) {
var res []string
err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
res = append(res, path)
}
return nil
})
return res, err
}