Files
opencloud/vendor/github.com/gookit/goutil/envutil/dotenv.go
PC Kitty d97217f22c Update github.com/gookit/goutil to v0.7.4 for FreeBSD compatibility
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
2026-04-28 18:03:17 +02:00

199 lines
4.1 KiB
Go

package envutil
import (
"os"
"path/filepath"
"strings"
"github.com/gookit/goutil/internal/comfunc"
)
// DefaultEnvFile default file name
const DefaultEnvFile = ".env"
// Dotenv load and parse dotenv files
type Dotenv struct {
// Files dot env file paths, allow multi files.
// - filename support simple glob pattern. eg: ".env.*"
//
// default: [".env"]
Files []string
// BaseDir base dir for join files path
//
// default is workdir
BaseDir string
// UpperKey change key to upper on set ENV. default: true
UpperKey bool
// IgnoreNotExist only load exists.
//
// - default: false - will return error if not exists
IgnoreNotExist bool
// LoadFirstExist only load first exists env file on Files
LoadFirstExist bool
loadFiles []string
loadData map[string]string
}
// NewDotenv create a new dotenv config
func NewDotenv() *Dotenv {
return &Dotenv{
UpperKey: true,
Files: []string{DefaultEnvFile},
// init fields
loadData: make(map[string]string),
}
}
// LoadAndInit load dotenv files and parse to os.Environ
func (c *Dotenv) LoadAndInit() error {
return c.doLoadFiles(c.Files)
}
// LoadFiles append load dotenv files
// - filename support simple glob pattern. eg: ".env.*"
func (c *Dotenv) LoadFiles(files ...string) error {
return c.doLoadFiles(files)
}
// LoadText load dotenv contents and parse to os Env
func (c *Dotenv) LoadText(contents string) error {
return c.parseAndSetEnv(contents)
}
// do load dotenv files
func (c *Dotenv) doLoadFiles(files []string) error {
var filePath string
for _, file := range files {
filePath = strings.TrimSpace(file)
if c.BaseDir != "" && !filepath.IsAbs(file) {
filePath = filepath.Join(c.BaseDir, file)
}
// load and parse to ENV
if err := c.loadFile(filePath); err != nil {
return err
}
if c.LoadFirstExist && len(c.loadFiles) > 0 {
break
}
}
return nil
}
func (c *Dotenv) loadFile(filePath string) error {
// filename support simple glob pattern.
if strings.ContainsRune(filePath, '*') {
matches, err := filepath.Glob(filePath)
if err != nil {
return err
}
for _, matchFile := range matches {
if err = c.parseFile(matchFile); err != nil {
return err
}
}
return err
}
// Load single file
return c.parseFile(filePath)
}
// parseFile load single file and parse to ENV
func (c *Dotenv) parseFile(filePath string) error {
contents, err := os.ReadFile(filePath)
if err != nil {
// IgnoreNotExist: skip non-existent files
if c.IgnoreNotExist && os.IsNotExist(err) {
return nil
}
return err
}
err = c.parseAndSetEnv(string(contents))
if err == nil {
c.loadFiles = append(c.loadFiles, filePath)
}
return err
}
func (c *Dotenv) parseAndSetEnv(contents string) error {
// Parse ENV lines
envMp, err := comfunc.ParseEnvLines(contents, comfunc.ParseEnvLineOption{
SkipOnErrorLine: true,
})
// Set to ENV
for key, val := range envMp {
key = strings.ToUpper(key)
c.loadData[key] = val
_ = os.Setenv(key, val)
}
return err
}
// UnloadEnv remove loaded dotenv data from os.Environ
func (c *Dotenv) UnloadEnv() bool {
if len(c.loadData) == 0 {
return false
}
for key := range c.loadData {
_ = os.Unsetenv(key)
}
return true
}
// LoadedData get loaded dotenv data map
func (c *Dotenv) LoadedData() map[string]string {
return c.loadData
}
// LoadedFiles get loaded dotenv files
func (c *Dotenv) LoadedFiles() []string {
return c.loadFiles
}
// Reset unload all loaded ENV and reset data
func (c *Dotenv) Reset() {
c.UnloadEnv()
c.loadFiles = nil
c.loadData = make(map[string]string)
}
//
// region standard dotenv instance
//
var stdEnv = NewDotenv()
// StdDotenv get standard dotenv instance
func StdDotenv() *Dotenv { return stdEnv }
// DotenvLoad load dotenv file and parse to ENV
func DotenvLoad(fns ...func(cfg *Dotenv)) error {
for _, fn := range fns {
fn(stdEnv)
}
return stdEnv.LoadAndInit()
}
// LoadEnvFiles load dotenv files and parse to ENV
func LoadEnvFiles(baseDir string, files ...string) error {
return DotenvLoad(func(cfg *Dotenv) {
cfg.BaseDir = baseDir
if len(files) > 0 {
cfg.Files = files
}
})
}
// LoadedEnvFiles get loaded dotenv files
func LoadedEnvFiles() []string {
return stdEnv.LoadedFiles()
}