RickyA
RickyA

Reputation: 16029

How to get current GOPATH from code

How do I get the current GOPATH from a block of code?

runtime only has 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
}

I could make a function that has GOROOT replaced with GOPATH, but is there a buildin for this?

Upvotes: 23

Views: 26605

Answers (4)

codefreak
codefreak

Reputation: 7141

Use os.Getenv

From docs:

Getenv retrieves the value of the environment variable named by the key. It returns the value, which will be empty if the variable is not present.

Example:

package main

import (
    "fmt"
    "os"
    )

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

Update for Go 1.8+

Go 1.8 has default GOPATH exported via go/build:

package main

import (
    "fmt"
    "go/build"
    "os"
)

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

Upvotes: 36

Benny Jobigan
Benny Jobigan

Reputation: 5309

I was messing with this today for something I am working on, and it was more annoying than I'd have expected. In the end, this seemed to work for me in the various tests I did on it (not 'rigorous' tests).

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
}

Note that I decided to use only the 1st path if multiple paths are listed on GOPATH, as I suspect few will have more than 1 path listed, and the first would be where go get puts the source (I guess). This code also does not account for if the paths are valid or not.

Also note that to build a file path after getting the GOPATH, I had to use path/filepath.Join() not path.Join(). The former will use \ on windows if the first arg contains \, and / for others. Although windows can accept / for paths apparently, all of my PATH and GOPATH-like environmental variables are written with the normal \ of windows. path.Join() used /, producing an invalid path.

Upvotes: 1

rhysd
rhysd

Reputation: 140

You should use go/build package.

package main

import (
    "fmt"
    "go/build"
)

func main() {
    fmt.Println(build.Default.GOPATH)
}

Upvotes: 14

tmh
tmh

Reputation: 1445

Since Go 1.8, there is a default GOPATH:

The GOPATH environment variable specifies the location of your workspace. It defaults to a directory named go inside your home directory, so $HOME/go on Unix, $home/go on Plan 9, and %USERPROFILE%\go (usually C:\Users\YourName\go) on Windows.

This means the GOPATH environment variable is not necessarily set to anything in particular.

You can still use os.Getenv to get the value, but in case it is not set you need to make sure that you use the the plattform-specific default value instead, for example using 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")
}

Upvotes: 0

Related Questions