From 2f6aa3310853beb53f075c86ea8af2059c8c5ae8 Mon Sep 17 00:00:00 2001 From: hexxa Date: Sat, 2 Apr 2022 15:38:59 +0800 Subject: [PATCH] fix(configs): refactor config loader to read default, db, configs, args in order --- go.mod | 2 +- go.sum | 4 ++ src/server/config_load.go | 64 +++++++++++++++++------- src/server/config_load_test.go | 66 +++++++++++++++++++------ src/server/testdata/config_1.yml | 22 ++++----- src/server/testdata/test_quickshare.db | Bin 524288 -> 131072 bytes 6 files changed, 113 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index 716a6a7..176b20e 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gin-gonic/gin v1.7.3 github.com/go-playground/validator/v10 v10.9.0 // 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/jessevdk/go-flags v1.4.0 github.com/json-iterator/go v1.1.11 // indirect diff --git a/go.sum b/go.sum index bd5490a..26e7005 100644 --- a/go.sum +++ b/go.sum @@ -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/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-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/go.mod h1:rhOAe/52S/J1fq1VnXvKX8FHuo65I+IcYUozW4M7+wE= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= diff --git a/src/server/config_load.go b/src/server/config_load.go index 95aefd1..a14446a 100644 --- a/src/server/config_load.go +++ b/src/server/config_load.go @@ -20,38 +20,41 @@ type Args struct { 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) { defaultCfg, err := DefaultConfig() if err != nil { return nil, err } - cfg, err := gocfg.New(NewConfig()).Load(gocfg.JSONStr(defaultCfg)) if err != nil { return nil, err } - cfg, err = mergeConfigFiles(cfg, args.Configs) + tmpCfg := *cfg + dbPath, err := getDbPath(&tmpCfg, args.Configs, args.DbPath) if err != nil { return nil, err } - - dbPath := cfg.GrabString("Db.DbPath") - if args.DbPath != "" { - dbPath = args.DbPath - _, err := os.Stat(dbPath) - if err == nil { - cfg, err = mergeDbConfig(cfg, dbPath) - if err != nil { - return nil, err - } - } else if err != nil { - if !os.IsNotExist(err) { - return nil, err - } else { - fmt.Printf("warning: Database does not exist in (%s), skipped", dbPath) - } + _, err = os.Stat(dbPath) + if err == nil { + cfg, err = mergeDbConfig(cfg, dbPath) + if err != nil { + return nil, err } + } else if err != nil { + if !os.IsNotExist(err) { + return nil, err + } else { + 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) @@ -83,6 +86,31 @@ func mergeDbConfig(cfg *gocfg.Cfg, dbPath string) (*gocfg.Cfg, error) { 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) { var err error diff --git a/src/server/config_load_test.go b/src/server/config_load_test.go index 8d2a373..d1bc726 100644 --- a/src/server/config_load_test.go +++ b/src/server/config_load_test.go @@ -3,6 +3,7 @@ package server import ( "encoding/json" "fmt" + "reflect" "testing" "github.com/ihexxa/gocfg" @@ -19,14 +20,28 @@ func TestLoadCfg(t *testing.T) { DbPath: "", 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{ Host: "", Port: 0, DbPath: "", 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{ Host: "", Port: 0, @@ -45,7 +60,7 @@ func TestLoadCfg(t *testing.T) { "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{ Host: "", Port: 0, @@ -61,6 +76,21 @@ func TestLoadCfg(t *testing.T) { 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{ Fs: &FSConfig{ Root: "1", @@ -111,19 +141,19 @@ func TestLoadCfg(t *testing.T) { }, Site: &db.SiteConfig{ ClientCfg: &db.ClientConfig{ - SiteName: "1", - SiteDesc: "1", + SiteName: "Quickshare", + SiteDesc: "quick and simple file sharing", Bg: &db.BgConfig{ - Url: "1", - Repeat: "1", - Position: "1", - Align: "1", - BgColor: "1", + Url: "/static/img/textured_paper.png", + Repeat: "repeat", + Position: "center", + Align: "fixed", + BgColor: "#ccc", }, }, }, Db: &DbConfig{ - DbPath: "1", + DbPath: "testdata/test_quickshare.db", }, } @@ -259,7 +289,7 @@ func TestLoadCfg(t *testing.T) { }, } - cfgWithDB := &Config{ + cfgWithPartialCfg := &Config{ Fs: &FSConfig{ Root: "4", OpensLimit: 4, @@ -321,16 +351,18 @@ func TestLoadCfg(t *testing.T) { }, }, Db: &DbConfig{ - DbPath: "testdata/test_quickshare.db", + DbPath: "5", }, } expects := []*Config{ cfgDefault, + &cfgDBOnly, + cfg1, cfg1, cfg4, cfg5, - cfgWithDB, + cfgWithPartialCfg, } testLoadCfg := func(t *testing.T) { @@ -351,7 +383,11 @@ func TestLoadCfg(t *testing.T) { 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) } } diff --git a/src/server/testdata/config_1.yml b/src/server/testdata/config_1.yml index 62adaf6..5ece387 100644 --- a/src/server/testdata/config_1.yml +++ b/src/server/testdata/config_1.yml @@ -37,16 +37,16 @@ workers: queueSize: 1 sleepCyc: 1 workerCount: 1 -site: - clientCfg: - siteName: "1" - siteDesc: "1" - bg: - url: "1" - repeat: "1" - position: "1" - align: "1" - bgColor: "1" +# site: +# clientCfg: +# siteName: "1" +# siteDesc: "1" +# bg: +# url: "1" +# repeat: "1" +# position: "1" +# align: "1" +# bgColor: "1" db: - dbPath: "1" + dbPath: "testdata/test_quickshare.db" diff --git a/src/server/testdata/test_quickshare.db b/src/server/testdata/test_quickshare.db index f6e39d2b8d2d2ab05bfe78b9cc070a3e53c1758b..86346ce90d9b5d4b64fcb174cb34dcc4390c3e7f 100644 GIT binary patch literal 131072 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 literal 524288 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