fix(configs): refactor config loader to read default, db, configs, args in order

This commit is contained in:
hexxa 2022-04-02 15:38:59 +08:00 committed by Hexxa
parent 86b2672b01
commit 2f6aa33108
6 changed files with 113 additions and 45 deletions

2
go.mod
View file

@ -10,7 +10,7 @@ require (
github.com/gin-gonic/gin v1.7.3 github.com/gin-gonic/gin v1.7.3
github.com/go-playground/validator/v10 v10.9.0 // indirect github.com/go-playground/validator/v10 v10.9.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/ihexxa/gocfg v0.0.0-20220128082538-9e607ebed51b github.com/ihexxa/gocfg v0.0.1
github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d
github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags v1.4.0
github.com/json-iterator/go v1.1.11 // indirect github.com/json-iterator/go v1.1.11 // indirect

4
go.sum
View file

@ -48,6 +48,10 @@ github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnn
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/ihexxa/gocfg v0.0.0-20220128082538-9e607ebed51b h1:pzx3BC3+v38POQg9sJWhfs/a4xFaJfC0Ar4RRVnFIMo= github.com/ihexxa/gocfg v0.0.0-20220128082538-9e607ebed51b h1:pzx3BC3+v38POQg9sJWhfs/a4xFaJfC0Ar4RRVnFIMo=
github.com/ihexxa/gocfg v0.0.0-20220128082538-9e607ebed51b/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs= github.com/ihexxa/gocfg v0.0.0-20220128082538-9e607ebed51b/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs=
github.com/ihexxa/gocfg v0.0.0-20220402060620-c43339e8d159 h1:gKVyKHtTaT9UJHFjMadZEk4KW+RyMLx9N/cIIviF/nk=
github.com/ihexxa/gocfg v0.0.0-20220402060620-c43339e8d159/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs=
github.com/ihexxa/gocfg v0.0.1 h1:3zsCHY/SYdqKSoo3pwTBWMgivEB7/ctpPPHL3p43UBg=
github.com/ihexxa/gocfg v0.0.1/go.mod h1:oqDTq1ywx4Qi9DdhFwwMHoPCYv6Txrfj2SY5WWcgiJs=
github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d h1:+v33khYHVDPEuuWO/JE1IzhoIu5uNvEcSs5GmXc5Sjw= github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d h1:+v33khYHVDPEuuWO/JE1IzhoIu5uNvEcSs5GmXc5Sjw=
github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d/go.mod h1:rhOAe/52S/J1fq1VnXvKX8FHuo65I+IcYUozW4M7+wE= github.com/ihexxa/multipart v0.0.0-20210916083128-8584a3f00d1d/go.mod h1:rhOAe/52S/J1fq1VnXvKX8FHuo65I+IcYUozW4M7+wE=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=

View file

@ -20,26 +20,25 @@ type Args struct {
Configs []string `short:"c" long:"configs" description:"config path"` Configs []string `short:"c" long:"configs" description:"config path"`
} }
// LoadCfg loads the default config, the config in database, config files and arguments in order.
// All config values will be merged into one, and the latter overwrites the former.
// Each config can be part of the whole ServerCfg
func LoadCfg(args *Args) (*gocfg.Cfg, error) { func LoadCfg(args *Args) (*gocfg.Cfg, error) {
defaultCfg, err := DefaultConfig() defaultCfg, err := DefaultConfig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
cfg, err := gocfg.New(NewConfig()).Load(gocfg.JSONStr(defaultCfg)) cfg, err := gocfg.New(NewConfig()).Load(gocfg.JSONStr(defaultCfg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
cfg, err = mergeConfigFiles(cfg, args.Configs) tmpCfg := *cfg
dbPath, err := getDbPath(&tmpCfg, args.Configs, args.DbPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = os.Stat(dbPath)
dbPath := cfg.GrabString("Db.DbPath")
if args.DbPath != "" {
dbPath = args.DbPath
_, err := os.Stat(dbPath)
if err == nil { if err == nil {
cfg, err = mergeDbConfig(cfg, dbPath) cfg, err = mergeDbConfig(cfg, dbPath)
if err != nil { if err != nil {
@ -52,6 +51,10 @@ func LoadCfg(args *Args) (*gocfg.Cfg, error) {
fmt.Printf("warning: Database does not exist in (%s), skipped", dbPath) fmt.Printf("warning: Database does not exist in (%s), skipped", dbPath)
} }
} }
cfg, err = mergeConfigFiles(cfg, args.Configs)
if err != nil {
return nil, err
} }
return mergeArgs(cfg, args) return mergeArgs(cfg, args)
@ -83,6 +86,31 @@ func mergeDbConfig(cfg *gocfg.Cfg, dbPath string) (*gocfg.Cfg, error) {
return cfg.Load(gocfg.JSONStr(cfgStr)) return cfg.Load(gocfg.JSONStr(cfgStr))
} }
// getDbPath returns db path from arguments, configs, default config in order
// this is a little tricky
func getDbPath(cfg *gocfg.Cfg, configPaths []string, argDbPath string) (string, error) {
if argDbPath != "" {
return argDbPath, nil
}
var err error
for _, configPath := range configPaths {
if strings.HasSuffix(configPath, ".yml") || strings.HasSuffix(configPath, ".yaml") {
cfg, err = cfg.Load(gocfg.YAML(configPath))
} else if strings.HasSuffix(configPath, ".json") {
cfg, err = cfg.Load(gocfg.JSON(configPath))
} else {
return "", fmt.Errorf("unknown config file type (.yml .yaml .json are supported): %s", configPath)
}
if err != nil {
return "", err
}
}
return cfg.GrabString("Db.DbPath"), nil
}
func mergeConfigFiles(cfg *gocfg.Cfg, configPaths []string) (*gocfg.Cfg, error) { func mergeConfigFiles(cfg *gocfg.Cfg, configPaths []string) (*gocfg.Cfg, error) {
var err error var err error

View file

@ -3,6 +3,7 @@ package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
"testing" "testing"
"github.com/ihexxa/gocfg" "github.com/ihexxa/gocfg"
@ -19,14 +20,28 @@ func TestLoadCfg(t *testing.T) {
DbPath: "", DbPath: "",
Configs: []string{}, Configs: []string{},
}, },
// default config + config_1 // default config + db
&Args{
Host: "",
Port: 0,
DbPath: "testdata/test_quickshare.db",
Configs: []string{},
},
// default config + db + config_1 (dbPath is from config_1)
&Args{ &Args{
Host: "", Host: "",
Port: 0, Port: 0,
DbPath: "", DbPath: "",
Configs: []string{"testdata/config_1.yml"}, Configs: []string{"testdata/config_1.yml"},
}, },
// default config + config_1 + config_4 // // default config + db + config_1 (dbPath is from args)
&Args{
Host: "",
Port: 0,
DbPath: "testdata/test_quickshare.db",
Configs: []string{"testdata/config_1.yml"},
},
// default config + db + config_1 + config_4
&Args{ &Args{
Host: "", Host: "",
Port: 0, Port: 0,
@ -45,7 +60,7 @@ func TestLoadCfg(t *testing.T) {
"testdata/config_partial_db.yml", "testdata/config_partial_db.yml",
}, },
}, },
// default config + config_1 + config_4 + db_partial + args(db) // default config + db + config_1 + config_4 + config_partial_users.yml + config_partial_db.yml + args(db)
&Args{ &Args{
Host: "", Host: "",
Port: 0, Port: 0,
@ -61,6 +76,21 @@ func TestLoadCfg(t *testing.T) {
cfgDefault := DefaultConfigStruct() cfgDefault := DefaultConfigStruct()
cfgDBOnly := *cfgDefault
cfgDBOnly.Site = &db.SiteConfig{
ClientCfg: &db.ClientConfig{
SiteName: "Quickshare",
SiteDesc: "quick and simple file sharing",
Bg: &db.BgConfig{
Url: "/static/img/textured_paper.png",
Repeat: "repeat",
Position: "center",
Align: "fixed",
BgColor: "#ccc",
},
},
}
cfg1 := &Config{ cfg1 := &Config{
Fs: &FSConfig{ Fs: &FSConfig{
Root: "1", Root: "1",
@ -111,19 +141,19 @@ func TestLoadCfg(t *testing.T) {
}, },
Site: &db.SiteConfig{ Site: &db.SiteConfig{
ClientCfg: &db.ClientConfig{ ClientCfg: &db.ClientConfig{
SiteName: "1", SiteName: "Quickshare",
SiteDesc: "1", SiteDesc: "quick and simple file sharing",
Bg: &db.BgConfig{ Bg: &db.BgConfig{
Url: "1", Url: "/static/img/textured_paper.png",
Repeat: "1", Repeat: "repeat",
Position: "1", Position: "center",
Align: "1", Align: "fixed",
BgColor: "1", BgColor: "#ccc",
}, },
}, },
}, },
Db: &DbConfig{ Db: &DbConfig{
DbPath: "1", DbPath: "testdata/test_quickshare.db",
}, },
} }
@ -259,7 +289,7 @@ func TestLoadCfg(t *testing.T) {
}, },
} }
cfgWithDB := &Config{ cfgWithPartialCfg := &Config{
Fs: &FSConfig{ Fs: &FSConfig{
Root: "4", Root: "4",
OpensLimit: 4, OpensLimit: 4,
@ -321,16 +351,18 @@ func TestLoadCfg(t *testing.T) {
}, },
}, },
Db: &DbConfig{ Db: &DbConfig{
DbPath: "testdata/test_quickshare.db", DbPath: "5",
}, },
} }
expects := []*Config{ expects := []*Config{
cfgDefault, cfgDefault,
&cfgDBOnly,
cfg1,
cfg1, cfg1,
cfg4, cfg4,
cfg5, cfg5,
cfgWithDB, cfgWithPartialCfg,
} }
testLoadCfg := func(t *testing.T) { testLoadCfg := func(t *testing.T) {
@ -351,7 +383,11 @@ func TestLoadCfg(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if !Equal(gotCfg, expectCfg) { if !reflect.DeepEqual(gotCfg.Template(), expectCfg.Template()) {
gotJSON, _ := gotCfg.JSON()
expectJSON, _ := expectCfg.JSON()
fmt.Printf("\ngot\n%s\n", gotJSON)
fmt.Printf("\nexpected\n%s\n", expectJSON)
t.Fatalf("%d, cfgs are not identical", i) t.Fatalf("%d, cfgs are not identical", i)
} }
} }

View file

@ -37,16 +37,16 @@ workers:
queueSize: 1 queueSize: 1
sleepCyc: 1 sleepCyc: 1
workerCount: 1 workerCount: 1
site: # site:
clientCfg: # clientCfg:
siteName: "1" # siteName: "1"
siteDesc: "1" # siteDesc: "1"
bg: # bg:
url: "1" # url: "1"
repeat: "1" # repeat: "1"
position: "1" # position: "1"
align: "1" # align: "1"
bgColor: "1" # bgColor: "1"
db: db:
dbPath: "1" dbPath: "testdata/test_quickshare.db"

Binary file not shown.