43 lines
1.5 KiB
Go
43 lines
1.5 KiB
Go
// Package config provides a generic environment-variable + .env configuration
|
|
// loader. Each application defines its own configuration struct (with
|
|
// `env:"..."` tags) and calls Load to populate it. The framework owns only the
|
|
// loading mechanism, never the schema — so the two apps can have completely
|
|
// different configuration structs while sharing this loader.
|
|
package config
|
|
|
|
import (
|
|
"os"
|
|
|
|
"github.com/caarlos0/env/v11"
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
// Load populates dst from the process environment. A ".env" file in the working
|
|
// directory is loaded implicitly when present; passing a non-empty overrideFile
|
|
// (e.g. from a --env-file flag) loads that file instead. In either case godotenv
|
|
// never overwrites a variable already set in the real environment, so actual
|
|
// environment variables always take precedence over the file.
|
|
//
|
|
// Load returns an error rather than exiting; callers (typically a thin app-side
|
|
// wrapper) decide how to handle failure.
|
|
func Load[T any](overrideFile string, dst *T) error {
|
|
switch {
|
|
case overrideFile != "":
|
|
// Explicit override: the file is required, so a missing/unreadable file
|
|
// is an error.
|
|
if err := godotenv.Load(overrideFile); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
// Implicitly load ".env" when it exists. Its absence is not an error —
|
|
// the process environment may already carry everything.
|
|
if _, err := os.Stat(".env"); err == nil {
|
|
if err := godotenv.Load(".env"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return env.Parse(dst)
|
|
}
|