2024-02-06 21:05:38 +01:00
|
|
|
// Copyright 2021-2022 - Offen Authors <hioffen@posteo.de>
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/joho/godotenv"
|
|
|
|
"github.com/offen/envconfig"
|
|
|
|
)
|
|
|
|
|
|
|
|
// envProxy is a function that mimics os.LookupEnv but can read values from any other source
|
|
|
|
type envProxy func(string) (string, bool)
|
|
|
|
|
|
|
|
func loadConfig(lookup envProxy) (*Config, error) {
|
|
|
|
envconfig.Lookup = func(key string) (string, bool) {
|
|
|
|
value, okValue := lookup(key)
|
|
|
|
location, okFile := lookup(key + "_FILE")
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case okValue && !okFile: // only value
|
|
|
|
return value, true
|
|
|
|
case !okValue && okFile: // only file
|
|
|
|
contents, err := os.ReadFile(location)
|
|
|
|
if err != nil {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
return string(contents), true
|
|
|
|
case okValue && okFile: // both
|
|
|
|
return "", false
|
|
|
|
default: // neither, ignore
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var c = &Config{}
|
|
|
|
if err := envconfig.Process("", c); err != nil {
|
2024-02-09 10:24:28 +01:00
|
|
|
return nil, fmt.Errorf("loadConfig: failed to process configuration values: %w", err)
|
2024-02-06 21:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return c, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadEnvVars() (*Config, error) {
|
|
|
|
return loadConfig(os.LookupEnv)
|
|
|
|
}
|
|
|
|
|
2024-02-09 10:24:28 +01:00
|
|
|
type configFile struct {
|
2024-02-13 15:43:04 +01:00
|
|
|
name string
|
|
|
|
config *Config
|
|
|
|
additionalEnvVars map[string]string
|
2024-02-09 10:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func loadEnvFiles(directory string) ([]configFile, error) {
|
2024-02-06 21:05:38 +01:00
|
|
|
items, err := os.ReadDir(directory)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-02-09 10:24:28 +01:00
|
|
|
return nil, fmt.Errorf("loadEnvFiles: failed to read files from env directory: %w", err)
|
2024-02-06 21:05:38 +01:00
|
|
|
}
|
|
|
|
|
2024-02-09 10:24:28 +01:00
|
|
|
cs := []configFile{}
|
2024-02-06 21:05:38 +01:00
|
|
|
for _, item := range items {
|
2024-02-09 10:24:28 +01:00
|
|
|
if item.IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
p := filepath.Join(directory, item.Name())
|
|
|
|
envFile, err := godotenv.Read(p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("loadEnvFiles: error reading config file %s: %w", p, err)
|
|
|
|
}
|
|
|
|
lookup := func(key string) (string, bool) {
|
|
|
|
val, ok := envFile[key]
|
2024-02-13 15:43:04 +01:00
|
|
|
if ok {
|
|
|
|
return val, ok
|
|
|
|
}
|
|
|
|
return os.LookupEnv(key)
|
2024-02-09 10:24:28 +01:00
|
|
|
}
|
|
|
|
c, err := loadConfig(lookup)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("loadEnvFiles: error loading config from file %s: %w", p, err)
|
2024-02-06 21:05:38 +01:00
|
|
|
}
|
2024-02-13 15:43:04 +01:00
|
|
|
cs = append(cs, configFile{config: c, name: item.Name(), additionalEnvVars: envFile})
|
2024-02-06 21:05:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return cs, nil
|
|
|
|
}
|