-
-
Notifications
You must be signed in to change notification settings - Fork 887
/
dedup.go
103 lines (86 loc) · 2.2 KB
/
dedup.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
package main
import (
"math"
"sync"
"time"
"github.com/fsnotify/fsnotify"
)
// Depending on the system, a single "write" can generate many Write events; for
// example compiling a large Go program can generate hundreds of Write events on
// the binary.
//
// The general strategy to deal with this is to wait a short time for more write
// events, resetting the wait period for every new event.
func dedup(paths ...string) {
if len(paths) < 1 {
exit("must specify at least one path to watch")
}
// Create a new watcher.
w, err := fsnotify.NewWatcher()
if err != nil {
exit("creating a new watcher: %s", err)
}
defer w.Close()
// Start listening for events.
go dedupLoop(w)
// Add all paths from the commandline.
for _, p := range paths {
err = w.Add(p)
if err != nil {
exit("%q: %s", p, err)
}
}
printTime("ready; press ^C to exit")
<-make(chan struct{}) // Block forever
}
func dedupLoop(w *fsnotify.Watcher) {
var (
// Wait 100ms for new events; each new event resets the timer.
waitFor = 100 * time.Millisecond
// Keep track of the timers, as path → timer.
mu sync.Mutex
timers = make(map[string]*time.Timer)
// Callback we run.
printEvent = func(e fsnotify.Event) {
printTime(e.String())
// Don't need to remove the timer if you don't have a lot of files.
mu.Lock()
delete(timers, e.Name)
mu.Unlock()
}
)
for {
select {
// Read from Errors.
case err, ok := <-w.Errors:
if !ok { // Channel was closed (i.e. Watcher.Close() was called).
return
}
printTime("ERROR: %s", err)
// Read from Events.
case e, ok := <-w.Events:
if !ok { // Channel was closed (i.e. Watcher.Close() was called).
return
}
// We just want to watch for file creation, so ignore everything
// outside of Create and Write.
if !e.Has(fsnotify.Create) && !e.Has(fsnotify.Write) {
continue
}
// Get timer.
mu.Lock()
t, ok := timers[e.Name]
mu.Unlock()
// No timer yet, so create one.
if !ok {
t = time.AfterFunc(math.MaxInt64, func() { printEvent(e) })
t.Stop()
mu.Lock()
timers[e.Name] = t
mu.Unlock()
}
// Reset the timer for this path, so it will start from 100ms again.
t.Reset(waitFor)
}
}
}