Skip to content

Commit cfaa0d6

Browse files
committed
Add filter file hook functions (Still need comments and tests)
1 parent adb37d8 commit cfaa0d6

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

example/basics/main.go

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ func main() {
2020
// Uncomment to only notify rename and move events.
2121
// w.FilterOps(watcher.Rename, watcher.Move)
2222

23+
// Uncomment to filter files based on a regular expression.
24+
//
25+
// Only files that match the regular expression during file listing
26+
// will be watched.
27+
// r := regexp.MustCompile("^abc$")
28+
// w.AddFilterHook(watcher.RegexFilterHook(r, false))
29+
2330
go func() {
2431
for {
2532
select {

watcher.go

+60
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io/ioutil"
77
"os"
88
"path/filepath"
9+
"regexp"
910
"strings"
1011
"sync"
1112
"time"
@@ -24,6 +25,10 @@ var (
2425
// ErrWatchedFileDeleted is an error that occurs when a file or folder that was
2526
// being watched has been deleted.
2627
ErrWatchedFileDeleted = errors.New("error: watched file or folder deleted")
28+
29+
// ErrSkip is less of an error, but more of a way for path hooks to skip a file or
30+
// directory.
31+
ErrSkip = errors.New("error: skipping file")
2732
)
2833

2934
// An Op is a type that is used to describe what type
@@ -78,7 +83,31 @@ func (e Event) String() string {
7883
pathType = "DIRECTORY"
7984
}
8085
return fmt.Sprintf("%s %q %s [%s]", pathType, e.Name(), e.Op, e.Path)
86+
}
87+
88+
// FilterFileHookFunc is a function that is called to filter files during listings.
89+
// If a file is ok to be listed, nil is returned otherwise ErrSkip is returned.
90+
type FilterFileHookFunc func(info os.FileInfo, fullPath string) error
91+
92+
// RegexFilterHook is a function that accepts or rejects a file
93+
// for listing based on whether it's filename or full path matches
94+
// a regular expression.
95+
func RegexFilterHook(r *regexp.Regexp, useFullPath bool) FilterFileHookFunc {
96+
return func(info os.FileInfo, fullPath string) error {
97+
str := info.Name()
98+
99+
if useFullPath {
100+
str = fullPath
101+
}
102+
103+
// Match
104+
if r.MatchString(str) {
105+
return nil
106+
}
81107

108+
// No match.
109+
return ErrSkip
110+
}
82111
}
83112

84113
// Watcher describes a process that watches files for changes.
@@ -91,6 +120,7 @@ type Watcher struct {
91120

92121
// mu protects the following.
93122
mu *sync.Mutex
123+
ffh []FilterFileHookFunc
94124
running bool
95125
names map[string]bool // bool for recursive or not.
96126
files map[string]os.FileInfo // map of files.
@@ -128,6 +158,13 @@ func (w *Watcher) SetMaxEvents(delta int) {
128158
w.mu.Unlock()
129159
}
130160

161+
// AddFilterHook
162+
func (w *Watcher) AddFilterHook(f FilterFileHookFunc) {
163+
w.mu.Lock()
164+
w.ffh = append(w.ffh, f)
165+
w.mu.Unlock()
166+
}
167+
131168
// IgnoreHiddenFiles sets the watcher to ignore any file or directory
132169
// that starts with a dot.
133170
func (w *Watcher) IgnoreHiddenFiles(ignore bool) {
@@ -203,12 +240,24 @@ func (w *Watcher) list(name string) (map[string]os.FileInfo, error) {
203240
// Add all of the files in the directory to the file list as long
204241
// as they aren't on the ignored list or are hidden files if ignoreHidden
205242
// is set to true.
243+
outer:
206244
for _, fInfo := range fInfoList {
207245
path := filepath.Join(name, fInfo.Name())
208246
_, ignored := w.ignored[path]
209247
if ignored || (w.ignoreHidden && strings.HasPrefix(fInfo.Name(), ".")) {
210248
continue
211249
}
250+
251+
for _, f := range w.ffh {
252+
err := f(fInfo, path)
253+
if err == ErrSkip {
254+
continue outer
255+
}
256+
if err != nil {
257+
return nil, err
258+
}
259+
}
260+
212261
fileList[path] = fInfo
213262
}
214263
return fileList, nil
@@ -245,6 +294,17 @@ func (w *Watcher) listRecursive(name string) (map[string]os.FileInfo, error) {
245294
if err != nil {
246295
return err
247296
}
297+
298+
for _, f := range w.ffh {
299+
err := f(info, path)
300+
if err == ErrSkip {
301+
return nil
302+
}
303+
if err != nil {
304+
return err
305+
}
306+
}
307+
248308
// If path is ignored and it's a directory, skip the directory. If it's
249309
// ignored and it's a single file, skip the file.
250310
_, ignored := w.ignored[path]

0 commit comments

Comments
 (0)