/
filemonitor.go
116 lines (99 loc) · 2.43 KB
/
filemonitor.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
115
116
package zeusmaster
import (
"io"
"os"
"os/exec"
"path"
"runtime"
"strings"
slog "github.com/burke/zeus/go/shinylog"
)
var filesToWatch chan string
var filesChanged chan string
var watcherIn io.WriteCloser
var watcherOut io.ReadCloser
var watcherErr io.ReadCloser
var allWatchedFiles map[string]bool
func StartFileMonitor(tree *ProcessTree, quit chan bool) {
// this is obscenely large, just because as long as we start
// watching the files eventually, it's more of a priority to
// get the slaves booted as quickly as possible.
filesToWatch = make(chan string, 8192)
filesChanged = make(chan string, 256)
allWatchedFiles = make(map[string]bool)
startWrapper()
for {
select {
case <-quit:
quit <- true
return
case path := <-filesToWatch:
go handleLoadedFileNotification(path)
case path := <-filesChanged:
go handleChangedFileNotification(tree, path)
}
}
}
func executablePath() string {
switch runtime.GOOS {
case "darwin":
return path.Join(path.Dir(os.Args[0]), "fsevents-wrapper")
case "linux":
gemRoot := path.Dir(path.Dir(os.Args[0]))
return path.Join(gemRoot, "ext/inotify-wrapper/inotify-wrapper")
}
Error("Unsupported OS")
return ""
}
func startWrapper() {
cmd := exec.Command(executablePath())
var err error
if watcherIn, err = cmd.StdinPipe(); err != nil {
Error(err.Error())
}
if watcherOut, err = cmd.StdoutPipe(); err != nil {
Error(err.Error())
}
if watcherErr, err = cmd.StderrPipe(); err != nil {
Error(err.Error())
}
cmd.Start()
go func() {
buf := make([]byte, 2048)
for {
n, err := watcherOut.Read(buf)
if err != nil {
errorFailedReadFromWatcher(err)
}
message := strings.TrimSpace(string(buf[:n]))
files := strings.Split(message, "\n")
for _, file := range files {
filesChanged <- file
}
}
}()
go func() {
err := cmd.Wait()
ErrorFileMonitorWrapperCrashed(err)
}()
}
func AddFile(file string) {
filesToWatch <- file
}
func handleLoadedFileNotification(file string) {
// a slave loaded a file. It's up to us here to make sure this file is watched.
if !allWatchedFiles[file] {
allWatchedFiles[file] = true
startWatchingFile(file)
}
}
func handleChangedFileNotification(tree *ProcessTree, file string) {
slog.Yellow("Dependency change at " + file)
tree.RestartNodesWithFeature(file)
}
func startWatchingFile(file string) {
_, err := watcherIn.Write([]byte(file + "\n"))
if err != nil {
println("startWatchingFile:" + err.Error())
}
}