Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reliably get the projects root in go?

Tags:

testing

go

For now I used runtime.Caller(0) in combination with path.Dir and filepath.Abs to get the path to the currently executed file and get the project root relative to it.

So lets say I've a folder structure like this:

$GOPATH/src/example.org/myproject
$GOPATH/src/example.org/myproject/main.go
$GOPATH/src/example.org/myproject/path
$GOPATH/src/example.org/myproject/path/loader.go

If I want my project root I call the loader.go which in turn gets its path with runtime.Caller(0) and then goes up one folder to reach the project root.

The problem is when using go test -cover the executed file is not in its normal place anymore but in a special sub directory for the testing and coverage analysis.
runtime.Caller(0) gives me the following:

example.org/myproject/path/_test/_obj_/loader.go

Running it through path.Dir and filepath.Abs will give me:

$GOPATH/src/example.org/myproject/path/example.org/myproject/path/_test/_obj_

When I go up from there I won't reach the project root but something totally different obviously. So my questions stands:
Is there any reliable way of getting the project root?

like image 697
SilentStorm Avatar asked Jul 21 '17 09:07

SilentStorm


People also ask

How do you get to the root directory of a project?

In order to get the root directory path, you can use _DIR_ or dirname(). echo dirname(__FILE__); Both the above syntaxes will return the same result.

How do you find the root path?

Type “echo %SYSTEMROOT%" at the command prompt and press “Enter.” The result of this search is the root folder for Microsoft Windows.

How do I find the root path in node JS?

At runtime node creates a registry of the full paths of all loaded files. The modules are loaded first, and thus at the top of this registry. By selecting the first element of the registry and returning the path before the 'node_modules' directory we are able to determine the root of the application.

How do you get a path in Golang?

Getwd functionis used to get the current working directory in Golang, the function returns the rooted path name and if the current directory can be reached via multiple paths, the function can return any one of them.


2 Answers

You can build it from the $GOPATH env variable:

gp := os.Getenv("GOPATH")
ap := path.Join(gp, "src/example.org/myproject")
fmt.Println(ap)

That will yield the absolute path to your paroject dir:

/path/to/gopath/src/example.org/myproject

This obviously only works when GOPATH is set. aka. on your dev machine. On production you need to supply directories via a config file.

like image 90
RickyA Avatar answered Oct 02 '22 14:10

RickyA


See this answer. In case you are using go ~ 1.8, func Executable() (string, error) is an option I stumbled over when I needed it. I tested briefly how it interacts with go test -cover and it seems to work fine:

func Executable() (string, error)

Executable returns the path name for the executable that started the current process. There is no guarantee that the path is still pointing to the correct executable. If a symlink was used to start the process, depending on the operating system, the result might be the symlink or the path it pointed to. If a stable result is needed, path/filepath.EvalSymlinks might help.

package main

import (
    "fmt"
    "os"
    "path"
)

func main() {
    e, err := os.Executable()
    if err != nil {
        panic(err)
    }
    path := path.Dir(e)
    fmt.Println(path)
}

The test:

binpath.go:

package binpath

import (
    "os"
    "path"
)

func getBinPath() string {
    e, err := os.Executable()
    if err != nil {
        panic(err)
    }
    path := path.Dir(e)
    return path
}

binpath_test.go:

package binpath

import (
    "fmt"
    "testing"
)

func TestGetBinPath(t *testing.T) {
    fmt.Println(getBinPath())
}

Results in something like /tmp/go-build465775039/github.com/tworabbits/binpath/_test

like image 26
tworabbits Avatar answered Oct 02 '22 13:10

tworabbits