英文:
How to use dynamic location for godotenv.Load() .env file?
问题
问题
我正在使用Go构建一个REST API。使用godotenv包来加载环境变量。运行go run main.go
,项目按预期运行,环境变量被加载。
然而,当想要运行测试时,使用命令go test ./...
,其中包括运行config/config_test.go
,会抛出以下错误:Error loading .env file
(如函数中所指定)。
给定以下项目结构:
> app
> auth
> config
- config.go
- config_test.go
> migrations
> static
> vendor
- .env
- .gitignore
- docker-compose.yml
- go.mod
- go.sum
- main.go
- README.md
在config.go中,我使用以下函数来加载数据库配置。
func GetConfig() *Config {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_DATABASE")
dbUsername := os.Getenv("DB_USERNAME")
dbPassword := os.Getenv("DB_PASSWORD")
return &Config{
DB: &DBConfig{
Connection: "mysql",
Host: dbHost,
Port: dbPort,
Username: dbUsername,
Password: dbPassword,
Name: dbName,
Charset: "utf8",
},
}
}
我理解当从根目录运行时它可以工作,因为.env
位于根目录。当运行config/config_test.go
时,它会尝试在/config/.env
中查找.env
文件。如果我将这行代码更改为err := godotenv.Load("../.env")
,则config_test.go
可以成功运行,但是从根目录运行的go run main.go
将无法成功运行。
问题
如何在config.go
的GetConfig()
函数中动态加载.env
文件的位置,以便go test ./...
和go run main.go
都可以加载.env
文件?
编辑
我知道在我的应用程序中将path string
参数传递给GetConfig()
函数可以解决这个问题(我正在app包中初始化此配置)。然而,我想在不同目录中创建多个测试,并且不希望传递参数。有没有其他方法可以实现这一点?
英文:
Problem
I am building a REST API in Go. The godotenv package is used to load the environment variables. Running go run main.go
, the project runs the API as expected, the environment variables are loaded.
However, when wanting to run the test using: go test ./...
- which runs config/config_test.go
among others - it throws the following error: Error loading .env file
(as specified in function).
Given the following project structure:
> app
> auth
> config
- config.go
- config_test.go
> migrations
> static
> vendor
- .env
- .gitignore
- docker-compose.yml
- go.mod
- go.sum
- main.go
- README.md
In config.go, I use the following function to load the Database configuration.
func GetConfig() *Config {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_DATABASE")
dbUsername := os.Getenv("DB_USERNAME")
dbPassword := os.Getenv("DB_PASSWORD")
return &Config{
DB: &DBConfig{
Connection: "mysql",
Host: dbHost,
Port: dbPort,
Username: dbUsername,
Password: dbPassword,
Name: dbName,
Charset: "utf8",
},
}
}
I understand that it works when running from root, because the .env
resides in root. When running config/config_test.go
, it tries to look for the .env
file in the /config/.env
. If I change the line: err := godotenv.Load(".env")
to err := godotenv.Load("../.env")
, the config_test.go runs successfully, but the go run main.go
from root does not run successfully.
Question
How can I load the .env
location dynamically from the GetConfig()
function in config.go
, so that both the go test ./...
and go run main.go
can load the .env
?
Edit
I am aware that passing a path string
parameter to the GetConfig()
function would work in my application (I am initializing this config in the app package). However, I want to create multiple tests in different directories, and prefer not to pass a parameter. Is there another way to accomplish this?
答案1
得分: 10
根据@Inian的建议,我实现了以下解决方案,也在godotenv包的Issues标签页上列出。
在config.go中,我添加了一个目录名称的常量(在我的情况下是rest-api
)。我添加了一个loadEnv
函数,该函数尝试动态获取项目的根路径,基于项目名称和当前工作目录。
const projectDirName = "rest-api" // 更改为相关项目名称
func loadEnv() {
projectName := regexp.MustCompile(`^(.*` + projectDirName + `)`)
currentWorkDirectory, _ := os.Getwd()
rootPath := projectName.Find([]byte(currentWorkDirectory))
err := godotenv.Load(string(rootPath) + `/.env`)
if err != nil {
log.Fatalf("Error loading .env file")
}
}
func GetConfig() *Config {
loadEnv()
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_DATABASE")
dbUsername := os.Getenv("DB_USERNAME")
dbPassword := os.Getenv("DB_PASSWORD")
return &Config{
DB: &DBConfig{
Connection: "mysql",
Host: dbHost,
Port: dbPort,
Username: dbUsername,
Password: dbPassword,
Name: dbName,
Charset: "utf8",
},
}
}
以上是翻译好的内容,请确认是否满意。
英文:
Following the suggestion of @Inian, I implemented the following solution, also listed on the Issues
tab of the godotenv package.
In config.go I added a constant for the directory name (which is rest-api
in my case). I added a loadEnv
function that tries to get the root path of the project dynamically, based on the project name and the current working directory.
const projectDirName = "rest-api" // change to relevant project name
func loadEnv() {
projectName := regexp.MustCompile(`^(.*` + projectDirName + `)`)
currentWorkDirectory, _ := os.Getwd()
rootPath := projectName.Find([]byte(currentWorkDirectory))
err := godotenv.Load(string(rootPath) + `/.env`)
if err != nil {
log.Fatalf("Error loading .env file")
}
}
func GetConfig() *Config {
loadEnv()
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_DATABASE")
dbUsername := os.Getenv("DB_USERNAME")
dbPassword := os.Getenv("DB_PASSWORD")
return &Config{
DB: &DBConfig{
Connection: "mysql",
Host: dbHost,
Port: dbPort,
Username: dbUsername,
Password: dbPassword,
Name: dbName,
Charset: "utf8",
},
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论