/
fs_wrap.go
executable file
·136 lines (122 loc) · 3.68 KB
/
fs_wrap.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//go:build (darwin || dragonfly || freebsd || linux || netbsd || openbsd || windows || aix || arm_linux || solaris) && !nacl && !plan9
// +build darwin dragonfly freebsd linux netbsd openbsd windows aix arm_linux solaris
// +build !nacl
// +build !plan9
/*
* Copyright © 2019 Hedzr Yeh.
*/
package cmdr
import (
"bufio"
"log"
"os"
"path"
"path/filepath"
"strings"
"sync"
"sync/atomic"
"github.com/fsnotify/fsnotify"
)
func fsWatcherRoutine(s *Options, configDir string, filesWatching []string) {
if atomic.CompareAndSwapInt32(&watcherRun, 0, 1) {
defer func() { atomic.CompareAndSwapInt32(&watcherRun, 1, 0) }()
watcher, err := fsnotify.NewWatcher()
if err == nil {
// eventsWG := &sync.WaitGroup{}
// eventsWG.Add(1)
_ = watcher.Add(configDir)
go fsWatchRunner(s, configDir, filesWatching, watcher)
// initWG.Done() // done initializing the watch in this go routine, so the parent routine can move on...
// eventsWG.Wait() // now, wait for event loop to end in this go-routine...
} else {
stopExitingChannelForFsWatcher()
}
}
}
//nolint:funlen,gocognit //single
func fsWatchRunner(s *Options, configDir string, filesWatching []string, watcher *fsnotify.Watcher) {
defer func() {
watcher.Close()
// effw.Lock()
// defer effw.Unlock()
// if cmdrExitingForFsWatcher != nil {
// close(cmdrExitingForFsWatcher)
// cmdrExitingForFsWatcher = nil
// }
// eventsWG.Done()
}()
for {
select {
case event, ok := <-watcher.Events:
// ok == false: 'Events' channel is closed
if ok {
// log.Debugf("ooo | fsnotify.watcher |%v", event.String())
// currentConfigFile, _ := filepath.EvalSymlinks(filename)
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if event.Op&writeOrCreateMask != 0 {
suffixIsValid := testCfgSuffix(event.Name)
if suffixIsValid {
inside := strings.HasPrefix(filepath.Clean(event.Name), configDir)
include := testArrayContains(event.Name, filesWatching)
if inside || include {
file, err := os.Open(event.Name)
if err != nil {
log.Printf("ERROR: os.Open() returned %v\n", err)
} else {
err = s.mergeConfigFile(bufio.NewReader(file), event.Name, path.Ext(event.Name))
if err != nil {
log.Printf("ERROR: os.Open() returned %v\n", err)
}
s.reloadConfig()
_ = file.Close()
if !include {
filesWatching = append(filesWatching, event.Name)
}
}
}
}
}
}
case err, ok := <-watcher.Errors:
if ok { // 'Errors' channel is not closed
// log.Printf("watcher error: %v\n", err)
log.Printf("Watcher error: %v\n", err)
}
return
case <-cmdrExitingForFsWatcher:
return
}
}
}
// stopExitingChannelForFsWatcher stop fs watcher explicitly
func stopExitingChannelForFsWatcher() {
effw.Lock()
defer effw.Unlock()
if cmdrExitingForFsWatcher != nil && GetBool("watching") {
cmdrExitingForFsWatcher <- struct{}{}
}
}
// stopExitingChannelForFsWatcherAlways stop fs watcher explicitly
func stopExitingChannelForFsWatcherAlways() {
effw.Lock()
defer effw.Unlock()
if cmdrExitingForFsWatcher != nil {
close(cmdrExitingForFsWatcher)
cmdrExitingForFsWatcher = nil
}
}
// func initExitingChannelForFsWatcher() {
// effw.Lock()
// defer effw.Unlock()
// if cmdrExitingForFsWatcher == nil {
// cmdrExitingForFsWatcher = make(chan struct{}, 16)
// }
// }
var (
cmdrExitingForFsWatcher chan struct{}
effw sync.RWMutex
watcherRun int32
)