From 943b9e6a3697eed783240c3afdd7197b91a82fdd Mon Sep 17 00:00:00 2001 From: Kyle Nusbaum Date: Wed, 11 Nov 2020 11:26:47 -0600 Subject: [PATCH 1/2] viper: support building on AIX This commit removes the config watch feature of the library when building on AIX. The fsnotify dependency required for this feature does not currently compile on AIX, and we no not currently need this feature on AIX. --- viper.go | 70 ------------------------------------------ watch_config.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 70 deletions(-) create mode 100644 watch_config.go diff --git a/viper.go b/viper.go index 476d5ff..50a46be 100644 --- a/viper.go +++ b/viper.go @@ -30,7 +30,6 @@ import ( "path/filepath" "reflect" "strings" - "sync" "time" yaml "gopkg.in/yaml.v2" @@ -281,75 +280,6 @@ func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { v.onConfigChange = run } -func WatchConfig() { v.WatchConfig() } - -func (v *Viper) WatchConfig() { - initWG := sync.WaitGroup{} - initWG.Add(1) - go func() { - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - defer watcher.Close() - // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way - 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) - - 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 - } - } - }() - watcher.Add(configDir) - initWG.Done() // done initalizing 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 -} // SetConfigFile explicitly defines the path, name and extension of the config file. // Viper will use this and not check any of the config paths. diff --git a/watch_config.go b/watch_config.go new file mode 100644 index 0000000..3646833 --- /dev/null +++ b/watch_config.go @@ -0,0 +1,81 @@ +// +build !aix + +package viper + +import ( + "log" + "path/filepath" + "sync" + + "github.com/fsnotify/fsnotify" +) + +func WatchConfig() { v.WatchConfig() } + +func (v *Viper) WatchConfig() { + initWG := sync.WaitGroup{} + initWG.Add(1) + go func() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way + 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) + + 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 + } + } + }() + watcher.Add(configDir) + initWG.Done() // done initalizing 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 +} From 76228697183bf904ddf9a031c684db1918266083 Mon Sep 17 00:00:00 2001 From: Kyle Nusbaum Date: Wed, 11 Nov 2020 12:28:51 -0600 Subject: [PATCH 2/2] fix formatting --- viper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/viper.go b/viper.go index 50a46be..82d415a 100644 --- a/viper.go +++ b/viper.go @@ -280,7 +280,6 @@ func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { v.onConfigChange = run } - // SetConfigFile explicitly defines the path, name and extension of the config file. // Viper will use this and not check any of the config paths. func SetConfigFile(in string) { v.SetConfigFile(in) }