自动根据每个项目定义GOPATH

huangapple go评论87阅读模式
英文:

Automatically define GOPATH on a per project basis

问题

对于我创建的每个项目,每次进入项目目录时,我都必须执行export GOPATH={path_to_project}。肯定有更简单的方法。难道我不能为给定的目录创建一个.bashrc或.bash_profile文件来定义该项目的GOPATH吗?

例如,我有两个Go项目A和B。如果我有一个统一的GOPATH,在我在项目之间移动时不重新定义,那么两个项目的二进制文件将存储在同一个位置。更重要的是,第三方库的二进制文件也将存储在同一个位置,因此我无法在每个项目的基础上维护同一库的多个版本。

然而,如果我能够按项目定义GOPATH,那么所有的二进制文件和第三方库都将与项目相关。这似乎是大多数其他语言环境中处理包管理的常见方式(如Ruby的rbenv,Python的vertiualenv等)。

英文:

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 are project dependent. This seems to be the common way of handling package management in most other language environments (ruby rbenv, python vertiualenv, etc.)

答案1

得分: 25

(Q2 2018:
请注意,随着vgo(现在称为“module”)项目的推出,GOPATH可能会被弃用,取而代之的是基于项目的工作流程。这将避免我在两年前提出的手动项目GOPATH

在Go 1.11(2018年8月)中,GOPATH可以是可选的,使用模块


您在使用便捷管理多个GOPATH目录中表达了类似的想法,由Herbert Fischer (hgfischer)提出,适用于Linux/Unix环境(基于上面评论中提到的问题):

> 只需将以下代码片段包含在您的~/.bashrc(或~/.bash_profile)中,并使用source ~/.bashrc重新加载您的shell环境。
此代码片段将创建一个shell函数,该函数将覆盖内置命令cd,并使用自定义命令扫描输入的目录以及上层目录,查找名为.gopath的文件。

cd () {
    builtin cd "$@"
    cdir=$PWD
    while [ "$cdir" != "/" ]; do
        if [ -e "$cdir/.gopath" ]; then
            export GOPATH=$cdir
            break
        fi
        cdir=$(dirname "$cdir")
    done
}

> 现在您只需要在您想要作为GOPATH的每个目录中创建一个.gopath文件,每次进入该目录时,重新定义的cd函数将将当前环境的GOPATH设置为该目录。


2017年更新:如果您不想修改您的环境,您仍然可以通过在Visual Studio Code(一个跨平台的IDE)中打开该项目的src文件夹来为每个项目使用一个GOPATH,并结合扩展程序“Go for Visual Studio Code”。

在该IDE中,您可以:

  • 在名为go.toolsGopath的设置中保留您的全局唯一GOPATH
  • 使用名为go.inferGopath的设置推断您当前的GOPATH

自动根据每个项目定义GOPATH

这样,VSCode将在您的全局GOPATH中安装一系列工具(供您在VSCode之外使用)。
请参阅“Go extension依赖的Go工具”:godepgolintgurugodoc等。

而对于您的项目,GOPATH将是src文件夹的父文件夹:

自动根据每个项目定义GOPATH

当您从IDE编译/安装项目时,这将起作用。
如果您想要从命令行执行此操作,则仍然适用上面的原始答案。

英文:

(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 with source ~/.bashrc.
This snippet will create a shell function that will override the builtin command cd 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 your GOPATH and every time you enter this directory, the redefined cd function will set the GOPATH 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:

  • keep your global unique GOPATH in a setting called go.toolsGopath.
  • infer your current GOPATH with a setting called go.inferGopath

自动根据每个项目定义GOPATH

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:

自动根据每个项目定义GOPATH

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.

答案2

得分: 10

你可以使用类似 autoenv 的工具来设置一个脚本,当你进入特定目录时自动执行。

对于你的目的,一个示例的 /happy/go/path/yay/.env 文件可能如下所示:

export GOPATH="/happy/go/path/yay"
export PATH="$GOPATH/bin:$PATH"
英文:

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"

答案3

得分: 5

我会编写一个脚本,可以从当前目录推断出正确的GOPATH,并将go命令的别名设置为首先调用此脚本。例如,一个非常简单的实现:

#!/bin/bash
# infer-gopath.sh

pwd

然后,在.bash_aliases(或您保存别名的任何位置)中:

alias go='GOPATH=$(infer-gopath.sh) go'

这将将GOPATH设置为infer-gopath.sh输出的内容,仅用于调用go命令,因此不会对您的shell产生任何持久影响。

英文:

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.

答案4

得分: 5

我知道这不是很聪明,但我发现如果我只是进入go项目的基本目录,其中包含src、pkg和bin文件夹,我可以简单地输入:

export GOPATH=$(pwd)

就可以了,一切都很好!

英文:

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!

答案5

得分: 3

我的印象是,go工具积极地不鼓励“在每个项目基础上维护同一库的多个版本”,原因是经验表明这种策略在大型代码库(如Google的代码库)上不起作用。关于包版本控制的讨论在golang-nuts上进行了很多:(搜索列表),并且似乎讨论仍然在进行中,正如Ian Lance Taylor在这个2013年6月6日的采访中所指出的(搜索词“versioning”)。

go打包系统的设计允许每个项目都有自己的目录结构;唯一的限制是它们都需要是GOPATH中某个目录的子目录。这样做的好处是它与版本控制系统很好地交互,只要VCS主分支始终构建。在上面引用的博客采访中,ILT建议:

> 我们在内部的做法是对导入的代码进行快照,并定期更新该快照。这样,如果API发生变化,我们的代码库不会意外中断。

将“导入的代码”替换为“我的其他库”,这似乎是一个可能性;你可以有两个go目录,一个用于生产,一个用于开发;对于开发,你可以将开发目录放在路径的最前面,这样开发的二进制文件和库就不会污染生产目录。我不知道这是否足够。

如果你真的想为每个项目单独设置一个GOPATH,我建议按照以下步骤进行:

1)使每个项目的GOPATH以名为go(或类似的)的目录结尾

2)使用类似以下的shell函数来推断GOPATH(几乎没有经过完全测试):

gopath() {
  GOPATH="$(
    ( while [[ $PWD != / && $(basename $PWD) != go ]]; do
        cd ..
      done
      if [[ $PWD == / ]]; then
        echo $GOPATH
      else
        echo $PWD
      fi
    ))" go "$@"
}

然后,只要你的当前工作目录位于项目的代码库中,你可以使用gopath代替go。(更复杂的可能性可能包括使用显式提供的项目路径来推断GOPATH。)

英文:

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.)

答案6

得分: 1

我不能评论,但是可以根据@joshlf的答案进行扩展:

通过在GOPATH前面添加别名go -- 我的方法不需要你处理/创建额外的文件:

alias go='GOPATH=$(echo $(pwd)) go'

祝好!

英文:

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

答案7

得分: 0

我喜欢上面的gopath()答案的要点,但我不喜欢(a)只为go命令设置GOPATH(我在vim插件等中使用它),也不喜欢(b)要记住输入gopath而不是go 自动根据每个项目定义GOPATH

这是我最终添加到我的~/.bash_profile的内容:

export GOPATH="...一个默认路径..."
function cd() {
  builtin cd $@ &&
  export GOPATH="$(
    ( while [[ $PWD != / && $(basename $PWD) != go ]]; do
        cd ..
      done
      if [[ $PWD == / ]]; then
        echo $GOPATH
      else
        echo $PWD
      fi
    ))"
}

(我还在这篇博文中详细讨论了上述内容的要求in this blog post

英文:

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 自动根据每个项目定义GOPATH

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)

答案8

得分: 0

我是一个Golang新手,但最好的方法可能是在每个项目中创建一个shell脚本来构建/运行项目,并将此脚本放在项目根目录中:

#!/usr/bin/env bash

// 获取包含此脚本的目录的绝对路径
PROJECT_DIR=$(cd $(dirname $0) && pwd)

// 设置GOPATH,然后运行go build
GOPATH=${GOPATH}:${PROJECT_DIR} && cd ${PROJECT_DIR} && go build

即使您从不是项目根目录的目录中执行此脚本,它也应该正常工作。

英文:

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 自动根据每个项目定义GOPATH

#!/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.

huangapple
  • 本文由 发表于 2013年7月22日 13:52:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/17780754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定