For every project I create I have to do export GOPATH={path_to_project}
every time i cd into the project dir. There has to be an easier way. Isn't there some way I can create a .bashrc or .bash_profile file for a given directory to define the GOPATH for that project?
For example, I have two go projects A and B. If I have a singular GOPATH that isn't redefined when I move between projects then binaries for both projects will be stored in the same place. More importantly, binaries for third party libraries will be stored in the same place so I have no way of maintaining multiple versions of the same library on a per project basis.
However, if I am able to define GOPATH on a per project basis then all binaries and third party libraries a project dependent. This seems to be the common way of handling package management in most other language environments (ruby rbenv, python vertiualenv, etc.)
I would write a script which can infer the proper GOPATH from the current directory, and then alias the go
command to first call this script. For example, a very simple implementation:
#!/bin/bash
# infer-gopath.sh
pwd
And then, in .bash_aliases (or wherever you keep your aliases):
alias go='GOPATH=$(infer-gopath.sh) go'
This sets GOPATH
to whatever infer-gopath.sh
outputs just for the invocation of the go
command, so it won't have any lasting effect on your shell.
My impression is that the go
tool actively discourages "maintaining multiple versions of the same library on a per project basis" for the precise reason that experience has shown that that strategy doesn't work on large codebases (such as Google's). There has been quite a lot of discussion about package versioning on golang-nuts: (search the list), and it seems that the discussion is still open, as indicated by Ian Lance Taylor in this June 6, 2013 interview (search for the word "versioning").
The go
packaging system is designed to allow every project to have its own directory structure; the only restriction is that they all need to be children of (some) directory in GOPATH
. This has the advantage that it interacts well with version control systems, as long as the VCS master always builds. In the blog interview referenced above, ILT suggests:
What we do internally is take a snapshot of the imported code, and update that snapshot from time to time. That way, our code base won't break unexpectedly if the API changes.
Substituting "my other libraries" for "the imported code", that seems like a possibility; you could have two go
directories, production and development; for development, you could put the development directory first in the path so that development binaries and libraries don't pollute the production directories. I don't know if that is sufficient.
If you really want to have a separate GOPATH
for each project, I'd suggest the following:
1) Make every project's GOPATH
end at a directory named go
(or some such)
2) Deduce the GOPATH
using the something like the following shell function (almost totally untested):
gopath() {
GOPATH="$(
( while [[ $PWD != / && $(basename $PWD) != go ]]; do
cd ..
done
if [[ $PWD == / ]]; then
echo $GOPATH
else
echo $PWD
fi
))" go "$@"
}
Then you can use gopath
instead of go
as long as your current working directory is somewhere inside the project's repository. (More sophisticated possibilities might include using the explicitly provided project path, if any, to deduce GOPATH
.)
You can use a tool like autoenv to set up a script that is automatically executed when you cd
into a particular directory.
For your purposes, an example /happy/go/path/yay/.env
file might look like:
export GOPATH="/happy/go/path/yay"
export PATH="$GOPATH/bin:$PATH"
I like the guts of the gopath() answer above, but I don't like (a) having the GOPATH
set only for the go
command (I use it in vim plugins, etc), nor do I like (b) having to remember to type gopath
instead of go
:)
This is what I ultimately added to my ~/.bash_profile
:
export GOPATH="... a default path ..."
function cd() {
builtin cd $@ &&
export GOPATH="$(
( while [[ $PWD != / && $(basename $PWD) != go ]]; do
cd ..
done
if [[ $PWD == / ]]; then
echo $GOPATH
else
echo $PWD
fi
))"
}
(I also wrote up the above with a little extra discussion of requirements in this blog post)
(Q2 2018: Note that with the vgo (now "module") project, GOPATH
might end up being deprecated in favor of a project-based workflow. That would avoid the manual project-based GOPATH
I was proposing below, two years ago)
With Go 1.11 (August 2018), GOPATH
can be optional, with modules.
You have a similar idea expressed in Manage multiple GOPATH dirs with ease, by Herbert Fischer (hgfischer
), for a Linux/Unix environment (base on the question already mention in the comments above):
Just include the following snippet in your
~/.bashrc
(or~/.bash_profile
) and reload your shell environment withsource ~/.bashrc
.
This snippet will create a shell function that will override the builtin commandcd
with a customized one that scans the entered directory, and every other above, for a file named.gopath
.
cd () {
builtin cd "$@"
cdir=$PWD
while [ "$cdir" != "/" ]; do
if [ -e "$cdir/.gopath" ]; then
export GOPATH=$cdir
break
fi
cdir=$(dirname "$cdir")
done
}
Now you just need to create a
.gopath
file in every directory you want as yourGOPATH
and every time you enter this directory, the redefinedcd
function will set theGOPATH
of your current environment to this directory.
Update 2017: if you don't want to modify your environment, you can still use one GOPATH
per project, by opening the src
folder of that project in Visual Studio Code (vscode, which is a multi-platform IDE), combined with the extension "Go for Visual Studio Code".
In that IDE, you can:
GOPATH
in a setting called go.toolsGopath
.GOPATH
with a setting called go.inferGopath
That way, VSCode will install a collection of tools in your global GOPATH
(for you to use outside VSCode as well).
See "Go tools that the Go extension depends on": godep
, golint
, guru
, godoc
, ...
And yet, your GOPATH
for your project will be the parent folder of src:
That works when you compile/install your project from the IDE.
If you want to do it from the command line, the original answer above would still apply.
I can't comment, but to build off the answer from @joshlf :::
alias go
by prepending the GOPATH
-- my method doesn't require you deal with/create an extra file:
alias go='GOPATH=$(echo $(pwd)) go'
cheers
I'm a Golang newb, but the best way to do this would probably be to create a shell script in each of your projects, to build/run your project, and put this script in your project root :)
#!/usr/bin/env bash
// get absolute path to the directory which contains this script
PROJECT_DIR=$(cd $(dirname $0) && pwd)
// set GOPATH as you wish, then run go build
GOPATH=${GOPATH}:${PROJECT_DIR} && cd ${PROJECT_DIR} && go build
this script should work, even if you execute it from a directory that is not the project root.
I know this is not very clever but I find that if I simply go to the base directory of the go project where I have the src, pkg and bin folders I can simply type:
export GOPATH=$(pwd)
and thats it all good!