Skip to content

Commit

Permalink
refactor: Implement our own dotenv
Browse files Browse the repository at this point in the history
  • Loading branch information
GNITOAHC committed Jun 6, 2024
1 parent 36ff381 commit 7c92105
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 10 deletions.
87 changes: 87 additions & 0 deletions dotenv/dotenv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dotenv

import (
"bufio"
"errors"
"fmt"
"log/slog"
"os"
"regexp"
"strings"
)

func load(path string) error {
varRegexp := regexp.MustCompile(`\${([a-zA-Z0-9_]+)}`) // Match ${VAR}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()

// Read the file
scanner := bufio.NewScanner(file) // Create a scanner
envMap := make(map[string]string) // Map to store the environment variables
var line, k, v string // Variables to store the line, key and value

for scanner.Scan() {
line = scanner.Text()
if varRegexp.MatchString(line) {
// Check if the variable is defined (warn if not)
varName := varRegexp.FindString(line)[2 : len(varRegexp.FindString(line))-1]
if _, ok := envMap[varName]; !ok {
slog.Warn(fmt.Sprintf("Undefined variable: %s in line %s", varRegexp.FindString(line), line))
}
line = varRegexp.ReplaceAllStringFunc(line, func(s string) string {
return envMap[s[2:len(s)-1]]
})
}
// Parse the line
k, v, err = parse(line)
if err != nil {
return errors.New(fmt.Sprintf("Invalid line: %s", line))
}
if k == "" || v == "" { // Skip empty lines
continue
}
envMap[k] = v
}
// Set the environment variables
for k, v := range envMap {
os.Setenv(k, v)
}
return nil
}

func parse(line string) (string, string, error) {
s := strings.TrimSpace(line) // Trim the line
if strings.HasPrefix(s, "#") { // Check if the line is a comment
return "", "", nil
}
if !strings.Contains(s, "=") { // Check if the line is a key value pair
return "", "", errors.New("No '=' in line")
}
keyValuePair := regexp.MustCompile(`\s*=\s*`).Split(s, 2) // Split the line by the first '='
if len(keyValuePair) == 2 {
// Return key and value (remove comments if any)
value := strings.Split(keyValuePair[1], "#")[0]
// Remove quotes if any
if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") {
value = value[1 : len(value)-1]
}
return strings.TrimSpace(keyValuePair[0]), strings.TrimSpace(value), nil
}
return "", "", nil
}

func Load(paths ...string) error {
if len(paths) == 0 {
paths = append(paths, ".env")
}
for _, path := range paths {
err := load(path)
if err != nil {
return err
}
}
return nil
}
25 changes: 25 additions & 0 deletions dotenv/dotenv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dotenv

import (
"os"
"testing"
)

func TestDotenv(t *testing.T) {
err := Load("./env_test")
t.Log("DOTENV_TEST_VAR_FIRST:", os.Getenv("DOTENV_TEST_VAR_FIRST"))
t.Log("DOTENV_TEST:", os.Getenv("DOTENV_TEST"))
t.Log("DOTENV_TEST_WITH_QUOTE:", os.Getenv("DOTENV_TEST_WITH_QUOTE"))
t.Log("DOTENV_TEST_WITH_SPACE:", os.Getenv("DOTENV_TEST_WITH_SPACE"))
t.Log("DOTENV_TEST_WITH_VAR:", os.Getenv("DOTENV_TEST_WITH_VAR"))
if err != nil {
t.Error("Error loading .env file:", err)
} else {
t.Log("Success loading .env file")
}
}

func TestLogError(t *testing.T) {
err := Load("./env_test_error")
t.Log("Error:", err)
}
5 changes: 5 additions & 0 deletions dotenv/env_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DOTENV_TEST=testenv
DOTENV_TEST_WITH_QUOTE="testenv_withquote"
DOTENV_TEST_WITH_SPACE = "testenv_withspace"
VAR = var_here
DOTENV_TEST_WITH_VAR = test_withvar_${VAR}
6 changes: 6 additions & 0 deletions dotenv/env_test_error
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
VAR = var_here
VAR = var_here
VAR = var_here
VAR = var_here
VAR = var_here
DOTENV_ERROR error
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module past-papers-web

go 1.22.2

require github.com/joho/godotenv v1.5.1 // indirect
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
4 changes: 2 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"log"
"os"

"github.com/joho/godotenv"
"past-papers-web/dotenv"
)

type Config struct {
Expand All @@ -14,7 +14,7 @@ type Config struct {
}

func NewConfig() *Config {
err := godotenv.Load()
err := dotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
Expand Down
7 changes: 3 additions & 4 deletions internal/helper/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package helper
import (
b64 "encoding/base64"
"os"
"past-papers-web/internal/config"
"testing"

"github.com/joho/godotenv"
"past-papers-web/dotenv"
"past-papers-web/internal/config"
)

func TestUploadCombos(t *testing.T) {

err := godotenv.Load()
err := dotenv.Load("./.env") // Load .env under same directory
if err != nil {
t.Log("Error loading .env file")
}
Expand Down

0 comments on commit 7c92105

Please sign in to comment.