/
watcher.go
114 lines (99 loc) · 2.13 KB
/
watcher.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
103
104
105
106
107
108
109
110
111
112
113
114
package appwatchertools
import (
"context"
"errors"
"github.com/fsnotify/fsnotify"
"log"
"os"
"path/filepath"
"strings"
"time"
)
type WatchFileFilter = func(path string) (bool, error)
type OnChangeFn = func(path []string) error
type WatchConfig struct {
Dir string
Debounce time.Duration
isRebuilding bool
// Returns true if file should be watched.
Filter WatchFileFilter
OnChange OnChangeFn
}
func NewWatchConfig() *WatchConfig {
return &WatchConfig{
Filter: func(path string) (bool, error) {
return true, nil
},
}
}
func (c *WatchConfig) cancelFunc() {
// @todo create this
}
func WatchDir(cfg *WatchConfig, ctx context.Context, events chan<- fsnotify.Event) error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
events <- event
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
case <-ctx.Done():
return
}
}
}()
keepWatching(ctx, watcher, cfg)
<-ctx.Done()
return nil
}
func keepWatching(ctx context.Context, watcher *fsnotify.Watcher, cfg *WatchConfig) {
go func() {
for {
select {
case <- ctx.Done():
return
case <- time.After(time.Second):
// sweep for new files every 1 second
err := filepath.Walk(cfg.Dir, func(path string, info os.FileInfo, err error) error {
if info == nil {
cfg.cancelFunc()
return errors.New("nil directory")
}
if info.IsDir() {
if strings.HasPrefix(filepath.Base(path), "_") {
return filepath.SkipDir
}
if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") {
return filepath.SkipDir
}
}
shouldWatchFile, err := cfg.Filter(path)
if shouldWatchFile {
err = watcher.Add(path)
}
return err
})
if err != nil {
// @todo maybe do something
}
//if err != nil {
// ctx.Done()
// break
//}
// sweep for new files every 1 second
//time.Sleep(1 * time.Second)
}
}
}()
}