mirror of
https://github.com/spf13/viper
synced 2025-05-15 08:37:19 +00:00
Merge ab4327a019
into a785a79f22
This commit is contained in:
commit
d95395a29d
1 changed files with 49 additions and 61 deletions
110
viper.go
110
viper.go
|
@ -31,7 +31,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
|
@ -386,72 +385,61 @@ func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
|
||||||
func WatchConfig() { v.WatchConfig() }
|
func WatchConfig() { v.WatchConfig() }
|
||||||
|
|
||||||
func (v *Viper) WatchConfig() {
|
func (v *Viper) WatchConfig() {
|
||||||
initWG := sync.WaitGroup{}
|
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
|
||||||
initWG.Add(1)
|
filename, err := v.getConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
configFile := filepath.Clean(filename)
|
||||||
|
configDir, _ := filepath.Split(configFile)
|
||||||
|
realConfigFile, _ := filepath.EvalSymlinks(filename)
|
||||||
|
|
||||||
|
watcher, err := newWatcher()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
watcher, err := newWatcher()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
|
for {
|
||||||
filename, err := v.getConfigFile()
|
select {
|
||||||
if err != nil {
|
case event, ok := <-watcher.Events:
|
||||||
log.Printf("error: %v\n", err)
|
if !ok { // 'Events' channel is closed
|
||||||
initWG.Done()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
configFile := filepath.Clean(filename)
|
|
||||||
configDir, _ := filepath.Split(configFile)
|
|
||||||
realConfigFile, _ := filepath.EvalSymlinks(filename)
|
|
||||||
|
|
||||||
eventsWG := sync.WaitGroup{}
|
|
||||||
eventsWG.Add(1)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event, ok := <-watcher.Events:
|
|
||||||
if !ok { // 'Events' channel is closed
|
|
||||||
eventsWG.Done()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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 (filepath.Clean(event.Name) == configFile &&
|
|
||||||
event.Op&writeOrCreateMask != 0) ||
|
|
||||||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
|
|
||||||
realConfigFile = currentConfigFile
|
|
||||||
err := v.ReadInConfig()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error reading config file: %v\n", err)
|
|
||||||
}
|
|
||||||
if v.onConfigChange != nil {
|
|
||||||
v.onConfigChange(event)
|
|
||||||
}
|
|
||||||
} else if filepath.Clean(event.Name) == configFile &&
|
|
||||||
event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
|
|
||||||
eventsWG.Done()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case err, ok := <-watcher.Errors:
|
|
||||||
if ok { // 'Errors' channel is not closed
|
|
||||||
log.Printf("watcher error: %v\n", err)
|
|
||||||
}
|
|
||||||
eventsWG.Done()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
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 (filepath.Clean(event.Name) == configFile &&
|
||||||
|
event.Op&writeOrCreateMask != 0) ||
|
||||||
|
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
|
||||||
|
realConfigFile = currentConfigFile
|
||||||
|
err := v.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error reading config file: %v\n", err)
|
||||||
|
}
|
||||||
|
if v.onConfigChange != nil {
|
||||||
|
v.onConfigChange(event)
|
||||||
|
}
|
||||||
|
} else if filepath.Clean(event.Name) == configFile &&
|
||||||
|
event.Op&fsnotify.Remove != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case err, ok := <-watcher.Errors:
|
||||||
|
if ok { // 'Errors' channel is not closed
|
||||||
|
log.Printf("watcher error: %v\n", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
watcher.Add(configDir)
|
|
||||||
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...
|
|
||||||
}()
|
}()
|
||||||
initWG.Wait() // make sure that the go routine above fully ended before returning
|
watcher.Add(configDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfigFile explicitly defines the path, name and extension of the config file.
|
// SetConfigFile explicitly defines the path, name and extension of the config file.
|
||||||
|
|
Loading…
Add table
Reference in a new issue