From c1bd0b788eef8e78b91b6e6f285c749527db31c2 Mon Sep 17 00:00:00 2001 From: "5684185+vsariola@users.noreply.github.com" <5684185+vsariola@users.noreply.github.com> Date: Tue, 20 May 2025 19:34:45 +0300 Subject: [PATCH] draft unified mechanisms for loading config files --- tracker/config.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tracker/config.go diff --git a/tracker/config.go b/tracker/config.go new file mode 100644 index 0000000..8f17f1a --- /dev/null +++ b/tracker/config.go @@ -0,0 +1,42 @@ +package tracker + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path/filepath" + + "gopkg.in/yaml.v2" +) + +func ReadConfig(embedFS embed.FS, path string, out any) (warning error) { + bytes := must(fs.ReadFile(embedFS, path)) // the file _must_ exist in the embedded fs; panic on purpose if not + if err := yaml.UnmarshalStrict(bytes, out); err != nil { + panic(err) // also, the embedded default config file _must_ be strictly valid yaml; panic if not + } + // now, try to read the user config file, overlapping the default one. + // Notice that the return values are just warnings - there's always the + // default config there so no harm done if the user config is missing or + // invalid. + configDir, err := os.UserConfigDir() + if err != nil { + return fmt.Errorf("ReadConfig %v: %v", path, err) + } + configPath := filepath.Join(configDir, "sointu", path) + bytesUser, err := os.ReadFile(configPath) + if err != nil { + return fmt.Errorf("ReadConfig %v: %v", path, err) + } + if err := yaml.Unmarshal(bytesUser, out); err != nil { + return fmt.Errorf("ReadConfig %v: %v", path, err) + } + return nil +} + +func must[T any](ic T, err error) T { + if err != nil { + panic(err) + } + return ic +}