Can't read .env file without absolute path - go

When I try to read the .env file it does not work without using the absolute path.
func init() {
err := godotenv.Load(".env") //<--fails
//err := godotenv.Load("./.env") //<--fails
//err := godotenv.Load("/home/peter/Documents/tests/configuration/.env") //<--works
if err != nil {
panic(err)
}
Config = GetConfig()
}
I get panic: open .env: no such file or directory
But the file is there
$ ls -a
. .. config.go .env
Any clue?

A potential problem is that the directory you are running the executable from is different than the directory of which the .env file is located. Could you verify this?

Related

How to use a config file while run compiled golang program

I build a go file using go build main.go. But this program is using a ini file, how do I use this file cause when I run ./main, I am getting this error:
2018/09/20 17:37:38 open config/config.ini: no such file or directory
2018/09/20 17:37:38 open config/config.ini: no such file or directory
panic: open config/config.ini: no such file or directory
goroutine 1 [running]:
log.Panic(0xc0000f7e98, 0x1, 0x1)
The code for using this file are:
func GetConfigFile() (*ini.File, error) {
f, err := ini.Load("config/config.ini")
if err != nil {
log.Println(err)
}
return f, err
}
It depends on where you run your program from. Read up on the concept of the current working directory, if you run your program from a console, the path is usually displayed at the start of the line. You use the relative path "config/config.ini" in your code which means that if you are currently in the directory /home/user then the file is expected to be at /home/user/config/config.ini.
You may want to either run your code from a different directory or use an absolute path in your code, e.g. /home/user/go/src/myapp/config/config.ini
Use absolute path like this :
func GetConfigFile() (*ini.File, error) {
f, err := ini.Load("/var/config/config.ini")
if err != nil {
log.Println(err)
}
return f, err
}

Getting error 'no such file or directory' when reading file in samba folder

I want to read the following test.html file. I have mounted it in my ubuntu 16.04 machine and I can access it.
But how can I read the file in go?
I get the error no such file or directory
url := `smb://192.168.32.114/test/test.html`
dat, err := ioutil.ReadFile(url)
if err != nil {
log.Println(err)
}

Go cannot find file specified

I'm trying to make simple read settings from config file. Both files - config.json and Settings.go, are in the same folder. But I'm always getting "The system cannot find the file specified." What I'm doing wrong?
func GetDbConnectionString() string {
file, err := os.Open("config.json")
if err != nil {
log.Fatal(err)
}
decoder := json.NewDecoder(file)
settings := Settings{}
err1 := decoder.Decode(&settings)
if err1 != nil {
fmt.Println("error:", err1)
}
log.Print(&settings)
return fmt.Sprintf("%s:%s#/%s", settings.login, settings.password, settings.database)
}
Your settings.json is not in the same directory as your main.go. If you invoke either go run main.go, or go build . && ./app, the current path will be .../app/ which does not contain the settings.json file.
Try copying your settings.json file to the same directory as your app, local invocation will work (it will still fail if you run from a separate directory though).

go test load files from root directory? [duplicate]

I'm writing some unit tests for my application in Go. The tests fail however because it cannot find the configuration files. Normally the binary looks for the configuration files in the working directory under the path conf/*.conf.
I figured that browsing to the directory that has conf/ and running go test in it would solve it, but it still reports that the file system cannot find the path specified.
How can I tell go test to use a certain directory as the working directory so that the tests may actually be executed?
You may be able to use the Caller to get the path to the current test source file, like this:
package sample
import (
"testing"
"runtime"
"fmt"
)
func TestGetFilename(t *testing.T) {
_, filename, _, _ := runtime.Caller(0)
t.Logf("Current test filename: %s", filename)
}
I do not believe this is possible. I have not been able to find documentation stating this explicitly, but I believe go test always uses the package directory (containing the go source files) as the working directory.
As a workaround, I compiled the test and execute the test from the current directory.
go test -c && ./<mypackage>.test
Or, if you want a generic command that you can use, you can rename the test file with -o option.
go test -c -o xyz.test && ./xyz.test
While not really convenient, you can always pass it as a command line variable, for example :
package blah_test
import (
"flag"
"fmt"
"os"
"testing"
)
var (
cwd_arg = flag.String("cwd", "", "set cwd")
)
func init() {
flag.Parse()
if *cwd_arg != "" {
if err := os.Chdir(*cwd_arg); err != nil {
fmt.Println("Chdir error:", err)
}
}
}
func TestBlah(t *testing.T) {
t.Errorf("cwd: %+q", *cwd_arg)
}
Then run it like :
┌─ oneofone#Oa [/tmp]
└──➜ go test . -cwd="$PWD"
--- FAIL: TestBlah (0.00 seconds)
blah_test.go:16: cwd: "/tmp"
No matter where the work directory is. It must be under your project Dir. So my solution is
wd, _ := os.Getwd()
for !strings.HasSuffix(wd, "<yourProjectDirName>") {
wd = filepath.Dir(wd)
}
raw, err := ioutil.ReadFile(fmt.Sprintf("%s/src/conf/conf.dev.json", wd))
Your path should always start from your project Dir. Every time you read the file in a package and accessed by main.go or your another package unit test. It will always work.
You can use the os package.
You would want to do something like this
func TestMyFunction(t *testing.T) {
os.Chdir("./path")
//TEST FUNCTION
os.Chdir("..")
}
There are several possibilities in the os package.
To add init function into *_test.go under your test package.
Test package will run this function before test function start.
func init() {
_, filename, _, _ := runtime.Caller(0)
// The ".." may change depending on you folder structure
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}
I know this is an old question but I had the same problem trying to use migrations for the database on my tests, and maybe this solution helps someone.
Since there is no native way of getting the project directory, you could identify some file or directory that you know it's only in the root of the project (in my case, it was the relative directory database/migrations). Once you have this unique relative directory, you could have a function like the following to obtain the project root directory. It just gets the current working directory (assuming it's inside the project's directory) and starts to navigate all the way up until it finds a dir that has the relative directory you know it's on the root of the project:
func FindMyRootDir() string {
workingDirectory, err := os.Getwd()
if err != nil {
panic(err)
}
lastDir := workingDirectory
myUniqueRelativePath := "database/migrations"
for {
currentPath := fmt.Sprintf("%s/%s", lastDir, myUniqueRelativePath)
fi, err := os.Stat(currentPath)
if err == nil {
switch mode := fi.Mode(); {
case mode.IsDir():
return currentPath
}
}
newDir := filepath.Dir(lastDir)
// Ooops, we couldn't find the root dir. Check that your "myUniqueRelativePath" really exists
if newDir == "/" || newDir == lastDir {
return ""
}
lastDir = newDir
}
}
Of course it's not the most beautiful solution, but it works.
I've had a similar problem and found the solution on this blog
Basically you can change the folder that the test is running using a similar function:
package main
import (
"os"
"path"
"runtime"
)
func MakeFunctionRunOnRootFolder() {
_, filename, _, _ := runtime.Caller(0)
// The ".." may change depending on you folder structure
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}
Go 1.20 is getting new -C arguments for "go subcommands" so this should help:
go test -C directory/ ...
It's a common practice in Go to place test fixtures in same package inside testdata folder.
Some examples from standard library:
debug/elf
net/http
image
Also, there is a post from Dave Cheney, where he suggests following code:
f, err := os.Open("testdata/somefixture.json")
I currently use a neat solution for this problem, instead of opening the file directly by calling os.Open(), I use the embed package in a smart way:
First I create a global variable in my root package called:
//go:embed config/* otherdirectories/*
var RootFS embed.FS
Then I just open the files inside my tests by using this global variable, e.g.:
func TestOpenConfig(t *testing.T) {
configFile, err := rootpkg.RootFS.ReadFile("config/env")
if err != nil {
t.Fatalf("unable to open config/env file: %s", err)
}
if string(configFile) != "FOO=bar\n" {
t.Fatalf("config file contents differ from expected: %s", string(configFile))
}
}
This is a neat trick because now you can always work with relative paths from your root package, which is what I used to do in other programming languages.
Of course, this has the restriction that you will need to import your root package, which depending on your package layout might not be ideal because of cyclic imports. If this is your case you might just create a embed.go file inside the config directory itself and call
your configs by name.
One other drawback is that you are embedding test files in your binary, this is probably ok if your test files are not very big, like megabytes big, so I don't really mind this issue.
I also created a repository for illustrating this solution:
https://github.com/VinGarcia/golang-reading-files-from-tests
I would use an Environment Variable for the location of your application. It seems to be the best way when running go tools, as test programs can be run from a temporary location.
// get home dir of app, use MYAPPHOME env var if present, else executable dir.
func exeDir() string {
dir, exists := os.LookupEnv("MYAPPHOME")
if exists {
return dir
} else {
ex, err := os.Executable()
if err != nil {
panic(err)
}
exPath := path.Dir(ex)
return exPath
}
}

How to specify the file location for `template.ParseFiles` in Go Language?

After I watched this video, I try it myself. However, I get the panic error panic: open templates/index.html: The system cannot find the path specified. The Complete erroe message is like the following.
Hello, Go Web Development 1.3
panic: open templates/index.html: The system cannot find the path specified.
goroutine 1 [running]:
panic(0x789260, 0xc082054e40)
F:/Go/src/runtime/panic.go:481 +0x3f4
html/template.Must(0x0, 0xe34538, 0xc082054e40, 0x0)
F:/Go/src/html/template/template.go:340 +0x52
main.main()
E:/Users/User/Desktop/codespace/go_workspace/src/go-for-web-dev/src/1.3_UsingTemplate.go:11 +0x20d
I have tried different string like "templates/index.html", "index.html", "./template/index.html"... Also, I try to copy the entire template folder into pkg, bin...But I get the same error message.
The following is the go program (1.3_UsingTemplate.go).
package src
import (
"fmt"
"net/http"
"html/template"
)
func main() {
fmt.Println("Hello, Go Web Development 1.3")
templates := template.Must(template.ParseFiles("templates/index.html")) //This line should have some problem
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if err := templates.ExecuteTemplate(w, "index.html", nil); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
fmt.Println(http.ListenAndServe(":8080",nil))
}
File Structure
Update
To solve this problem, I need to first change the current working directory to the folder containing the *.go file. Then, execute go run {filename.go}. In GoClipse, is there any setting can be set to the Run Configurations for automatically changing the current working directory to the folder containing the *.go file?
os.Getwd() can be used to return the root working directory of your project and then concatenate with the inner path of your template file:
// Working Directory
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
// Template
tpl, err := template.ParseFiles(wd + "/templates/index.html")
You specified a path relative to the current working directory. This directory may not have any relationship with the directory containing the source code.
Change directory to E:/Users/User/Desktop/codespace/go_workspace/src/go-for-web-dev/src to run your program. The path to the template is relative to this directory.

Resources