From acad1ec1cb0f650e8d8966511e3b06ed299cf37c Mon Sep 17 00:00:00 2001 From: Robert Gerus Date: Mon, 14 Dec 2015 14:58:42 +0100 Subject: [PATCH] Use external dyncfg. --- .travis.yml | 1 - bot/bot.go | 6 +- config/.testconfig.json | 7 -- config/config.go | 192 ------------------------------- config/config_test.go | 246 ---------------------------------------- config/doc.go | 6 - gorepost.go | 4 +- irc/irc.go | 6 +- 8 files changed, 8 insertions(+), 460 deletions(-) delete mode 100644 config/.testconfig.json delete mode 100644 config/config.go delete mode 100644 config/config_test.go delete mode 100644 config/doc.go diff --git a/.travis.yml b/.travis.yml index cd0f0fd..2add50e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ notifications: before_install: - go get github.com/arachnist/gorepost/bot - go get github.com/arachnist/gorepost/irc - - go get github.com/arachnist/gorepost/config - go get github.com/axw/gocov/gocov - go get github.com/mattn/goveralls - go get github.com/go-playground/overalls diff --git a/bot/bot.go b/bot/bot.go index e5c1d50..19fc6a9 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -1,14 +1,14 @@ package bot import ( - "github.com/arachnist/gorepost/config" + "github.com/arachnist/dyncfg" "sync" ) -var cfg *config.Config +var cfg *dyncfg.Dyncfg var cfgLock sync.Mutex -func Initialize(config *config.Config) { +func Initialize(config *dyncfg.Dyncfg) { cfg = config cfgLock.Unlock() } diff --git a/config/.testconfig.json b/config/.testconfig.json deleted file mode 100644 index 657940a..0000000 --- a/config/.testconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "TestLookup":"this can be anything you can imagine, but now it's just a string", - "TestLookupString":"this should be a string", - "TestLookupStringSlice":["i", "am", "going", "to", "be", "a", "slice"], - "TestLookupStringMap":["I", "want", "to", "be", "a", "map[string]bool"], - "ThisWillBeAnInt":42 -} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 388436d..0000000 --- a/config/config.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2015 Robert S. Gerus. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package config - -import ( - "encoding/json" - "io/ioutil" - "log" - "os" - "sort" - "sync" - "time" -) - -type cacheEntry struct { - modTime time.Time - contents interface{} -} - -// A Config is a dynamic configuration key lookup mechanism. -type Config struct { - cache map[string]cacheEntry - buildFileList func(map[string]string) []string - l sync.Mutex -} - -// New takes a file list builder and returns a new instance of Config. -// -// The instance is ready to use. -func New(f func(map[string]string) []string) *Config { - var c Config - c.cache = make(map[string]cacheEntry) - c.buildFileList = f - return &c -} - -func (c *Config) lookupvar(key, path string) interface{} { - var f interface{} - i, err := os.Stat(path) - _, ok := c.cache[path] - if os.IsNotExist(err) { - log.Println("Config does not exist", path) - if ok { - log.Println("Purging", path, "from cache") - delete(c.cache, path) - } - } - if err != nil { - return nil - } - - if c.cache[path].modTime.Before(i.ModTime()) || !ok { - log.Println("Stale cache for", path) - data, err := ioutil.ReadFile(path) - if err != nil { - log.Println("Purging", path, "from cache:", err) - delete(c.cache, path) - return nil - } - - err = json.Unmarshal(data, &f) - if err != nil { - log.Println("Cannot parse", path) - log.Println("Purging", path, "from cache:", err) - delete(c.cache, path) - return nil - } - - log.Println("Updating cache for", path) - c.cache[path] = cacheEntry{ - modTime: i.ModTime(), - contents: f, - } - - return f.(map[string]interface{})[key] - } - - log.Println("Found cache for", path) - return c.cache[path].contents.(map[string]interface{})[key] -} - -// Lookup searches for requested configuration key in file list built using -// context. -func (c *Config) Lookup(context map[string]string, key string) interface{} { - var value interface{} - - c.l.Lock() - defer c.l.Unlock() - - for _, fpath := range c.buildFileList(context) { - log.Println("Context:", context, "Looking up", key, "in", fpath) - value = c.lookupvar(key, fpath) - if value != nil { - log.Println("Context:", context, "Found", key, value) - return value - } - } - - log.Println("Context:", context, "Key", key, "not found") - return nil -} - -// LookupString is analogous to Lookup(), but does the cast to string. -func (c *Config) LookupString(context map[string]string, key string) string { - var value interface{} - - c.l.Lock() - defer c.l.Unlock() - - for _, fpath := range c.buildFileList(context) { - log.Println("Context:", context, "Looking up", key, "in", fpath) - value = c.lookupvar(key, fpath) - if value != nil { - log.Println("Context:", context, "Found", key, value) - return value.(string) - } - } - - log.Println("Context:", context, "Key", key, "not found") - return "" -} - -// LookupInt is analogous to Lookup(), but does the cast to int. -func (c *Config) LookupInt(context map[string]string, key string) int { - var value interface{} - - c.l.Lock() - defer c.l.Unlock() - - for _, fpath := range c.buildFileList(context) { - log.Println("Context:", context, "Looking up", key, "in", fpath) - value = c.lookupvar(key, fpath) - if value != nil { - log.Println("Context:", context, "Found", key, value) - return int(value.(float64)) - } - } - - log.Println("Context:", context, "Key", key, "not found") - return -1 -} - -// LookupStringSlice is analogous to Lookup(), but does the cast to []string -func (c *Config) LookupStringSlice(context map[string]string, key string) (retval []string) { - var value interface{} - - c.l.Lock() - defer c.l.Unlock() - - for _, fpath := range c.buildFileList(context) { - log.Println("Context:", context, "Looking up", key, "in", fpath) - value = c.lookupvar(key, fpath) - if value != nil { - log.Println("Context:", context, "Found", key, value) - for _, s := range value.([]interface{}) { - retval = append(retval, s.(string)) - } - sort.Strings(retval) - return retval - } - } - - log.Println("Context:", context, "Key", key, "not found") - return []string{""} -} - -// LookupStringMap is analogous to Lookup(), but does the cast to -// map[string]bool for optimised lookups. -func (c *Config) LookupStringMap(context map[string]string, key string) (retval map[string]bool) { - var value interface{} - retval = make(map[string]bool) - - c.l.Lock() - defer c.l.Unlock() - - for _, fpath := range c.buildFileList(context) { - log.Println("Context:", context, "Looking up", key, "in", fpath) - value = c.lookupvar(key, fpath) - if value != nil { - log.Println("Context:", context, "Found", key, value) - for _, s := range value.([]interface{}) { - retval[s.(string)] = true - } - return retval - } - } - - log.Println("Context:", context, "Key", key, "not found") - return retval -} diff --git a/config/config_test.go b/config/config_test.go deleted file mode 100644 index 91ce934..0000000 --- a/config/config_test.go +++ /dev/null @@ -1,246 +0,0 @@ -// +build go1.4 - -// Copyright 2015 Robert S. Gerus. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package config - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "reflect" - "testing" - "time" -) - -var emptyContext map[string]string - -// func Lookup(context map[string]string, key string) interface{} -var testsLookup = []struct { - key string - expectedValue string -}{ - { - key: "TestLookup", - expectedValue: "this can be anything you can imagine, but now it's just a string", - }, - { - key: "NotExisting", - expectedValue: "", - }, -} - -func TestLookup(t *testing.T) { - for i, e := range testsLookup { - v := c.Lookup(emptyContext, e.key) - if fmt.Sprintf("%+v", v) != fmt.Sprintf("%+v", e.expectedValue) { - t.Log("test#", i, "Lookup key", e.key) - t.Logf("expected: %+v\n", e.expectedValue) - t.Logf("result : %+v\n", v) - t.Fail() - } - } -} - -// func LookupString(context map[string]string, key string) string -var testsLookupString = []struct { - key string - expectedValue string -}{ - { - key: "TestLookupString", - expectedValue: "this should be a string", - }, - { - key: "NotExisting", - expectedValue: "", - }, -} - -func TestLookupString(t *testing.T) { - for i, e := range testsLookupString { - v := c.LookupString(emptyContext, e.key) - if fmt.Sprintf("%+v", v) != fmt.Sprintf("%+v", e.expectedValue) { - t.Log("test#", i+1, "Lookup key", e.key) - t.Logf("expected: %+v\n", e.expectedValue) - t.Logf("result : %+v\n", v) - t.Fail() - } - } -} - -// func LookupInt(context map[string]string, key string) int -var testsLookupInt = []struct { - key string - expectedValue int -}{ - { - key: "ThisWillBeAnInt", - expectedValue: 42, - }, - { - key: "NotExisting", - expectedValue: -1, - }, -} - -func TestLookupInt(t *testing.T) { - for i, e := range testsLookupInt { - v := c.LookupInt(emptyContext, e.key) - if fmt.Sprintf("%+v", v) != fmt.Sprintf("%+v", e.expectedValue) { - t.Log("test#", i+1, "Lookup key", e.key) - t.Logf("expected: %+v\n", e.expectedValue) - t.Logf("result : %+v\n", v) - t.Fail() - } - } -} - -// func LookupStringSlice(context map[string]string, key string) []string -var testsLookupStringSlice = []struct { - key string - expectedValue []string -}{ - { - // TestLookupStringSlice return slice is ordered - key: "TestLookupStringSlice", - expectedValue: []string{"a", "am", "be", "going", "i", "slice", "to"}, - }, - { - key: "NotExisting", - expectedValue: []string{""}, - }, -} - -func TestLookupStringSlice(t *testing.T) { - for i, e := range testsLookupStringSlice { - v := c.LookupStringSlice(emptyContext, e.key) - if fmt.Sprintf("%+v", v) != fmt.Sprintf("%+v", e.expectedValue) { - t.Log("test#", i+1, "Lookup key", e.key) - t.Logf("expected: %+v\n", e.expectedValue) - t.Logf("result : %+v\n", v) - t.Fail() - } - } -} - -// func LookupStringMap(context map[string]string, key string) map[string]bool -var testsLookupStringMap = []struct { - key string - expectedValue map[string]bool -}{ - { - key: "TestLookupStringMap", - expectedValue: map[string]bool{ - "to": true, - "be": true, - "a": true, - "map[string]bool": true, - "I": true, - "want": true, - }, - }, - { - key: "NotExisting", - expectedValue: map[string]bool{}, - }, -} - -func TestLookupStringMap(t *testing.T) { - for i, e := range testsLookupStringMap { - v := c.LookupStringMap(emptyContext, e.key) - if !reflect.DeepEqual(v, e.expectedValue) { - t.Log("test#", i+1, "Lookup key", e.key) - t.Logf("expected: %+v\n", e.expectedValue) - t.Logf("result : %+v\n", v) - t.Fail() - } - } -} - -func configLookupHelper(map[string]string) []string { - return []string{"this/thing/does/not/exist.json", ".testconfig.json"} -} - -func complicatedLookupHelper(map[string]string) []string { - return []string{ - ".to-be-removed.json", - ".to-be-replaced-with-gibberish.json", - ".to-be-chmoded-000.json", - ".to-be-replaced.json", - } -} - -var testEvents = []struct { - desc string - action func() - ev int -}{ - { - desc: "remove file", - action: func() { _ = os.Remove(".to-be-removed.json") }, - ev: 1, - }, - { - desc: "replace with gibberish", - action: func() { - _ = ioutil.WriteFile(".to-be-replaced-with-gibberish.json", []byte("!@#%^&!%@$&*#@@%*@^#$^&*@&(!"), 0644) - }, - ev: 2, - }, - { - desc: "chmod 000", - action: func() { - _ = os.Chmod(".to-be-chmoded-000.json", 0000) - _ = os.Chtimes(".to-be-chmoded-000.json", time.Now().Local(), time.Now().Local()) - }, - ev: 3, - }, - { - desc: "replace", - action: func() { _ = ioutil.WriteFile(".to-be-replaced.json", []byte("{\"testkey\":99}"), 0644) }, - ev: 99, - }, -} - -func TestLookupvarConditions(t *testing.T) { - // create files and put their parsed contents in cache - for i := len(complicatedLookupHelper(emptyContext)) - 1; i >= 0; i-- { - path := complicatedLookupHelper(emptyContext)[i] - err := ioutil.WriteFile(path, []byte(fmt.Sprintf("{\"testkey\":%d}", i)), 0644) - if err != nil { - t.Log("file write failed") - } - - if i != c2.LookupInt(emptyContext, "testkey") { - t.Log("LookupInt did not return correct value", i) - t.Fail() - } - } - - time.Sleep(time.Second) // make sure we get to update cache - - for _, e := range testEvents { - e.action() - v := c2.LookupInt(emptyContext, "testkey") - if e.ev != v { - t.Log("Test failed:", e.desc, "expected:", e.ev, "got:", v) - t.Fail() - } - } - - for _, p := range complicatedLookupHelper(emptyContext) { - _ = os.Remove(p) - } -} - -var c *Config = New(configLookupHelper) -var c2 *Config = New(complicatedLookupHelper) - -func TestMain(m *testing.M) { - log.SetOutput(ioutil.Discard) - os.Exit(m.Run()) -} diff --git a/config/doc.go b/config/doc.go deleted file mode 100644 index 464f2a7..0000000 --- a/config/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2015 Robert S. Gerus. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -// Package config is a hiera-inspired configuration library. -package config diff --git a/gorepost.go b/gorepost.go index b153203..0775fec 100644 --- a/gorepost.go +++ b/gorepost.go @@ -10,8 +10,8 @@ import ( "os" "path" + "github.com/arachnist/dyncfg" "github.com/arachnist/gorepost/bot" - "github.com/arachnist/gorepost/config" "github.com/arachnist/gorepost/irc" ) @@ -50,7 +50,7 @@ func main() { log.Fatalln("Not a directory:", os.Args[1]) } - cfg := config.New(fileListFuncBuilder(os.Args[1], "common.json")) + cfg := dyncfg.New(fileListFuncBuilder(os.Args[1], "common.json")) logfile, err := os.OpenFile(cfg.LookupString(context, "Logpath"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) if err != nil { diff --git a/irc/irc.go b/irc/irc.go index c3049e7..24f9d3d 100644 --- a/irc/irc.go +++ b/irc/irc.go @@ -12,7 +12,7 @@ import ( "sync" "time" - "github.com/arachnist/gorepost/config" + "github.com/arachnist/dyncfg" ) const delim byte = '\n' @@ -32,7 +32,7 @@ type Connection struct { quitrecv chan struct{} quitkeeper chan struct{} l sync.Mutex - cfg *config.Config + cfg *dyncfg.Dyncfg } // Sender sends IRC messages to server and logs their contents. @@ -179,7 +179,7 @@ func (c *Connection) Keeper() { } // Setup performs initialization tasks. -func (c *Connection) Setup(dispatcher func(func(Message), Message), network string, config *config.Config) { +func (c *Connection) Setup(dispatcher func(func(Message), Message), network string, config *dyncfg.Dyncfg) { rand.Seed(time.Now().UnixNano()) c.reconnect = make(chan struct{}, 1)