Merge pull request #3587 from wkloucek/single-config-file-location

load configuration only from one directory
This commit is contained in:
Willy Kloucek
2022-04-26 15:28:17 +02:00
committed by GitHub
11 changed files with 95 additions and 91 deletions
+37 -4
View File
@@ -10,16 +10,16 @@ const ()
var (
// switch between modes
BaseDataPathType = "homedir"
// don't read from this, only write
BaseDataPathType = "homedir" // or "path"
// default data path
BaseDataPathValue = "/var/lib/ocis"
)
func BaseDataPath() string {
// It is not nice to have hidden / secrete configuration options
// But how can we update the base path for every occurence with a flageset option?
// This is currenlty not possible and needs a new configuration concept
// But how can we update the base path for every occurrence with a flagset option?
// This is currently not possible and needs a new configuration concept
p := os.Getenv("OCIS_BASE_DATA_PATH")
if p != "" {
return p
@@ -40,3 +40,36 @@ func BaseDataPath() string {
return ""
}
}
var (
// switch between modes
BaseConfigPathType = "homedir" // or "path"
// default config path
BaseConfigPathValue = "/etc/ocis"
)
func BaseConfigPath() string {
// It is not nice to have hidden / secrete configuration options
// But how can we update the base path for every occurrence with a flagset option?
// This is currently not possible and needs a new configuration concept
p := os.Getenv("OCIS_CONFIG_DIR")
if p != "" {
return p
}
switch BaseConfigPathType {
case "homedir":
dir, err := os.UserHomeDir()
if err != nil {
// fallback to BaseConfigPathValue for users without home
return BaseConfigPathValue
}
return path.Join(dir, ".ocis", "config")
case "path":
return BaseConfigPathValue
default:
log.Fatalf("BaseConfigPathType %s not found", BaseConfigPathType)
return ""
}
}
+10 -66
View File
@@ -1,87 +1,31 @@
package config
import (
"io/fs"
"os"
"path/filepath"
"strings"
"path"
gofig "github.com/gookit/config/v2"
gooyaml "github.com/gookit/config/v2/yaml"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
var (
defaultLocations = []string{
filepath.Join(os.Getenv("HOME"), "/.ocis/config/"),
"/etc/ocis/",
".config/",
}
// supportedExtensions is determined by gookit/config.
supportedExtensions = []string{
"yaml",
"yml",
}
// decoderConfigTagname sets the tag name to be used from the config structs
// currently we only support "yaml" because we only support config loading
// from yaml files and the yaml parser has no simple way to set a custom tag name to use
decoderConfigTagName = "yaml"
)
// DefaultConfigSources returns a slice with matched expected config files. It sugars coat several aspects of config file
// management by assuming there are 3 default locations a config file could be.
// It uses globbing to match a config file by name, and retrieve any supported extension supported by our drivers.
// It sanitizes the output depending on the list of drivers provided.
func DefaultConfigSources(filename string, drivers []string) []string {
var sources []string
locations := []string{}
if v := os.Getenv("OCIS_CONFIG_DIR"); v != "" {
locations = append(locations, v)
// only use the configured config dir
locations = append(locations, os.Getenv("OCIS_CONFIG_DIR"))
} else {
// merge config from all default locations
locations = append(locations, defaultLocations...)
}
for i := range locations {
dirFS := os.DirFS(locations[i])
pattern := filename + ".*"
matched, _ := fs.Glob(dirFS, pattern)
if len(matched) > 0 {
// prepend path to results
for j := 0; j < len(matched); j++ {
matched[j] = filepath.Join(locations[i], matched[j])
}
}
sources = append(sources, matched...)
}
return sanitizeExtensions(sources, drivers, func(a, b string) bool {
return strings.HasSuffix(filepath.Base(a), b)
})
}
// sanitizeExtensions removes elements from "set" which extensions are not in "ext".
func sanitizeExtensions(set []string, ext []string, f func(a, b string) bool) []string {
var r []string
for i := 0; i < len(set); i++ {
for j := 0; j < len(ext); j++ {
if f(filepath.Base(set[i]), ext[j]) {
r = append(r, set[i])
}
}
}
return r
}
// BindSourcesToStructs assigns any config value from a config file / env variable to struct `dst`. Its only purpose
// is to solely modify `dst`, not dealing with the config structs; and do so in a thread safe manner.
func BindSourcesToStructs(extension string, dst interface{}) (*gofig.Config, error) {
sources := DefaultConfigSources(extension, supportedExtensions)
cnf := gofig.NewWithOptions(extension)
cnf.WithOptions(func(options *gofig.Options) {
options.DecoderConfig.TagName = "yaml"
options.DecoderConfig.TagName = decoderConfigTagName
})
cnf.AddDriver(gooyaml.Driver)
_ = cnf.LoadFiles(sources...)
cfgFile := path.Join(defaults.BaseConfigPath(), extension+".yaml")
_ = cnf.LoadFiles([]string{cfgFile}...)
err := cnf.BindStruct("", &dst)
if err != nil {