英文:
How to reliably get the projects root in go?
问题
现在我使用runtime.Caller(0)
与path.Dir
和filepath.Abs
结合使用,以获取当前执行文件的路径,并相对于该路径获取项目根目录。
假设我有以下文件夹结构:
$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
如果我想要获取项目根目录,我调用loader.go
,然后使用runtime.Caller(0)
获取其路径,然后向上一级文件夹到达项目根目录。
问题是,当使用go test -cover
时,执行的文件不再位于正常位置,而是位于一个特殊的子目录中,用于测试和覆盖分析。
runtime.Caller(0)
给我返回以下结果:
example.org/myproject/path/_test/_obj_/loader.go
通过path.Dir
和filepath.Abs
处理后,我得到:
$GOPATH/src/example.org/myproject/path/example.org/myproject/path/_test/_obj_
从那里向上一级,我将无法到达项目根目录,而是显然到达了完全不同的位置。所以我的问题是:
有没有可靠的方法来获取项目根目录?
英文:
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?
答案1
得分: 3
你可以使用$GOPATH
环境变量来构建它:
gp := os.Getenv("GOPATH")
ap := path.Join(gp, "src/example.org/myproject")
fmt.Println(ap)
这将返回你的项目目录的绝对路径:
/path/to/gopath/src/example.org/myproject
显然,这只在设置了GOPATH
时有效,也就是在你的开发机器上。在生产环境中,你需要通过配置文件提供目录。
英文:
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.
答案2
得分: 2
请看这个答案。如果你使用的是Go 1.8及以上版本,func Executable() (string, error)
是一个我在需要时偶然发现的选项。我简单测试了它与go test -cover
的交互方式,似乎工作正常:
> func Executable() (string, error)
>
> Executable返回启动当前进程的可执行文件的路径名。不能保证路径仍然指向正确的可执行文件。如果使用符号链接启动进程,根据操作系统的不同,结果可能是符号链接或它指向的路径。如果需要稳定的结果,可以使用path/filepath.EvalSymlinks。
package main
import (
"fmt"
"os"
"path"
)
func main() {
e, err := os.Executable()
if err != nil {
panic(err)
}
path := path.Dir(e)
fmt.Println(path)
}
测试代码:
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())
}
结果类似于/tmp/go-build465775039/github.com/tworabbits/binpath/_test
。
英文:
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
答案3
得分: 0
Abs 返回路径的绝对表示。如果路径不是绝对路径,则会与当前工作目录连接,将其转换为绝对路径。
absPath, err := filepath.Abs()
if err != nil {
panic("Ooops")
}
英文:
Abs returns an absolute representation of path. If the path is not absolute it will be joined with the current working directory to turn it into an absolute path
absPath, err := filepath.Abs()
if err != nil {
panic("Ooops)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论