Files
fn_registry/functions/infra/dotenv_load.go
T
egutierrez ebf246beb0 feat(infra): funciones impuras Go para carga de env/config (dotenv, env_require, config_from_env, config_from_file)
- dotenv_load: parser .env con no-sobreescritura y soporte de comillas
- env_require: os.Getenv con error descriptivo fail-fast
- env_require_all: verifica multiples vars y lista todas las faltantes
- config_from_env: reflection sobre struct tags env/default/required/secret, 5 tipos soportados
- config_from_file: JSON via stdlib, YAML stub con not-implemented
- 25 tests unitarios, todos PASS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 02:01:50 +02:00

74 lines
1.8 KiB
Go

package infra
import (
"bufio"
"fmt"
"os"
"strings"
)
// DotenvLoad parses a .env file and sets environment variables via os.Setenv.
// It does NOT overwrite variables that are already set in the environment.
//
// Parsing rules:
// - Lines starting with # (after trimming) are ignored as comments.
// - Blank lines are ignored.
// - Lines must follow the KEY=VALUE format.
// - Values may be optionally quoted with single or double quotes; quotes are stripped.
// - Inline comments (# after value) are NOT stripped — the raw value after = is used.
//
// Returns an error if the file cannot be opened or if a line has no '=' separator.
func DotenvLoad(path string) error {
f, err := os.Open(path)
if err != nil {
return fmt.Errorf("dotenv_load: open %q: %w", path, err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
lineNum := 0
for scanner.Scan() {
lineNum++
line := strings.TrimSpace(scanner.Text())
// skip blank lines and comments
if line == "" || strings.HasPrefix(line, "#") {
continue
}
idx := strings.IndexByte(line, '=')
if idx < 0 {
return fmt.Errorf("dotenv_load: %q line %d: missing '=' in %q", path, lineNum, line)
}
key := strings.TrimSpace(line[:idx])
val := line[idx+1:]
// strip surrounding quotes from value
val = stripQuotes(val)
// only set if not already present
if os.Getenv(key) == "" {
if err := os.Setenv(key, val); err != nil {
return fmt.Errorf("dotenv_load: setenv %q: %w", key, err)
}
}
}
if err := scanner.Err(); err != nil {
return fmt.Errorf("dotenv_load: scan %q: %w", path, err)
}
return nil
}
// stripQuotes removes surrounding single or double quotes from a string.
func stripQuotes(s string) string {
if len(s) >= 2 {
if (s[0] == '"' && s[len(s)-1] == '"') ||
(s[0] == '\'' && s[len(s)-1] == '\'') {
return s[1 : len(s)-1]
}
}
return s
}