Introduction to the
The twelve-Factor application advocates storing the configuration in environment variables. Anything that needs to be changed when you switch from development to production is extracted from the code into environment variables. However, in real development, setting environment variables is not practical if multiple projects are running on the same machine. The godotenv library reads the configuration from the. Env file and stores it in the program’s environment variables. It’s very convenient to use read in your code. Godotenv comes from dotenv, an open source Ruby project.
Quick to use
Third-party libraries need to be installed first:
$ go get github.com/joho/godotenv
Copy the code
After using:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main(a) {
err := godotenv.Load()
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("age: ", os.Getenv("age"))}Copy the code
Then add a. Env file in the same directory as the executable:
name = dj
age = 18
Copy the code
Run the program, output:
name: dj
age: 18
Copy the code
Visible, very convenient to use. By default, godotenv reads the. Env file in the root directory of the project, which uses the key = value format, one key/value pair per line. Godotenv.load () can be loaded, and os.getenv (“key”) can be read directly. Os.getenv is used to read environment variables:
package main
import (
"fmt"
"os"
)
func main(a) {
fmt.Println(os.Getenv("GOPATH"))}Copy the code
Advanced features
Automatic loading
If you’re lazy in the good tradition of programmers, you probably don’t even want to call the Load method yourself. Never mind, Godotenv gives you lazy power!
Import github.com/joho/godotenv/autoload, configuration will be read automatically:
package main
import (
"fmt"
"os"
_ "github.com/joho/godotenv/autoload"
)
func main(a) {
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("age: ", os.Getenv("age"))}Copy the code
Note that since the godotenv library is not explicitly used in the code, an empty import is used, that is, an _ is added before the package name.
The autoload library calls the Load method for you:
// src/github.com/joho/godotenv/autoload/autoload.go
package autoload
/* You can just read the .env file on import just by doing import _ "github.com/joho/godotenv/autoload" And bob's your mother's brother */
import "github.com/joho/godotenv"
func init(a) {
godotenv.Load()
}
Copy the code
Look carefully at the notes, programmer’s bad taste 😂!
Load a custom file
By default, the. Env file in the project root directory is loaded. Of course we can load files with any name, and files don’t have to end with. Env:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main(a) {
err := godotenv.Load("common"."dev.env")
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("version: ", os.Getenv("version"))
fmt.Println("database: ", os.Getenv("database"))}Copy the code
Contents of the common file:
Name = awesome Web version = 0.0.1Copy the code
Dev env:
database = sqlite
Copy the code
Production. Env:
database = mysql
Copy the code
Run it yourself and see the results!
Note: Load takes multiple file names as arguments, and if no file name is passed, the contents of the. Env file are read by default. If the same key exists in multiple files, the first one takes precedence and the second one does not take effect. So, what is the database output above?
annotation
Comments can be added to the.env file, starting with # and ending on the line.
# app name
name = awesome web
# current versionVersion = 0.0.1Copy the code
YAML
Env files can also be in YAML format:
Name: awesome Web Version: 0.0.1Copy the code
package main
import (
"fmt"
"os"
_ "github.com/joho/godotenv/autoload"
)
func main(a) {
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("version: ", os.Getenv("version"))}Copy the code
Environment variables are not stored
Godotenv allows you to not store the contents of a. Env file into an environment variable. Using godotenv.read () returns a map[string]string, which can be used directly:
package main
import (
"fmt"
"log"
"github.com/joho/godotenv"
)
func main(a) {
var myEnv map[string]string
myEnv, err := godotenv.Read()
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])}Copy the code
Direct operation map, simple and direct!
The data source
In addition to reading files, you can also read configurations from string from IO.Reader:
package main
import (
"fmt"
"log"
"github.com/joho/godotenv"
)
func main(a) {
content := 'name: awesome Web version: 0.0.1'
myEnv, err := godotenv.Unmarshal(content)
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])}Copy the code
As long as the IO.Reader interface is implemented, it can be used as a data source. Can be read from File (os.file), network (net.conn), bytes.buffer, and many other sources:
package main
import (
"bytes"
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main(a) {
file, _ := os.OpenFile(".env", os.O_RDONLY, 0666)
myEnv, err := godotenv.Parse(file)
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])
buf := &bytes.Buffer{}
buf.WriteString("name: awesome web @buffer")
buf.Write([]byte{'\n'})
buf.WriteString("version: 0.0.1")
myEnv, err = godotenv.Parse(buf)
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", myEnv["name"])
fmt.Println("version: ", myEnv["version"])}Copy the code
Note that the methods used to read from a string are different from those used to read from IO.Reader. The former is Unmarshal and the latter is Parse.
generate.env
file
Env files can be generated programmatically, and can be written directly to the file:
package main
import (
"bytes"
"log"
"github.com/joho/godotenv"
)
func main(a) {
buf := &bytes.Buffer{}
buf.WriteString("name = awesome web")
buf.WriteByte('\n')
buf.WriteString("version = 0.0.1")
env, err := godotenv.Parse(buf)
iferr ! =nil {
log.Fatal(err)
}
err = godotenv.Write(env, "./.env")
iferr ! =nil {
log.Fatal(err)
}
}
Copy the code
Check the generated. Env file:
name="awesome web"
version="0.0.1"
Copy the code
You can also return a string, which you can knead however you like:
package main
import (
"bytes"
"fmt"
"log"
"github.com/joho/godotenv"
)
func main(a) {
buf := &bytes.Buffer{}
buf.WriteString("name = awesome web")
buf.WriteByte('\n')
buf.WriteString("version = 0.0.1")
env, err := godotenv.Parse(buf)
iferr ! =nil {
log.Fatal(err)
}
content, err := godotenv.Marshal(env)
iferr ! =nil {
log.Fatal(err)
}
fmt.Println(content)
}
Copy the code
Command line mode
Godotenv also provides a command-line mode:
$ godotenv -f ./.env command args
Copy the code
$GOPATH/bin = $GOPATH/bin = $GOPATH/bin = godotenv;
The command line mode is to read the specified file (use the. Env file if not specified by -f), set the environment variables, and then run the following program.
Let’s write a simple program to verify:
package main
import (
"fmt"
"os"
)
func main(a) {
fmt.Println(os.Getenv("name"))
fmt.Println(os.Getenv("version"))}Copy the code
Run it with Godotenv:
$ godotenv -f ./.env go run main.go
Copy the code
Output:
Awesome web 0.0.1Copy the code
Multiple environments
In practice, different files are loaded based on the value of the APP_ENV environment variable:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main(a) {
env := os.Getenv("GODAILYLIB_ENV")
if env == "" {
env = "development"
}
err := godotenv.Load(".env." + env)
iferr ! =nil {
log.Fatal(err)
}
err = godotenv.Load()
iferr ! =nil {
log.Fatal(err)
}
fmt.Println("name: ", os.Getenv("name"))
fmt.Println("version: ", os.Getenv("version"))
fmt.Println("database: ", os.Getenv("database"))}Copy the code
We first read the environment variable GODAILYLIB_ENV, then the corresponding.env. + env, and finally the default.env file.
As mentioned earlier, the first read takes precedence. We can have the default. The foundation of the env file configuration information and some default values, if in development/test/production environment need to be modified, then the corresponding. Env. Development/env. The test/env. The production file configuration again.
.env file contents:
Name = awesome Web version = 0.0.1 database = fileCopy the code
. The env. Development:
database = sqlite3
Copy the code
. The env. Production:
database = mysql
Copy the code
Run the program:
The default is development environment$go run main.go name: awesome Web version: 0.0.1 database: sqlite3Set to build environment$GODAILYLIB_ENV=production go run main.go name: awesome Web version: 0.0.1 database: mysqlCopy the code
Point source
Godotenv reads the contents of the file, why can be accessed using os.getenv:
// src/github.com/joho/godotenv/godotenv.go
func loadFile(filename string, overload bool) error {
envMap, err := readFile(filename)
iferr ! =nil {
return err
}
currentEnv := map[string]bool{}
rawEnv := os.Environ()
for _, rawEnvLine := range rawEnv {
key := strings.Split(rawEnvLine, "=") [0]
currentEnv[key] = true
}
for key, value := range envMap {
if! currentEnv[key] || overload { os.Setenv(key, value) } }return nil
}
Copy the code
Because Godotenv calls os.setenv to set key-value pairs into environment variables.
conclusion
This article introduced the basic and advanced uses of the Godotenv library. Godotenv source code is also easier to read, there is time, interested in children’s shoes suggest a look ~
reference
- Godotenv GitHub Repository: github.com/joho/godote…
I
My blog
Welcome to follow my wechat public account [GoUpUp], learn together, progress together ~
This article is published by OpenWrite!