2026-07-07 18:05:02 +08:00

101 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package configx
import (
"bufio"
"errors"
"os"
"strings"
"gopkg.in/yaml.v3"
)
// LoadYAML 把指定 YAML 文件反序列化到已有配置对象里。
// 调用方通常会先准备一个带默认值的 struct再让 YAML 局部覆盖它。
func LoadYAML(path string, out any) error {
body, err := os.ReadFile(path)
if err != nil {
return err
}
return yaml.Unmarshal(body, out)
}
// LoadYAMLWithEnv 只展开 ${NAME} 形式的环境变量;普通 $ 字符保留,避免误伤密钥正文。
func LoadYAMLWithEnv(path string, out any) error {
body, err := os.ReadFile(path)
if err != nil {
return err
}
return yaml.Unmarshal([]byte(expandBraceEnv(string(body))), out)
}
// LoadDotEnvFile 读取本地运行时 .env 文件;真实环境变量优先,文件里的值只补本地缺省。
func LoadDotEnvFile(path string) error {
file, err := os.Open(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
key, value, ok := parseDotEnvLine(scanner.Text())
if !ok {
continue
}
if _, exists := os.LookupEnv(key); exists {
continue
}
if err := os.Setenv(key, value); err != nil {
return err
}
}
return scanner.Err()
}
func parseDotEnvLine(line string) (string, string, bool) {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
return "", "", false
}
line = strings.TrimPrefix(line, "export ")
key, value, ok := strings.Cut(line, "=")
if !ok {
return "", "", false
}
key = strings.TrimSpace(key)
if key == "" {
return "", "", false
}
value = strings.TrimSpace(value)
if len(value) >= 2 {
quote := value[0]
if (quote == '"' || quote == '\'') && value[len(value)-1] == quote {
value = value[1 : len(value)-1]
}
}
return key, value, true
}
func expandBraceEnv(input string) string {
var builder strings.Builder
for i := 0; i < len(input); {
if input[i] == '$' && i+1 < len(input) && input[i+1] == '{' {
end := strings.IndexByte(input[i+2:], '}')
if end >= 0 {
key := input[i+2 : i+2+end]
builder.WriteString(os.Getenv(key))
i += end + 3
continue
}
}
builder.WriteByte(input[i])
i++
}
return builder.String()
}