refac: removed 7 direct and 12 indirect go modules for custom code instead
This commit is contained in:
1 parent
cfcf108488
commit
c68e9a7858
73 files changed
+2455
-428
No files matched your search
@@ -0,0 +1,142 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
dotenvExportPrefix = "export "
|
||||
dotenvCommentMarker = "#"
|
||||
dotenvInlineComment = " #"
|
||||
dotenvByteOrderMark = "\xef\xbb\xbf"
|
||||
dotenvMaxLineBytes = 1 << 20
|
||||
dotenvAssignment = "="
|
||||
dotenvDoubleQuote = '"'
|
||||
dotenvSingleQuote = '\''
|
||||
dotenvEscapeBackslash = '\\'
|
||||
)
|
||||
|
||||
var dotenvDoubleQuoteEscapes = map[byte]byte{
|
||||
'n': '\n',
|
||||
'r': '\r',
|
||||
't': '\t',
|
||||
'"': '"',
|
||||
'\\': '\\',
|
||||
}
|
||||
|
||||
func LoadDotenv(path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
values, err := ParseDotenv(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", path, err)
|
||||
}
|
||||
for name, value := range values {
|
||||
if _, isSet := os.LookupEnv(name); !isSet {
|
||||
if err := os.Setenv(name, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseDotenv(reader io.Reader) (map[string]string, error) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
scanner.Buffer(make([]byte, 0, bufio.MaxScanTokenSize), dotenvMaxLineBytes)
|
||||
|
||||
values := map[string]string{}
|
||||
for lineNumber := 1; scanner.Scan(); lineNumber++ {
|
||||
line := strings.TrimSpace(strings.TrimPrefix(scanner.Text(), dotenvByteOrderMark))
|
||||
if line == "" || strings.HasPrefix(line, dotenvCommentMarker) {
|
||||
continue
|
||||
}
|
||||
name, value, err := parseDotenvAssignment(line)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("line %d: %w", lineNumber, err)
|
||||
}
|
||||
values[name] = value
|
||||
}
|
||||
return values, scanner.Err()
|
||||
}
|
||||
|
||||
func parseDotenvAssignment(line string) (string, string, error) {
|
||||
line = strings.TrimSpace(strings.TrimPrefix(line, dotenvExportPrefix))
|
||||
name, raw, found := strings.Cut(line, dotenvAssignment)
|
||||
name = strings.TrimSpace(name)
|
||||
if !found || !isDotenvName(name) {
|
||||
return "", "", fmt.Errorf("expected NAME=value")
|
||||
}
|
||||
value, err := parseDotenvValue(strings.TrimSpace(raw))
|
||||
return name, value, err
|
||||
}
|
||||
|
||||
func isDotenvName(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
for _, r := range name {
|
||||
isLetter := r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z'
|
||||
isDigit := r >= '0' && r <= '9'
|
||||
if !isLetter && !isDigit && r != '_' && r != '.' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func parseDotenvValue(raw string) (string, error) {
|
||||
if raw == "" {
|
||||
return "", nil
|
||||
}
|
||||
switch raw[0] {
|
||||
case dotenvDoubleQuote:
|
||||
return parseDoubleQuoted(raw)
|
||||
case dotenvSingleQuote:
|
||||
return parseSingleQuoted(raw)
|
||||
}
|
||||
if comment := strings.Index(raw, dotenvInlineComment); comment >= 0 {
|
||||
raw = raw[:comment]
|
||||
}
|
||||
return strings.TrimSpace(raw), nil
|
||||
}
|
||||
|
||||
func parseSingleQuoted(raw string) (string, error) {
|
||||
end := strings.IndexByte(raw[1:], dotenvSingleQuote)
|
||||
if end < 0 {
|
||||
return "", fmt.Errorf("unterminated single quote")
|
||||
}
|
||||
return raw[1 : 1+end], nil
|
||||
}
|
||||
|
||||
func parseDoubleQuoted(raw string) (string, error) {
|
||||
var value strings.Builder
|
||||
for i := 1; i < len(raw); i++ {
|
||||
switch raw[i] {
|
||||
case dotenvDoubleQuote:
|
||||
return value.String(), nil
|
||||
case dotenvEscapeBackslash:
|
||||
i++
|
||||
if i >= len(raw) {
|
||||
return "", fmt.Errorf("unterminated double quote")
|
||||
}
|
||||
if unescaped, known := dotenvDoubleQuoteEscapes[raw[i]]; known {
|
||||
value.WriteByte(unescaped)
|
||||
} else {
|
||||
value.WriteByte(dotenvEscapeBackslash)
|
||||
value.WriteByte(raw[i])
|
||||
}
|
||||
default:
|
||||
value.WriteByte(raw[i])
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("unterminated double quote")
|
||||
}
|
||||
Reference in new issue
Block a user