What is the correct setting for GOPATH? - go

I was trying to follow a tutorial on using aws with go. When I gave the command "go get github.com/aws/aws-sdk-go/aws", I still got failure to import. I was left wondering if the "go get" succeeded or not.
Following the guidance provided in the answers here, I updated my GOPATH variable and now the import succeeds.

Your hello.go should start something like this:
package main
import (
"github.com/aws/aws-sdk-go/aws"
)
See this example in the playground. So when importing a remote module use the full path in the import statement.
Re another question you asked in the comments (and I mentioned in comments to another of your questions) - go mod init initialises a module. See this article for information. When using modules, GOPATH is no longer used for resolving imports (see this article). So basically GOPATHis the old way of doing things; go modules is the new way (it solves a lot of issues but having the two approaches can be confusing to someone new to the language because some tutorials assume GOPATH and others use modules).
For completeness you have other questions about environmental variables. I think this may be due to a misunderstanding about how these work. When you enter export GOPATH=XXX in a terminal session that will update the environment within that session (that is that terminal window only; it will not have any impact on any other sessions you have open, including vscode). If you want to set a system wide environmental variable then you need to update a configuration file (often ~/.bashrc but this depends upon your OS see this article for info). After doing that restart the applications (or ideally youre PC) to pick up the new setting.

When you run go get github.com/aws/aws-sdk-go/aws; go tool will download the package into $GOPATH/src/github.com/aws/aws-sdk-go/aws directory.
That is why you need to import package by its full name (which is same as path to files under $GOPATH/src directory:
import "github.com/aws/aws-sdk-go/aws"
You can find more about how source code is organized under GOPATH and how imports work here and specifically about remote (github) imports here.
NOTE: GOPATH resolution works only when your project doesn't use modules (you don't have go.mod file). If you're following a tutorial and it doesn't mention use of modules above should work fine.

Related

managing hardcoded import paths

In Go, it is common that some packages are versioned. So a program might look like this:
package main
import (
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/glfw/v3.2/glfw"
)
// ... do stuff
Sometimes, I might want to update the version of glfw. Lets imagine GLFW 3.3 bindings come to Go and I want to update from 3.2.
I might have multiple Go files in a project all using glfw. I don't want to go into each of them and update the version of the import by hand. Ideally I wouldn't be copying that long path around, either, and I could define it in one place per project.
Maybe I could write a script to find+replace "github.com/go-gl/glfw/v3.2/glfw"
Maybe I could template the file with Genny
Maybe I could create a symlink inside the root Go path "glfw" -> "github.com/go-gl/glfw/v3.2/glfw", update it when changing version, and just use import "glfw"
but this information then lives "outside" the project, so no-one cloning my project knows what version to use
but this is a global change and I might have multiple projects which want to depend on different versions
Ideally I would be able to do something like this in each source file:
package main
import (
$gl
$glfw
)
And in some project-level dot file, something like:
gl=github.com/go-gl/gl/v3.3-core/gl
glfw=github.com/go-gl/glfw/v3.2/glfw
Or, a command-line argument attached to go build defining constants that could look something like:
go build -Dgl=github.com/go-gl/gl/v3.3-core/gl -Dglfw=github.com/go-gl/glfw/v3.2/glfw
How is everyone else handling this currently?
See github.com/golang/go/wiki/Modules for the recommended way of managing package versions.

What is the best local structure for Go open source repository development?

I'm trying to debug Go implementation of ethereum(link), because my core interest is in developing new consensus algorithm (i.e. modify the open source Go code from github).
However, I'm having problem with the location/path of the source code. When I put the folder(i.e. go-ethereum) outside of the $GOPATH and then try to compile&debug geth(go-ethereum/cmd/geth/main.go) it shows the following error: Use of internal package is not allowed.
From that error message, I figured out that the import github.com/ethereum/go-ethereum was not importing my source, and instead it was getting code from internet(like other libraries). Which of course is definitely what I shouldn't do when I'm trying to modify the github.com/ethereum/go-ethereum package code.
So, my workaround was to clone the source code into $GOPATH/src/github.com/ethereum/go-ethereum and followed this answer, and Goland IDE started compiling&debugging without error (wasn't able to go build ./cmd/geth/main.go though due to error undefined: configFileFlag...)
Thereby now I've got a working debugger that can debug with my source code modification, but this doesn't look like ideal source code structure.
The question is:
Is putting source code inside $GOPATH(because of internals) a proper approach? If so, what if I was using go-ethereum package from another project?(Fortunately I'm not, but I'm curious) Do I have to stash&revert changes I made to the code?
Yes, the folder structure you ended up with is the right one.
Code should be under $GOPATH/src as you describe.
But note that $GOPATH is not a fixed folder in your system, you can have multiple projects under different folders and change the value of $GOPATH accordingly depending what you are working on (or have multiple console terminals open, each with its own $GOPATH value).

What is the reason to have GOPATH set to my workspace?

I read everywhere that my GOPATH must be set to my workspace. If I do that and use go get to get packages from for example GitHub, they are all added to my workspace though, which I don't find particularly useful because it clutters my workspace. In my workspace I expect to find MY code and my code only.
So I now have my own repos in ~/repos/go and left my GOPATH to be the default ~/go. This works perfect. All libraries I import live in ~/go, which keeps my own workplace ~/repos/go nice and clean. This works great for me, so I'm not sure why this is not the recommended way of working.
Am I missing something? Are there things I break or are functionalities not working in this way?
Edit
To explain why my question is different from this question: I know what GOPATH does (define a place to put packages when using go get and a place to import packages from), but I was unaware of why you need to have the public code in the same place as your own code. Turns out there is no need for it, as explained by #peterSO in the (excellent) answer I accepted below.
go help gopath
Go searches each directory listed in GOPATH to find source code, but
new packages are always downloaded into the first directory in the
list.
$GOPATH is a directory list. For example, on Linux,
export GOPATH=$HOME/gopublic:$HOME/goprivate
go get places all downloads in the first directory in the list: $HOME/gopublic. Put all your packages in the second directory in the list: $HOME/goprivate.
GOPATH is a default directory that the golang toolchain looks at when you're attempting to compile code. It's not technically 100% necessary to set a custom one, as if I recall correctly, it defaults to ~/go/.
As peterSO said above, GOPATH is a list and puts packages into the first entry.

How to update imports when they change location

I see that in Go you can import packages directly from Github like:
import "github.com/MakeNowJust/heredoc"
I understand that the path I am seeing in import line is not an URL, but only the path the package is located in (normally relative to $GOROOT/src/pkg or $GOPATH/src). So the package heredoc is most probably located in the directory $GOPATH/src/github.com/MakeNowJust/heredoc.
Now let's say that the package developer decided to migrate the code repo to Bitbucket. So now the library URL is bitbucket.com/muchMoreCoolerName/heredoc. He also added some new features to the code repo.
My question is how will you get the updated code?
The only solution I can think of is changing all the imports to new URL and doing go get again. But changing the code for library update seems a little inconvenient.
If you just use go get and then import, there is no way around it, you will have to update the import paths to get the new code. However, if you use vendoring(a technique to keep your dependency with your code and also distribute it with them) you would be isolated from that move at least until you update. When you want to update, you could use a vendor functionality to keep the old import path but to sync with the other repo.
Frankly, I'd still use vendoring in anyway and just do a search and replace for the old import path when I decide to update, this is not that hard.
EDIT You can also use dep to manage dependencies if you haven't transitioned to modules yet.

Setting package path in Go

Getting started with Go and going through the docs here: https://golang.org/doc/code.html
The part entitled Package paths recommends using my Github account as a base path. However, with the forward slashes in the GH url, when I run mkdir -p $GOPATH/src/github.com/user it creates a sub-folder. So the example of github.com/user creates:
src/
github.com/
user/
but I don't think this is what's intended.
What can I do here?
The behavior is correct. The packages names in Go provide unique global name space.
github.com/user/repo therefore identifies a package, which is easily go get -able (download and install the package) and also provides much needed separation. You can also create packages without a hostname (in this case github.com) but effectively preventing users from using go get and resorting to manual management.
Having a username in GitHub case allows you to use forks of other libraries and maintain the separation. The full package name is then used for importing
import "github.com/user/repo"
This is actually the intended behavior,
You can even call go get on a github repo and it will create this same directory structure

Resources