Files
summercms/modules/compass/env.go
Jakub Zych 5e50b166ef refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
2026-09-28 02:21:02 +02:00

125 lines
2.7 KiB
Go

package compass
import (
"fmt"
"os"
"strings"
"unicode"
"github.com/knadh/koanf/providers/env/v2"
"github.com/knadh/koanf/v2"
)
const envPrefix = "SUMMER_"
func loadEnvVars(k *koanf.Koanf, environ []string) error {
if k == nil {
return nil
}
return k.Load(env.Provider(".", env.Opt{
Prefix: envPrefix,
EnvironFunc: func() []string {
if environ == nil {
return []string{}
}
return environ
},
TransformFunc: transformSummerKey,
}), nil)
}
func transformSummerKey(key, value string) (string, any) {
if key == "SUMMER_ENV" {
return "", nil
}
rest, ok := strings.CutPrefix(key, envPrefix)
if !ok || rest == "" {
return "", nil
}
parts := strings.Split(rest, "__")
for i, part := range parts {
parts[i] = strings.ToLower(part)
}
return strings.Join(parts, "."), value
}
func readDotEnv(path string) ([]string, error) {
raw, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("compass: read .env: %w", err)
}
var out []string
for _, line := range strings.Split(string(raw), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
if after, ok := strings.CutPrefix(line, "export "); ok {
line = strings.TrimSpace(after)
}
key, val, ok := strings.Cut(line, "=")
if !ok {
continue
}
key = strings.TrimSpace(key)
if key == "" {
continue
}
val = strings.TrimSpace(val)
if len(val) >= 2 {
if (val[0] == '"' && val[len(val)-1] == '"') || (val[0] == '\'' && val[len(val)-1] == '\'') {
val = val[1 : len(val)-1]
}
}
out = append(out, key+"="+val)
}
return out, nil
}
func mergeEnviron(real, dotenv []string) []string {
present := make(map[string]struct{}, len(real))
out := make([]string, 0, len(real)+len(dotenv))
for _, kv := range real {
key, _, _ := strings.Cut(kv, "=")
present[key] = struct{}{}
out = append(out, kv)
}
for _, kv := range dotenv {
key, _, _ := strings.Cut(kv, "=")
if _, ok := present[key]; ok {
continue
}
out = append(out, kv)
}
return out
}
func lookupEnv(environ []string, key string) string {
for i := len(environ) - 1; i >= 0; i-- {
k, v, ok := strings.Cut(environ[i], "=")
if ok && k == key {
return v
}
}
return ""
}
func sanitizeEnv(env string) (string, error) {
if env == "" {
return "", fmt.Errorf("compass: environment name is empty")
}
if env == "." || env == ".." || strings.Contains(env, "..") || strings.ContainsAny(env, `/\`) {
return "", fmt.Errorf("compass: invalid environment name")
}
for _, r := range env {
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '-' || r == '_' {
continue
}
return "", fmt.Errorf("compass: invalid environment name")
}
return env, nil
}