Is it true that GOPATH and GOROOT are no longer needed?

It so happened that developers who are just starting to get acquainted with Go often encounter the problem of choosing a working directory for Go projects. So in the chat of the GolangConf conference this question was also asked. New gophers often scare each other with the words GOPATH and GOROOT . However, in the quick start guides with the current version of Go (1.13), these two “scary” words are not mentioned at all.


Let's see why. For the purity of the experiment, I deployed fresh Ubuntu to a virtual machine and installed Go according to the instructions from the Wiki :


sudo add-apt-repository ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install golang-go 

Go 1.13 is installed and ready to use:


 $ go version go version go1.13 linux/amd64 $ which go /usr/bin/go $ whereis go go: /usr/bin/go /usr/lib/go /usr/share/go /usr/share/man/man1/go.1.gz 

GOROOT


About GOROOT has already been perfectly written in the article of 2015 , and this information is still relevant.


It's funny that among the list of directories issued by the last command ( whereis go ), GOROOT is actually not:


 $ go env GOROOT /usr/lib/go-1.13 

So, for example, if for the IDE I need to specify the path to the files of the standard Go library, I will specify /usr/lib/go-1.13 . Perhaps, in this scenario, the use of GOROOT in everyday life ends.


GOPATH and modules


It would seem that in this place you need to rush to install GOPATH , but I will not do this. Actually GOPATH already set:


 $ go env GOPATH /home/elena/go 

I'm comfortable with the GOPATH in ~/go , which means I won’t change it.


I will immediately create a directory for my first project on Go. This can be done anywhere, for example, right in your home directory. Also, I will immediately start working with the Go Modules tool:


 $ mkdir ~/hello $ go mod init github.com/rumyantseva/hello go: creating new go.mod: module github.com/rumyantseva/hello 

For the go mod init command, I specified a unique module module path for my project. If necessary, a proxy or other tool will be able to find my project files along this path.


After calling the go mod init command, the go mod init directory appeared in my home directory:


 $ tree ~/go /home/elena/go └── pkg └── mod └── cache └── lock 3 directories, 1 file 

In this case, the lock-file (at the very bottom of the tree) is still empty.


The go.mod file appeared in the ~/hello go.mod with the following contents:


 module github.com/rumyantseva/hello go 1.13 

It is in go.mod that all information about the dependencies of my module will subsequently be stored.


Let's now write an application using an external dependency. In the ~/hello directory, I create the main.go file and write the following code into it:


 package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, world!") } 

Of course in real life for writing "Hello, world!" logrus can be dispensed with, but in this example, this library will help us find out where external dependency files are stored.


I launch the application in the simplest way:


 $ go run main.go go: finding github.com/sirupsen/logrus v1.4.2 go: downloading github.com/sirupsen/logrus v1.4.2 go: extracting github.com/sirupsen/logrus v1.4.2 go: downloading golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: extracting golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: finding golang.org/x/sys v0.0.0-20190422165155-953cdadca894 INFO[0000] Hello, world! 

Before the application was built and launched, the go mod tool worked. He defined my external dependency github.com/sirupsen/logrus , took its latest version v1.4.2 at the moment and went for transitive dependencies.


A line with a description of the dependence on logrus added to the logrus :


 module github.com/rumyantseva/hello go 1.13 require github.com/sirupsen/logrus v1.4.2 // indirect 

The go.sum file also appeared, which in addition to the logrus dependency logrus contains information about the hashes of transitive dependencies:


 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 

Where is the dependency code itself? It can be found in ~/go/pkg/mod . Also, checksums and other overhead information for working with dependencies will be stored in ~/go/pkg .


If you've already come across the go get tool, you know that when pulling dependencies, it actually clones the repositories (for example, in the case of git with git clone ). But go mod doesn't work that way. For go mod main unit of code is the module. Modules are archives. When working with go mod dependencies, it explicitly (if you invoked the go mod download command) or implicitly (if you started compiling the application) downloads and unpacks archives via GOPROXY . Let's see how the proxy is set in Go 1.13 by default:


 $ go env GOPROXY https://proxy.golang.org,direct 

So, as a proxy when building my "Hello, World!" used by proxy.golang.org . Of course, this variable can be changed by choosing a different repository of modules. For example, you can deploy your own internal proxy company, which will be stored, including internal libraries, the code of which was not published in open source.


In general, if I am starting a new project and do not mind using Go Modules, I may not know anything about GOPATH . Go will create the ~/go directory on its own when it is needed.


When is GOPATH needed?


If you basically do not use Go Modules (for example, in a legacy project), getting away from more explicit work with GOPATH may not be so simple.


To see what will happen to my project, if I decide not to use go mod , delete the files ~/hello/go.mod and ~/hello/go.sum . I will also remove ~/go to return to the state of the system that I had at the very beginning:


 rm -rf ~/go ~/hello/go.mod ~/hello/go.sum 

Only the main.go file remains in the ~/hello main.go . What happens now if I try to run it with go run ?


 $ go run main.go main.go:4:2: cannot find package "github.com/sirupsen/logrus" in any of: /usr/lib/go-1.13/src/github.com/sirupsen/logrus (from $GOROOT) /home/elena/go/src/github.com/sirupsen/logrus (from $GOPATH) 

Here they are, these scary GOROOT and GOPATH :)


In order to compile the application, I need to pull up the dependency in GOPATH . I do this with the good old go get :


 $ go get -v github.com/sirupsen/logrus github.com/sirupsen/logrus (download) created GOPATH=/home/elena/go; see 'go help gopath' get "golang.org/x/sys/unix": found meta tag get.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at //golang.org/x/sys/unix?go-get=1 get "golang.org/x/sys/unix": verifying non-authoritative meta tag golang.org/x/sys (download) golang.org/x/sys/unix github.com/sirupsen/logrus 

What happened First of all, go get created the ~/go directory (the one specified as GOPATH ). Then the process of cloning the repositories with dependencies began. It's funny that cloning repositories looks noticeably slower than the option when we used go mod to download and unpack modules. However, the dependency code can now be found inside ~/go/src/ .


By the way, there was still no git client on my clean Ubuntu installation, and in order for go get work, I had to install it.


I launch the application:


 $ go run main.go INFO[0000] Hello, world! 

Works!


That's just at the application level, I now do not track the version of external dependencies. What if, due to a vulnerability, at some point in the github.com/sirupsen/logrus repository is not the logger I expected, but some malicious code? Sooner or later, I still need a tool for working with dependencies, and if Go Modules for some reason does not fit, you have to look for something else ...


Conclusion


This article did not address some specific points, and working with external dependencies in Go can still cause a lot of questions. However, new versions of Go at least do not impose restrictions on where the working directories of your projects can be created.


If you are starting a new project, try Go Modules! Reverting to the old approach to working with dependencies makes sense only if something goes wrong. By the way, if you prefer to store all the dependencies inside the project, Go Modules supports vendor mode.


If you need to work with an existing project, and for some reason you do not want to translate it into Go Modules, it is important to indicate the features of its deployment and dependency management in the project documentation. If newcomers unfamiliar with the old approaches to working with dependencies come to the project, it will be much easier for them to deal with the project if all the documentation is in place.


By the way, on October 7th at the GolangConf conference, as one of the special activities, we are planning an expert zone where anyone can ask any questions about Go to members of the conference program committee and enthusiasts of the Russian Go-community. Install Go? Deal with addictions? Write a microservice? This is for us!



Source: https://habr.com/ru/post/467697/


All Articles