diff options
author | Francis Lavoie <[email protected]> | 2023-10-15 22:27:46 -0400 |
---|---|---|
committer | Francis Lavoie <[email protected]> | 2024-04-24 14:17:27 -0400 |
commit | 5af105fa9e97323fb0671b8d8adc7b5ebc55fc1c (patch) | |
tree | 971bc542098b1d79ee5605f5927d7451b48e75ed | |
parent | f999d903f868182d1a941ad4e691e64398afdd07 (diff) | |
download | caddy-5af105fa9e97323fb0671b8d8adc7b5ebc55fc1c.tar.gz caddy-5af105fa9e97323fb0671b8d8adc7b5ebc55fc1c.zip |
Rework replacer types to allow filtering out the file replacer
Co-authored-by: Mohammed Al Sahaf <[email protected]>
-rw-r--r-- | replacer.go | 73 | ||||
-rw-r--r-- | replacer_test.go | 36 |
2 files changed, 58 insertions, 51 deletions
diff --git a/replacer.go b/replacer.go index 7cbf64bdf..175339560 100644 --- a/replacer.go +++ b/replacer.go @@ -35,10 +35,10 @@ func NewReplacer() *Replacer { static: make(map[string]any), mapMutex: &sync.RWMutex{}, } - rep.providers = []ReplacerFunc{ - globalDefaultReplacements, - fileReplacements, - rep.fromStatic, + rep.providers = []replacementProvider{ + globalDefaultReplacementProvider{}, + fileReplacementProvider{}, + ReplacerFunc(rep.fromStatic), } return rep } @@ -50,8 +50,8 @@ func NewEmptyReplacer() *Replacer { static: make(map[string]any), mapMutex: &sync.RWMutex{}, } - rep.providers = []ReplacerFunc{ - rep.fromStatic, + rep.providers = []replacementProvider{ + ReplacerFunc(rep.fromStatic), } return rep } @@ -60,9 +60,8 @@ func NewEmptyReplacer() *Replacer { // A default/empty Replacer is not valid; // use NewReplacer to make one. type Replacer struct { - providers []ReplacerFunc - - static map[string]any + providers []replacementProvider + static map[string]any mapMutex *sync.RWMutex } @@ -71,16 +70,12 @@ type Replacer struct { // may be unsafe in some contexts. func (r *Replacer) WithoutFile() *Replacer { rep := &Replacer{static: r.static} - - // Add a func at the front of the list that - // always skips file placeholders - rep.providers = append( - []ReplacerFunc{func(key string) (any, bool) { - return nil, strings.HasPrefix(key, filePrefix) - }}, - r.providers..., - ) - + for _, v := range r.providers { + if _, ok := v.(fileReplacementProvider); ok { + continue + } + rep.providers = append(rep.providers, v) + } return rep } @@ -101,7 +96,7 @@ func (r *Replacer) Set(variable string, value any) { // the value and whether the variable was known. func (r *Replacer) Get(variable string) (any, bool) { for _, mapFunc := range r.providers { - if val, ok := mapFunc(variable); ok { + if val, ok := mapFunc.replace(variable); ok { return val, true } } @@ -320,16 +315,28 @@ func ToString(val any) string { } } -// ReplacerFunc is a function that returns a replacement -// for the given key along with true if the function is able -// to service that key (even if the value is blank). If the -// function does not recognize the key, false should be -// returned. +// ReplacerFunc is a function that returns a replacement for the +// given key along with true if the function is able to service +// that key (even if the value is blank). If the function does +// not recognize the key, false should be returned. type ReplacerFunc func(key string) (any, bool) -// fileReplacements handles {file.*} replacements, reading -// a file from disk and replacing with its contents. -func fileReplacements(key string) (any, bool) { +func (f ReplacerFunc) replace(key string) (any, bool) { + return f(key) +} + +// replacementProvider is a type that can provide replacements +// for placeholders. Allows for type assertion to determine +// which type of provider it is. +type replacementProvider interface { + replace(key string) (any, bool) +} + +// fileReplacementsProvider handles {file.*} replacements, +// reading a file from disk and replacing with its contents. +type fileReplacementProvider struct{} + +func (f fileReplacementProvider) replace(key string) (any, bool) { if !strings.HasPrefix(key, filePrefix) { return nil, false } @@ -348,10 +355,12 @@ func fileReplacements(key string) (any, bool) { return string(body), true } -// globalDefaultReplacements handles replacements that can -// be used in any context, such as system variables, time, -// or environment variables. -func globalDefaultReplacements(key string) (any, bool) { +// globalDefaultReplacementsProvider handles replacements +// that can be used in any context, such as system variables, +// time, or environment variables. +type globalDefaultReplacementProvider struct{} + +func (f globalDefaultReplacementProvider) replace(key string) (any, bool) { // check environment variable const envPrefix = "env." if strings.HasPrefix(key, envPrefix) { diff --git a/replacer_test.go b/replacer_test.go index 56b2f500e..cf4d321b6 100644 --- a/replacer_test.go +++ b/replacer_test.go @@ -240,9 +240,9 @@ func TestReplacerSet(t *testing.T) { func TestReplacerReplaceKnown(t *testing.T) { rep := Replacer{ mapMutex: &sync.RWMutex{}, - providers: []ReplacerFunc{ + providers: []replacementProvider{ // split our possible vars to two functions (to test if both functions are called) - func(key string) (val any, ok bool) { + ReplacerFunc(func(key string) (val any, ok bool) { switch key { case "test1": return "val1", true @@ -255,8 +255,8 @@ func TestReplacerReplaceKnown(t *testing.T) { default: return "NOOO", false } - }, - func(key string) (val any, ok bool) { + }), + ReplacerFunc(func(key string) (val any, ok bool) { switch key { case "1": return "test-123", true @@ -267,7 +267,7 @@ func TestReplacerReplaceKnown(t *testing.T) { default: return "NOOO", false } - }, + }), }, } @@ -413,7 +413,7 @@ func TestReplacerNew(t *testing.T) { value: "envtest", }, } { - if val, ok := repl.providers[0](tc.variable); ok { + if val, ok := repl.providers[0].replace(tc.variable); ok { if val != tc.value { t.Errorf("Expected value '%s' for key '%s' got '%s'", tc.value, tc.variable, val) } @@ -432,7 +432,7 @@ func TestReplacerNew(t *testing.T) { value: "foo", }, } { - if val, ok := repl.providers[1](tc.variable); ok { + if val, ok := repl.providers[1].replace(tc.variable); ok { if val != tc.value { t.Errorf("Expected value '%s' for key '%s' got '%s'", tc.value, tc.variable, val) } @@ -446,27 +446,25 @@ func TestReplacerNewWithoutFile(t *testing.T) { repl := NewReplacer().WithoutFile() for _, tc := range []struct { - variable string - value string - expectNil bool + variable string + value string + notFound bool }{ { - variable: "file.caddytest/integration/testdata/foo.txt", - expectNil: true, + variable: "file.caddytest/integration/testdata/foo.txt", + notFound: true, }, { variable: "system.os", value: runtime.GOOS, }, } { - if val, ok := repl.Get(tc.variable); ok { - if tc.expectNil && val != nil { - t.Errorf("Expected nil for key '%s' got '%v'", tc.variable, val) - } else if !tc.expectNil && val != tc.value { + if val, ok := repl.Get(tc.variable); ok && !tc.notFound { + if val != tc.value { t.Errorf("Expected value '%s' for key '%s' got '%s'", tc.value, tc.variable, val) } - } else { - t.Errorf("Expected key '%s' to be recognized by second provider", tc.variable) + } else if !tc.notFound { + t.Errorf("Expected key '%s' to be recognized", tc.variable) } } } @@ -512,7 +510,7 @@ func BenchmarkReplacer(b *testing.B) { func testReplacer() Replacer { return Replacer{ - providers: make([]ReplacerFunc, 0), + providers: make([]replacementProvider, 0), static: make(map[string]any), mapMutex: &sync.RWMutex{}, } |