Bash 基于每个项目自动定义GOPATH

Bash 基于每个项目自动定义GOPATH,bash,go,Bash,Go,对于我创建的每个项目,每次我将cd放入项目目录时,我都必须执行export GOPATH={path_to_project}。必须有一个更简单的方法。我是否有办法为给定目录创建一个.bashrc或.bash_概要文件来定义该项目的GOPATH 例如,我有两个go项目A和B。如果我有一个在项目之间移动时未重新定义的单一GOPATH,则两个项目的二进制文件将存储在同一位置。更重要的是,第三方库的二进制文件将存储在同一个位置,因此我无法在每个项目的基础上维护同一库的多个版本 然而,如果我能够在每个项目

对于我创建的每个项目,每次我将cd放入项目目录时,我都必须执行
export GOPATH={path_to_project}
。必须有一个更简单的方法。我是否有办法为给定目录创建一个.bashrc或.bash_概要文件来定义该项目的GOPATH

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


然而,如果我能够在每个项目的基础上定义GOPATH,那么所有二进制文件和第三方库都依赖于项目。这似乎是大多数其他语言环境(ruby rbenv、python vertiualenv等)中处理包管理的常用方法。

我将编写一个脚本,从当前目录推断正确的GOPATH,然后别名
go
命令来首先调用此脚本。例如,一个非常简单的实现:

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

pwd
然后,在.bash_别名中(或保留别名的任何地方):


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

我的印象是
go
工具积极地阻止“在每个项目的基础上维护同一库的多个版本”正因为如此,经验表明,这种策略在大型代码库(如谷歌)上不起作用。关于golang nuts上的包版本控制有很多讨论:(),正如Ian Lance Taylor在本文(搜索“版本控制”一词)中所指出的,讨论似乎仍然没有结束

go
打包系统旨在允许每个项目都有自己的目录结构;唯一的限制是它们都必须是
GOPATH
中(某些)目录的子目录。这样做的好处是,只要VCS主机始终构建,它就可以与版本控制系统很好地交互。在上面提到的博客采访中,ILT建议:

我们在内部所做的是获取导入代码的快照,并不时更新该快照。这样,如果API发生更改,我们的代码库就不会意外中断

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

如果您真的想为每个项目单独设置一个
GOPATH
,我建议如下:

1) 使每个项目的
GOPATH
在名为
go
的目录中结束(或类似目录)

2) 使用类似于以下shell函数(几乎完全未经测试)的函数推导出
GOPATH

然后,您可以使用
gopath
而不是
go
,只要当前工作目录位于项目存储库中的某个位置。(更复杂的可能性可能包括使用显式提供的项目路径(如果有)来推断
GOPATH

您可以使用类似的工具来设置脚本,当您将
cd
放入特定目录时,脚本会自动执行

出于您的目的,示例
/happy/go/path/yay/.env
文件可能如下所示:

export GOPATH="/happy/go/path/yay"
export PATH="$GOPATH/bin:$PATH"
我喜欢的勇气,但我不喜欢(a)只为
go
命令设置
GOPATH
(我在vim插件等中使用它),也不喜欢(b)必须记住键入
GOPATH
,而不是
go
:)

这就是我最终添加到我的
~/.bash\u配置文件中的内容:

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
    ))"
}
(我还写了上述内容,并额外讨论了一些要求)

(2018年第二季度: 请注意,
GOPATH
可能会被弃用,转而支持基于项目的工作流。这将避免两年前我在下面提出的手动基于项目的
GOPATH)

Go 1.11(2018年8月)的规定


对于Linux/Unix环境,您也有类似的想法(基于上面评论中已经提到的):

只需在
~/.bashrc
(或
~/.bash_配置文件
)中包含以下代码片段,并使用
源代码~/.bashrc
重新加载shell环境即可
此代码段将创建一个shell函数,该函数将使用一个自定义的函数覆盖内置命令
cd
,该函数扫描输入的目录,并每隔一段扫描一个名为
.gopath
的文件

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


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

在该IDE中,您可以:

  • 将全局唯一的
    GOPATH
    保存在名为
    go.toolsGopath
    的设置中
  • 使用名为
    go.inferGopath

这样,VSCode将在您的全局路径中安装一组工具(供您在VSCode外部使用)。
参见“:
godep
golint
guru
godoc
,”

然而,你的
export GOPATH="/happy/go/path/yay"
export PATH="$GOPATH/bin:$PATH"
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
    ))"
}
cd () {
    builtin cd "$@"
    cdir=$PWD
    while [ "$cdir" != "/" ]; do
        if [ -e "$cdir/.gopath" ]; then
            export GOPATH=$cdir
            break
        fi
        cdir=$(dirname "$cdir")
    done
}
#!/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
export GOPATH=$(pwd)