basic common app packages
This commit is contained in:
101
dotenv/read.go
Normal file
101
dotenv/read.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package dotenv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//
|
||||
// ported from https://github.com/joho/godotenv/blob/main/godotenv.go
|
||||
//
|
||||
|
||||
// Read all env (with same file loading semantics as Load) but return values as
|
||||
// a map rather than automatically writing values into env
|
||||
func Read(dir string, filenames ...string) (envMap map[string]string, err error) {
|
||||
filenames = filenamesOrDefault(filenames)
|
||||
envMap = make(map[string]string)
|
||||
|
||||
for _, filename := range filenames {
|
||||
slog.Info("read .env", slog.String("file", filepath.Join(dir, filename)))
|
||||
individualEnvMap, individualErr := readFile(filepath.Join(dir, filename))
|
||||
|
||||
if individualErr != nil {
|
||||
err = individualErr
|
||||
return
|
||||
}
|
||||
|
||||
maps.Copy(envMap, individualEnvMap)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LoadFile env file value to app env
|
||||
//
|
||||
// overload = true will replace env value even if they already there in process env
|
||||
func LoadFile(filename string, overload bool) error {
|
||||
envMap, err := readFile(filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
slog.Info(".env not found", slog.String("file", filename))
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
currentEnv := map[string]bool{}
|
||||
rawEnv := os.Environ()
|
||||
for _, rawEnvLine := range rawEnv {
|
||||
key := strings.Split(rawEnvLine, "=")[0]
|
||||
currentEnv[key] = true
|
||||
}
|
||||
|
||||
for key, value := range envMap {
|
||||
if !currentEnv[key] || overload {
|
||||
_ = os.Setenv(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func filenamesOrDefault(filenames []string) []string {
|
||||
if len(filenames) == 0 {
|
||||
return []string{".env"}
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
func readFile(filename string) (envMap map[string]string, err error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return parse(file)
|
||||
}
|
||||
|
||||
// parse reads an env file from io.Reader, returning a map of keys and values.
|
||||
func parse(r io.Reader) (map[string]string, error) {
|
||||
var buf bytes.Buffer
|
||||
_, err := io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unmarshal(buf.Bytes())
|
||||
}
|
||||
|
||||
// unmarshal parses env file from byte slice of chars, returning a map of keys and values.
|
||||
func unmarshal(src []byte) (map[string]string, error) {
|
||||
out := make(map[string]string)
|
||||
err := parseBytes(src, out)
|
||||
|
||||
return out, err
|
||||
}
|
Reference in New Issue
Block a user