@@ -200,6 +200,8 @@ type Viper struct {
200200 aliases map [string ]string
201201 typeByDefValue bool
202202
203+ previousValues map [string ]interface {}
204+
203205 // Store read properties on the object so that we can write back in order with comments.
204206 // This will only be used if the configuration read is a properties file.
205207 properties * properties.Properties
@@ -220,6 +222,7 @@ func New() *Viper {
220222 v .override = make (map [string ]interface {})
221223 v .defaults = make (map [string ]interface {})
222224 v .kvstore = make (map [string ]interface {})
225+ v .previousValues = make (map [string ]interface {})
223226 v .pflags = make (map [string ]FlagValue )
224227 v .env = make (map [string ]string )
225228 v .aliases = make (map [string ]string )
@@ -685,6 +688,45 @@ func GetViper() *Viper {
685688 return v
686689}
687690
691+ // HasChanged returns true if a key has changed and the change has not been retrieved yet using `Get()` and all
692+ // casters `GetString()`, `GetDuration()`, ...
693+ //
694+ // If the value has not been retrieved at all this will also return true.
695+ func HasChanged (key string ) bool { return v .HasChanged (key ) }
696+ func (v * Viper ) HasChanged (key string ) bool {
697+ lcaseKey := strings .ToLower (key )
698+ v .lock .RLock ()
699+ defer v .lock .RUnlock ()
700+
701+ value , ok := v .previousValues [lcaseKey ]
702+ if ! ok {
703+ return IsSet (lcaseKey )
704+ }
705+
706+ // Avoid writing the change
707+ return value != v .find (lcaseKey )
708+ }
709+
710+ // HasChangedSinceInit returns true if a key has changed and the change has not been retrieved yet using `Get()` and all
711+ // casters `GetString()`, `GetDuration()`, ...
712+ //
713+ // If the value has not been retrieved before at all this will return false.
714+ func HasChangedSinceInit (key string ) bool { return v .HasChangedSinceInit (key ) }
715+ func (v * Viper ) HasChangedSinceInit (key string ) bool {
716+ lcaseKey := strings .ToLower (key )
717+ v .lock .RLock ()
718+ defer v .lock .RUnlock ()
719+
720+ value , ok := v .previousValues [lcaseKey ]
721+ if ! ok {
722+ return false
723+ }
724+
725+ // Avoid writing the change
726+ return value != v .find (lcaseKey )
727+
728+ }
729+
688730// Get can retrieve any value given the key to use.
689731// Get is case-insensitive for a key.
690732// Get has the behavior of returning the value associated with the first
@@ -696,6 +738,11 @@ func Get(key string) interface{} { return v.Get(key) }
696738func (v * Viper ) Get (key string ) interface {} {
697739 lcaseKey := strings .ToLower (key )
698740 val := v .find (lcaseKey )
741+
742+ v .lock .Lock ()
743+ v .previousValues [lcaseKey ] = val
744+ v .lock .Unlock ()
745+
699746 if val == nil {
700747 return nil
701748 }
0 commit comments