diff --git a/api/server/datastore/bolt/bolt.go b/api/datastore/bolt/bolt.go similarity index 100% rename from api/server/datastore/bolt/bolt.go rename to api/datastore/bolt/bolt.go diff --git a/api/server/datastore/datastore.go b/api/datastore/datastore.go similarity index 82% rename from api/server/datastore/datastore.go rename to api/datastore/datastore.go index 92085633e..30d9e08a0 100644 --- a/api/server/datastore/datastore.go +++ b/api/datastore/datastore.go @@ -5,9 +5,9 @@ import ( "net/url" "github.com/Sirupsen/logrus" + "github.com/iron-io/functions/api/datastore/bolt" + "github.com/iron-io/functions/api/datastore/postgres" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore/bolt" - "github.com/iron-io/functions/api/server/datastore/postgres" ) func New(dbURL string) (models.Datastore, error) { diff --git a/api/server/datastore/mock.go b/api/datastore/mock.go similarity index 100% rename from api/server/datastore/mock.go rename to api/datastore/mock.go diff --git a/api/server/datastore/postgres/postgres.go b/api/datastore/postgres/postgres.go similarity index 100% rename from api/server/datastore/postgres/postgres.go rename to api/datastore/postgres/postgres.go diff --git a/api/models/config.go b/api/models/config.go index 9bd1f7e21..82fd0bb41 100644 --- a/api/models/config.go +++ b/api/models/config.go @@ -1,13 +1,6 @@ package models type Config struct { - DatabaseURL string `json:"db"` - API string `json:"api"` - Logging struct { - To string `json:"to"` - Level string `json:"level"` - Prefix string `json:"prefix"` - } } func (c *Config) Validate() error { diff --git a/api/server/router/apps_create.go b/api/server/apps_create.go similarity index 89% rename from api/server/router/apps_create.go rename to api/server/apps_create.go index 4bfa09760..bbf384b83 100644 --- a/api/server/router/apps_create.go +++ b/api/server/apps_create.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,7 +9,6 @@ import ( ) func handleAppCreate(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) wapp := &models.AppWrapper{} @@ -33,7 +32,7 @@ func handleAppCreate(c *gin.Context) { return } - app, err := store.StoreApp(wapp.App) + app, err := Api.Datastore.StoreApp(wapp.App) if err != nil { log.WithError(err).Debug(models.ErrAppsCreate) c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate)) diff --git a/api/server/router/apps_delete.go b/api/server/apps_delete.go similarity index 81% rename from api/server/router/apps_delete.go rename to api/server/apps_delete.go index 9d9c14fa8..b62717546 100644 --- a/api/server/router/apps_delete.go +++ b/api/server/apps_delete.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,11 +9,10 @@ import ( ) func handleAppDelete(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) appName := c.Param("app") - err := store.RemoveApp(appName) + err := Api.Datastore.RemoveApp(appName) if err != nil { log.WithError(err).Debug(models.ErrAppsRemoving) diff --git a/api/server/router/apps_get.go b/api/server/apps_get.go similarity index 85% rename from api/server/router/apps_get.go rename to api/server/apps_get.go index f89d90789..e5f2d0d23 100644 --- a/api/server/router/apps_get.go +++ b/api/server/apps_get.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,11 +9,10 @@ import ( ) func handleAppGet(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) appName := c.Param("app") - app, err := store.GetApp(appName) + app, err := Api.Datastore.GetApp(appName) if err != nil { log.WithError(err).Error(models.ErrAppsGet) diff --git a/api/server/router/apps_list.go b/api/server/apps_list.go similarity index 81% rename from api/server/router/apps_list.go rename to api/server/apps_list.go index 7746dc1e2..591acf312 100644 --- a/api/server/router/apps_list.go +++ b/api/server/apps_list.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,12 +9,11 @@ import ( ) func handleAppList(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) filter := &models.AppFilter{} - apps, err := store.GetApps(filter) + apps, err := Api.Datastore.GetApps(filter) if err != nil { log.WithError(err).Debug(models.ErrAppsList) c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsList)) diff --git a/api/server/router/apps_test.go b/api/server/apps_test.go similarity index 92% rename from api/server/router/apps_test.go rename to api/server/apps_test.go index 3ba2a714d..f473ab6fe 100644 --- a/api/server/router/apps_test.go +++ b/api/server/apps_test.go @@ -1,4 +1,4 @@ -package router +package server import ( "bytes" @@ -6,12 +6,13 @@ import ( "strings" "testing" + "github.com/iron-io/functions/api/datastore" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore" ) func TestAppCreate(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -51,7 +52,8 @@ func TestAppCreate(t *testing.T) { } func TestAppDelete(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -81,7 +83,8 @@ func TestAppDelete(t *testing.T) { } func TestAppList(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -110,7 +113,8 @@ func TestAppList(t *testing.T) { } func TestAppGet(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -139,7 +143,8 @@ func TestAppGet(t *testing.T) { } func TestAppUpdate(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string diff --git a/api/server/router/apps_update.go b/api/server/apps_update.go similarity index 89% rename from api/server/router/apps_update.go rename to api/server/apps_update.go index 90beedf03..24f9cdfe3 100644 --- a/api/server/router/apps_update.go +++ b/api/server/apps_update.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,7 +9,6 @@ import ( ) func handleAppUpdate(c *gin.Context) { - // store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) app := &models.App{} @@ -33,7 +32,7 @@ func handleAppUpdate(c *gin.Context) { return } - // app, err := store.StoreApp(wapp.App) + // app, err := Api.Datastore.StoreApp(wapp.App) // if err != nil { // log.WithError(err).Debug(models.ErrAppsCreate) // c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate)) diff --git a/api/server/router/helpers.go b/api/server/helpers.go similarity index 70% rename from api/server/router/helpers.go rename to api/server/helpers.go index 0f44010ee..024239743 100644 --- a/api/server/router/helpers.go +++ b/api/server/helpers.go @@ -1,4 +1,4 @@ -package router +package server import ( "encoding/json" @@ -11,30 +11,15 @@ import ( "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore" ) -func testRouter(ds models.Datastore, config *models.Config) *gin.Engine { +func testRouter() *gin.Engine { r := gin.Default() r.Use(func(c *gin.Context) { - c.Set("store", ds) c.Set("log", logrus.WithFields(logrus.Fields{})) - c.Set("config", config) c.Next() }) - Start(r) - return r -} - -func testRouterWithDefault() *gin.Engine { - r := gin.Default() - r.Use(func(c *gin.Context) { - c.Set("store", &datastore.Mock{}) - c.Set("log", logrus.WithFields(logrus.Fields{})) - c.Set("config", &models.Config{}) - c.Next() - }) - Start(r) + bindHandlers(r) return r } diff --git a/api/server/router/ping.go b/api/server/ping.go similarity index 90% rename from api/server/router/ping.go rename to api/server/ping.go index bd9db4bee..a00ae0502 100644 --- a/api/server/router/ping.go +++ b/api/server/ping.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" diff --git a/api/server/router/router.go b/api/server/router/router.go deleted file mode 100644 index b13a4c00c..000000000 --- a/api/server/router/router.go +++ /dev/null @@ -1,38 +0,0 @@ -package router - -import ( - "github.com/gin-gonic/gin" - "github.com/iron-io/functions/api/models" -) - -func Start(engine *gin.Engine) { - engine.GET("/", handlePing) - engine.GET("/version", handleVersion) - - v1 := engine.Group("/v1") - { - v1.GET("/apps", handleAppList) - v1.POST("/apps", handleAppCreate) - - v1.GET("/apps/:app", handleAppGet) - v1.PUT("/apps/:app", handleAppUpdate) - v1.DELETE("/apps/:app", handleAppDelete) - - apps := v1.Group("/apps/:app") - { - apps.GET("/routes", handleRouteList) - apps.POST("/routes", handleRouteCreate) - apps.GET("/routes/:route", handleRouteGet) - apps.PUT("/routes/:route", handleRouteUpdate) - apps.DELETE("/routes/:route", handleRouteDelete) - } - - } - - engine.Any("/r/:app/*route", handleRunner) - engine.NoRoute(handleRunner) -} - -func simpleError(err error) *models.Error { - return &models.Error{&models.ErrorBody{Message: err.Error()}} -} diff --git a/api/server/router/routes_create.go b/api/server/routes_create.go similarity index 88% rename from api/server/router/routes_create.go rename to api/server/routes_create.go index 53d8bf022..bb5de0147 100644 --- a/api/server/router/routes_create.go +++ b/api/server/routes_create.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,7 +9,6 @@ import ( ) func handleRouteCreate(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) var wroute models.RouteWrapper @@ -35,7 +34,7 @@ func handleRouteCreate(c *gin.Context) { return } - app, err := store.GetApp(wroute.Route.AppName) + app, err := Api.Datastore.GetApp(wroute.Route.AppName) if err != nil { log.WithError(err).Error(models.ErrAppsGet) c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsGet)) @@ -49,7 +48,7 @@ func handleRouteCreate(c *gin.Context) { return } - app, err = store.StoreApp(newapp) + app, err = Api.Datastore.StoreApp(newapp) if err != nil { log.WithError(err).Error(models.ErrAppsCreate) c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate)) @@ -57,7 +56,7 @@ func handleRouteCreate(c *gin.Context) { } } - route, err := store.StoreRoute(wroute.Route) + route, err := Api.Datastore.StoreRoute(wroute.Route) if err != nil { log.WithError(err).Error(models.ErrRoutesCreate) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesCreate)) diff --git a/api/server/router/routes_delete.go b/api/server/routes_delete.go similarity index 81% rename from api/server/router/routes_delete.go rename to api/server/routes_delete.go index 6f2f35b8b..5427ce69d 100644 --- a/api/server/router/routes_delete.go +++ b/api/server/routes_delete.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,12 +9,11 @@ import ( ) func handleRouteDelete(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) appName := c.Param("app") routeName := c.Param("route") - err := store.RemoveRoute(appName, routeName) + err := Api.Datastore.RemoveRoute(appName, routeName) if err != nil { log.WithError(err).Debug(models.ErrRoutesRemoving) diff --git a/api/server/router/routes_get.go b/api/server/routes_get.go similarity index 85% rename from api/server/router/routes_get.go rename to api/server/routes_get.go index 0c9e747f3..5c35ef8ed 100644 --- a/api/server/router/routes_get.go +++ b/api/server/routes_get.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,13 +9,12 @@ import ( ) func handleRouteGet(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) appName := c.Param("app") routeName := c.Param("route") - route, err := store.GetRoute(appName, routeName) + route, err := Api.Datastore.GetRoute(appName, routeName) if err != nil { log.WithError(err).Error(models.ErrRoutesGet) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet)) diff --git a/api/server/router/routes_list.go b/api/server/routes_list.go similarity index 85% rename from api/server/router/routes_list.go rename to api/server/routes_list.go index 6735ba0d9..9f7857eac 100644 --- a/api/server/router/routes_list.go +++ b/api/server/routes_list.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,7 +9,6 @@ import ( ) func handleRouteList(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) appName := c.Param("app") @@ -18,7 +17,7 @@ func handleRouteList(c *gin.Context) { AppName: appName, } - routes, err := store.GetRoutes(filter) + routes, err := Api.Datastore.GetRoutes(filter) if err != nil { log.WithError(err).Error(models.ErrRoutesGet) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesGet)) diff --git a/api/server/router/routes_test.go b/api/server/routes_test.go similarity index 93% rename from api/server/router/routes_test.go rename to api/server/routes_test.go index 37192b025..c0541141b 100644 --- a/api/server/router/routes_test.go +++ b/api/server/routes_test.go @@ -1,4 +1,4 @@ -package router +package server import ( "bytes" @@ -6,12 +6,13 @@ import ( "strings" "testing" + "github.com/iron-io/functions/api/datastore" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore" ) func TestRouteCreate(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -52,7 +53,8 @@ func TestRouteCreate(t *testing.T) { } func TestRouteDelete(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -82,7 +84,8 @@ func TestRouteDelete(t *testing.T) { } func TestRouteList(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -111,7 +114,8 @@ func TestRouteList(t *testing.T) { } func TestRouteGet(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -140,7 +144,8 @@ func TestRouteGet(t *testing.T) { } func TestRouteUpdate(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string diff --git a/api/server/router/routes_update.go b/api/server/routes_update.go similarity index 90% rename from api/server/router/routes_update.go rename to api/server/routes_update.go index 92f9170a3..17d3b85c5 100644 --- a/api/server/router/routes_update.go +++ b/api/server/routes_update.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" @@ -9,7 +9,6 @@ import ( ) func handleRouteUpdate(c *gin.Context) { - store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) var wroute models.RouteWrapper @@ -36,7 +35,7 @@ func handleRouteUpdate(c *gin.Context) { return } - route, err := store.StoreRoute(wroute.Route) + route, err := Api.Datastore.StoreRoute(wroute.Route) if err != nil { log.WithError(err).Debug(models.ErrAppsCreate) c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate)) diff --git a/api/server/router/runner.go b/api/server/runner.go similarity index 95% rename from api/server/router/runner.go rename to api/server/runner.go index 9755ea0b5..178615a87 100644 --- a/api/server/router/runner.go +++ b/api/server/runner.go @@ -1,4 +1,4 @@ -package router +package server import ( "io/ioutil" @@ -21,7 +21,6 @@ func handleRunner(c *gin.Context) { } log := c.MustGet("log").(logrus.FieldLogger) - store := c.MustGet("store").(models.Datastore) var err error @@ -64,7 +63,7 @@ func handleRunner(c *gin.Context) { log.WithFields(logrus.Fields{"app": appName, "path": route}).Debug("Finding route on datastore") - routes, err := store.GetRoutes(filter) + routes, err := Api.Datastore.GetRoutes(filter) if err != nil { log.WithError(err).Error(models.ErrRoutesList) c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesList)) diff --git a/api/server/router/runner_test.go b/api/server/runner_test.go similarity index 93% rename from api/server/router/runner_test.go rename to api/server/runner_test.go index a06d74bfd..94da6d1c1 100644 --- a/api/server/router/runner_test.go +++ b/api/server/runner_test.go @@ -1,4 +1,4 @@ -package router +package server import ( "bytes" @@ -6,12 +6,13 @@ import ( "strings" "testing" + "github.com/iron-io/functions/api/datastore" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore" ) func TestRouteRunnerGet(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -43,7 +44,8 @@ func TestRouteRunnerGet(t *testing.T) { } func TestRouteRunnerPost(t *testing.T) { - router := testRouter(&datastore.Mock{}, &models.Config{}) + New(&datastore.Mock{}, &models.Config{}) + router := testRouter() for i, test := range []struct { path string @@ -76,12 +78,13 @@ func TestRouteRunnerPost(t *testing.T) { } func TestRouteRunnerExecution(t *testing.T) { - router := testRouter(&datastore.Mock{ + New(&datastore.Mock{ FakeRoutes: []*models.Route{ {Path: "/myroute", Image: "iron/hello", Headers: map[string][]string{"X-Function": []string{"Test"}}}, {Path: "/myerror", Image: "iron/error", Headers: map[string][]string{"X-Function": []string{"Test"}}}, }, }, &models.Config{}) + router := testRouter() for i, test := range []struct { path string diff --git a/api/server/server.go b/api/server/server.go index add9f8897..bf4bd4cc7 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -1,27 +1,28 @@ -package api +package server import ( - "fmt" - "os" "path" "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" "github.com/iron-io/functions/api/models" - "github.com/iron-io/functions/api/server/datastore" - "github.com/iron-io/functions/api/server/router" ) +var Api *Server + type Server struct { - router *gin.Engine - cfg *models.Config + Router *gin.Engine + Config *models.Config + Datastore models.Datastore } -func New(config *models.Config) *Server { - return &Server{ - router: gin.Default(), - cfg: config, +func New(ds models.Datastore, config *models.Config) *Server { + Api = &Server{ + Router: gin.Default(), + Config: config, + Datastore: ds, } + return Api } func extractFields(c *gin.Context) logrus.Fields { @@ -32,33 +33,46 @@ func extractFields(c *gin.Context) logrus.Fields { return fields } -func (s *Server) Start() { - if s.cfg.DatabaseURL == "" { - cwd, _ := os.Getwd() - s.cfg.DatabaseURL = fmt.Sprintf("bolt://%s/bolt.db?bucket=funcs", cwd) - } - - if s.cfg.API == "" { - s.cfg.API = "http://localhost:8080" - } - - ds, err := datastore.New(s.cfg.DatabaseURL) - if err != nil { - logrus.WithError(err).Fatalln("Invalid DB url.") - } - - logrus.SetOutput(os.Stdout) - logrus.SetLevel(logrus.DebugLevel) - - s.router.Use(func(c *gin.Context) { - c.Set("config", s.cfg) - c.Set("store", ds) +func (s *Server) Run() { + s.Router.Use(func(c *gin.Context) { c.Set("log", logrus.WithFields(extractFields(c))) c.Next() }) - router.Start(s.router) + bindHandlers(s.Router) // Default to :8080 - s.router.Run() + s.Router.Run() +} + +func bindHandlers(engine *gin.Engine) { + engine.GET("/", handlePing) + engine.GET("/version", handleVersion) + + v1 := engine.Group("/v1") + { + v1.GET("/apps", handleAppList) + v1.POST("/apps", handleAppCreate) + + v1.GET("/apps/:app", handleAppGet) + v1.PUT("/apps/:app", handleAppUpdate) + v1.DELETE("/apps/:app", handleAppDelete) + + apps := v1.Group("/apps/:app") + { + apps.GET("/routes", handleRouteList) + apps.POST("/routes", handleRouteCreate) + apps.GET("/routes/:route", handleRouteGet) + apps.PUT("/routes/:route", handleRouteUpdate) + apps.DELETE("/routes/:route", handleRouteDelete) + } + + } + + engine.Any("/r/:app/*route", handleRunner) + engine.NoRoute(handleRunner) +} + +func simpleError(err error) *models.Error { + return &models.Error{&models.ErrorBody{Message: err.Error()}} } diff --git a/api/server/router/version.go b/api/server/version.go similarity index 90% rename from api/server/router/version.go rename to api/server/version.go index 762315a5a..a0a8a4f5d 100644 --- a/api/server/router/version.go +++ b/api/server/version.go @@ -1,4 +1,4 @@ -package router +package server import ( "net/http" diff --git a/main.go b/main.go index 14d9eb25a..9b87ce05d 100644 --- a/main.go +++ b/main.go @@ -8,24 +8,45 @@ For keeping a minimum running, perhaps when doing a routing table update, if des package main import ( + "fmt" "os" + "strings" log "github.com/Sirupsen/logrus" + "github.com/iron-io/functions/api/datastore" "github.com/iron-io/functions/api/models" "github.com/iron-io/functions/api/server" + "github.com/iron-io/titan/common" + "github.com/spf13/viper" ) func main() { config := &models.Config{} - config.DatabaseURL = os.Getenv("DB") - config.API = os.Getenv("API") + + InitConfig() + common.SetLogLevel(viper.GetString("log_level")) err := config.Validate() if err != nil { log.WithError(err).Fatalln("Invalid config.") } - log.Printf("config: %+v", config) - srv := api.New(config) - srv.Start() + ds, err := datastore.New(viper.GetString("db")) + if err != nil { + log.WithError(err).Fatalln("Invalid DB url.") + } + + srv := server.New(ds, config) + srv.Run() +} + +func InitConfig() { + cwd, _ := os.Getwd() + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.SetDefault("log_level", "info") + viper.SetDefault("db", fmt.Sprintf("bolt://%s/bolt.db?bucket=funcs", cwd)) + viper.SetConfigName("config") + viper.AddConfigPath(".") + viper.AutomaticEnv() // picks up env vars automatically + viper.ReadInConfig() }