【问题标题】:How to get current GOPATH from code如何从代码中获取当前的 GOPATH
【发布时间】:2022-01-25 19:51:55
【问题描述】:

如何从代码块中获取当前的GOPATH

runtime 只有GOROOT

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
    s := gogetenv("GOROOT")
    if s != "" {
        return s
    }
    return defaultGoroot
}

我可以创建一个将GOROOT 替换为GOPATH 的函数,但是是否有用于此的内置函数?

【问题讨论】:

    标签: go


    【解决方案1】:

    使用os.Getenv

    来自文档:

    Getenv 检索由 钥匙。它返回值,如果变量不是,它将为空 现在。

    例子:

    package main
    
    import (
        "fmt"
        "os"
        )
    
    func main() {
        fmt.Println(os.Getenv("GOPATH"))
    }
    

    Go 1.8+ 更新

    Go 1.8 具有通过 go/build 导出的默认 GOPATH:

    package main
    
    import (
        "fmt"
        "go/build"
        "os"
    )
    
    func main() {
        gopath := os.Getenv("GOPATH")
        if gopath == "" {
            gopath = build.Default.GOPATH
        }
        fmt.Println(gopath)
    }
    

    【讨论】:

    • 在 go 1.8 中,GOPATH 环境变量是可选的。如果用户没有它怎么办?有没有办法获得默认的?我认为 go 运行时应该有办法获取 gopath,让 Go 自己为你解决。
    • @tothemario 我发布了一个答案,从 Go 1.8 开始你如何获得有效的GOPATH。但是,我同意理想情况下运行时应该提供一种获取用户GOPATH 的方法。
    • @tothemario 使用 Go 1.8 的默认 go 路径实现中的代码更新了答案。
    • 不要忘记 GOPATH 可以列出多个路径并由操作系统的路径分隔符分隔。
    【解决方案2】:

    你应该使用go/build 包。

    package main
    
    import (
        "fmt"
        "go/build"
    )
    
    func main() {
        fmt.Println(build.Default.GOPATH)
    }
    

    【讨论】:

      【解决方案3】:

      我今天因为我正在处理的事情而搞砸了,这比我预期的更烦人。最后,在我对其进行的各种测试(不是“严格”测试)中,这似乎对我有用。

      goPath := strings.Split(os.Getenv("GOPATH"), string(os.PathListSeparator))
      if len(goPath) == 0 {
          goPath = append(goPath, build.Default.GOPATH)
      } else if goPath[0] == "" {
          goPath[0] = build.Default.GOPATH
      }
      

      请注意,如果 GOPATH 上列出了多个路径,我决定只使用第一个路径,因为我怀疑很少会列出超过 1 个路径,第一个是 go get 放置源的位置(我猜)。此代码也没有考虑路径是否有效。

      还要注意,要在获取 GOPATH 后构建文件路径,我必须使用 path/filepath.Join() 而不是 path.Join()。如果第一个 arg 包含 \,则前者将在 windows 上使用 \,对于其他参数则使用 /。尽管 windows 显然可以接受 / 作为路径,但我所有的 PATH 和 GOPATH 类环境变量都是用 windows 的正常 \ 编写的。 path.Join() 使用 /,产生无效路径。

      【讨论】:

        【解决方案4】:

        从 Go 1.8 开始,有一个 default GOPATH:

        GOPATH 环境变量指定您的位置 工作区。它默认为您家中名为 go 的目录 目录,所以在 Unix 上是 $HOME/go,在计划 9 上是 $home/go,以及 Windows 上的%USERPROFILE%\go(通常是C:\Users\YourName\go)。

        这意味着GOPATH 环境变量不必设置为任何特定的值。

        您仍然可以使用os.Getenv 获取该值,但如果未设置,您需要确保使用特定于平台的默认值,例如使用mitchellh/go-homedir

        package main
        
        import (
                "fmt"
                "log"
                "os"
        
                "github.com/mitchellh/go-homedir"
        )
        
        func main() {
                p, err := gopath()
                if err != nil {
                        log.Fatalf("Error finding GOPATH: %v", err)
                }
        
                fmt.Println(p)
        }
        
        func gopath() (string, error) {
                s := os.Getenv("GOPATH")
                if s != "" {
                        return s, nil
                }
                return homedir.Expand("~/go")
        }
        

        【讨论】:

        • 这有点矫枉过正。我们可以使用 Go 自己的源代码中的代码来获取默认的 go 路径。见github.com/golang/go/blob/go1.8/src/go/build/build.go#L260-L277
        • @codefreak 当然有更简单的方法,你的答案也是有效的。我喜欢go-homedir 的地方在于,当有疑问时,它会尝试多种方法来查找主目录,如果都失败了,它实际上会返回一个错误。因此,此代码的用户可以返回有意义的错误消息。如果只返回一个空字符串,用户必须检查它是否为空。如果他们忽略这一点,这可能会在某些边缘情况下导致意外行为或奇怪的错误。
        • 问题的关键是找到 GOPATH,而不是主目录。 go-homedir 非常适合查找主目录。但是,如果 Go 本身使用 defaultGOPATH 函数,那么处理 Go 构建代码本身无法处理的边缘情况又有什么意义。无论如何,让我们让用户决定他们最喜欢什么:)
        猜你喜欢
        • 1970-01-01
        • 2010-10-08
        • 1970-01-01
        • 1970-01-01
        • 2022-11-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多