-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
297 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Dotenv | ||
|
||
Package `dotenv` that supports importing data from files (eg `.env`) to ENV | ||
|
||
## Usage | ||
|
||
```go | ||
err := dotenv.Load("./", ".env") | ||
// err := dotenv.LoadExists("./", ".env") | ||
|
||
val := dotenv.Get("ENV_KEY") | ||
// Or use | ||
// val := os.Getenv("ENV_KEY") | ||
|
||
// with default value | ||
val := dotenv.Get("ENV_KEY", "default value") | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
// Package dotnev provide load .env data to os ENV | ||
package dotnev | ||
|
||
import ( | ||
"bufio" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/gookit/ini/v2/parser" | ||
) | ||
|
||
var ( | ||
// UpperEnvKey change key to upper on set ENV | ||
UpperEnvKey = true | ||
|
||
// DefaultName default file name | ||
DefaultName = ".env" | ||
|
||
// OnlyLoadExists load on file exists | ||
OnlyLoadExists bool | ||
|
||
// save original Env data | ||
// originalEnv []string | ||
|
||
// cache all loaded ENV data | ||
loadedData = map[string]string{} | ||
) | ||
|
||
// LoadedData get all loaded data by dontenv | ||
func LoadedData() map[string]string { | ||
return loadedData | ||
} | ||
|
||
// ClearLoaded clear the previously set ENV value | ||
func ClearLoaded() { | ||
for key := range loadedData { | ||
_ = os.Unsetenv(key) | ||
} | ||
|
||
// reset | ||
loadedData = map[string]string{} | ||
} | ||
|
||
// DontUpperEnvKey dont change key to upper on set ENV | ||
func DontUpperEnvKey() { | ||
UpperEnvKey = false | ||
} | ||
|
||
// Load parse .env file data to os ENV. | ||
// Usage: | ||
// dotenv.Load("./", ".env") | ||
func Load(dir string, filenames ...string) (err error) { | ||
if len(filenames) == 0 { | ||
filenames = []string{DefaultName} | ||
} | ||
|
||
for _, filename := range filenames { | ||
file := filepath.Join(dir, filename) | ||
if err = loadFile(file); err != nil { | ||
break | ||
} | ||
} | ||
return | ||
} | ||
|
||
// LoadExists only load on file exists | ||
func LoadExists(dir string, filenames ...string) error { | ||
oldVal := OnlyLoadExists | ||
|
||
OnlyLoadExists = true | ||
err := Load(dir, filenames...) | ||
OnlyLoadExists = oldVal | ||
|
||
return err | ||
} | ||
|
||
// LoadFromMap load data from given string map | ||
func LoadFromMap(kv map[string]string) (err error) { | ||
for key, val := range kv { | ||
if UpperEnvKey { | ||
key = strings.ToUpper(key) | ||
} | ||
|
||
err = os.Setenv(key, val) | ||
if err != nil { | ||
break | ||
} | ||
|
||
// cache it | ||
loadedData[key] = val | ||
} | ||
return | ||
} | ||
|
||
// Get get os ENV value by name | ||
// | ||
// NOTICE: if is windows OS, os.Getenv() Key is not case sensitive | ||
func Get(name string, defVal ...string) (val string) { | ||
if UpperEnvKey { | ||
name = strings.ToUpper(name) | ||
} | ||
if val = loadedData[name]; val != "" { | ||
return | ||
} | ||
|
||
if val = os.Getenv(name); val != "" { | ||
return | ||
} | ||
|
||
if len(defVal) > 0 { | ||
val = defVal[0] | ||
} | ||
return | ||
} | ||
|
||
// Int get a int value by key | ||
func Int(name string, defVal ...int) (val int) { | ||
if str := os.Getenv(name); str != "" { | ||
val, err := strconv.ParseInt(str, 10, 0) | ||
if err == nil { | ||
return int(val) | ||
} | ||
} | ||
|
||
if len(defVal) > 0 { | ||
val = defVal[0] | ||
} | ||
return | ||
} | ||
|
||
// load and parse .env file data to os ENV | ||
func loadFile(file string) (err error) { | ||
// open file | ||
fd, err := os.Open(file) | ||
if err != nil { | ||
// skip not exist file | ||
if os.IsNotExist(err) && OnlyLoadExists { | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
//noinspection GoUnhandledErrorResult | ||
defer fd.Close() | ||
|
||
// parse file content | ||
s := bufio.NewScanner(fd) | ||
p := parser.NewSimpled(parser.NoDefSection) | ||
|
||
if _, err = p.ParseFrom(s); err != nil { | ||
return | ||
} | ||
|
||
// set data to os ENV | ||
if mp, ok := p.SimpleData()[p.DefSection]; ok { | ||
err = LoadFromMap(mp) | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package dotnev | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"runtime" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestLoad(t *testing.T) { | ||
err := Load("./testdata", "not-exist", ".env") | ||
assert.Error(t, err) | ||
|
||
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST")) | ||
|
||
err = Load("./testdata") | ||
assert.NoError(t, err) | ||
assert.Equal(t, "blog", os.Getenv("DONT_ENV_TEST")) | ||
assert.Equal(t, "blog", Get("DONT_ENV_TEST")) | ||
_ = os.Unsetenv("DONT_ENV_TEST") // clear | ||
|
||
err = Load("./testdata", "error.ini") | ||
assert.Error(t, err) | ||
|
||
err = Load("./testdata", "invalid_key.ini") | ||
assert.Error(t, err) | ||
|
||
assert.Equal(t, "def-val", Get("NOT-EXIST", "def-val")) | ||
|
||
ClearLoaded() | ||
} | ||
|
||
func TestLoadExists(t *testing.T) { | ||
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST")) | ||
|
||
err := LoadExists("./testdata", "not-exist", ".env") | ||
|
||
assert.NoError(t, err) | ||
assert.Equal(t, "blog", os.Getenv("DONT_ENV_TEST")) | ||
assert.Equal(t, "blog", Get("DONT_ENV_TEST")) | ||
ClearLoaded() | ||
} | ||
|
||
func TestLoadFromMap(t *testing.T) { | ||
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST")) | ||
|
||
err := LoadFromMap(map[string]string{ | ||
"DONT_ENV_TEST": "blog", | ||
"dont_env_test1": "val1", | ||
"dont_env_test2": "23", | ||
}) | ||
|
||
assert.NoError(t, err) | ||
|
||
envStr := fmt.Sprint(os.Environ()) | ||
assert.Contains(t, envStr, "DONT_ENV_TEST=blog") | ||
assert.Contains(t, envStr, "DONT_ENV_TEST1=val1") | ||
|
||
assert.Equal(t, "blog", Get("DONT_ENV_TEST")) | ||
assert.Equal(t, "blog", os.Getenv("DONT_ENV_TEST")) | ||
assert.Equal(t, "val1", Get("DONT_ENV_TEST1")) | ||
assert.Equal(t, 23, Int("DONT_ENV_TEST2")) | ||
|
||
// on windows, os.Getenv() not case sensitive | ||
if runtime.GOOS == "windows" { | ||
assert.Equal(t, "val1", Get("dont_env_test1")) | ||
assert.Equal(t, 23, Int("dont_env_test2")) | ||
} else { | ||
assert.Equal(t, "", Get("dont_env_test1")) | ||
assert.Equal(t, 0, Int("dont_env_test2")) | ||
} | ||
|
||
assert.Equal(t, 20, Int("dont_env_test1", 20)) | ||
assert.Equal(t, 20, Int("dont_env_not_exist", 20)) | ||
|
||
// check cache | ||
assert.Contains(t, LoadedData(), "DONT_ENV_TEST2") | ||
|
||
// clear | ||
ClearLoaded() | ||
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST")) | ||
assert.Equal(t, "", Get("DONT_ENV_TEST1")) | ||
|
||
err = LoadFromMap(map[string]string{ | ||
"": "val", | ||
}) | ||
assert.Error(t, err) | ||
} | ||
|
||
func TestDontUpperEnvKey(t *testing.T) { | ||
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST")) | ||
|
||
DontUpperEnvKey() | ||
|
||
err := LoadFromMap(map[string]string{ | ||
"dont_env_test": "val", | ||
}) | ||
|
||
assert.Contains(t, fmt.Sprint(os.Environ()), "dont_env_test=val") | ||
assert.NoError(t, err) | ||
assert.Equal(t, "val", Get("dont_env_test")) | ||
|
||
// on windows, os.Getenv() not case sensitive | ||
if runtime.GOOS == "windows" { | ||
assert.Equal(t, "val", Get("DONT_ENV_TEST")) | ||
} else { | ||
assert.Equal(t, "", Get("DONT_ENV_TEST")) | ||
} | ||
|
||
UpperEnvKey = true // revert | ||
ClearLoaded() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# comments | ||
DONT_ENV_TEST = "blog" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
DONT_ENV_TEST = | ||
df |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,7 +58,7 @@ some = change val | |
// panic(err) | ||
// } | ||
|
||
// Out: | ||
// Output: | ||
// get int | ||
// - val: 100 | ||
// get bool | ||
|