差不多该认真考虑一下关于Golang开发环境的问题了——GOPATH污染的难题
由于「はじめての Go 言語」系列已经结束了,所以我想开始认真地搭建开发环境并尝试各种事情。首先,从准备环境开始。
GoPath 污染问题
去拿取指令是一個非常強大的功能,對像我這樣在Windows和UNIX環境之間移動的人來說,可以完全使用go get指令完成從存儲庫的獲取到構建/安裝的過程,而無需依賴於環境特定的工具如curl或make。這真是令人感激(當然,仍然可以使用make等工具進行更精細的控制)。
如果在一台机器上(包括虚拟机)管理一个项目的话,这样就足够了,但遗憾的是,工作中很少会出现这种情况。能够为每个项目准备虚拟机还算可以,但更多的情况是在仅限于最低配置,无法做到甚至这样的情况下同时处理多个项目的烦恼(这与Google大神是不同的)。而且,令人困扰的是,GOPATH环境变量并没有考虑到多个项目管理的情况。
在GOPATH环境变量中,可以设置多个路径。如果是在Windows环境下,可以像这样设置。
SET GOPATH=C:\golib;C:\workspace\project1;C:\workspace\project1;...
然而,只有在Go编译器搜索外部包时,这些路径才能全部有效,而在使用go get命令来获取存储库的情况下,则需要在GOPATH中指定第一个路径(在上述示例中为C:\golib)。这样一来,尽管我们为每个项目创建了单独的文件夹,但外部包却被整合到一个文件夹中,导致管理变得混乱。
【解决方案1】为每个项目重新设置GOPATH。
对于这个问题,最直接的答案是重新设置每个项目的 GOPATH。例如,在上述例子中介绍的构建 gb 时,可以按以下方式操作。
C:>SET GOPATH=C:\workspace\gb
C:>go get -v github.com/constabulary/gb/...
github.com/constabulary/gb (download)
github.com/constabulary/gb
github.com/constabulary/gb/cmd
github.com/constabulary/gb/vendor
github.com/constabulary/gb/cmd/gb
github.com/constabulary/gb/cmd/gb-vendor
C:>cd C:\workspace\gb
C:\workspace\gb>tree /f
C:.
├─bin
│ gb-vendor.exe
│ gb.exe
│
├─pkg
│ └─windows_amd64
│ └─github.com
│ └─constabulary
│ └─gb
│
└─src
└─github.com
└─constabulary
└─gb
├─cmd
│ ├─gb
│ └─gb-vendor
├─testdata
└─vendor
└─_testdata
(源文件和pkg文件夹以下部分已经省略)
只需完成以下步骤之一:将路径添加到 bin 文件夹或将执行文件复制到已通行路径的文件夹。如果将执行历史保存在批处理文件(或者 shell 脚本)中,随时可以恢复。
确实,每次都需要设置环境确实是麻烦的,但对于项目管理来说,并不需要额外的工具,只需使用Go编译器的标准功能即可进行管理。仅凭标准功能进行管理是相当重要的,例如,如果使用CI工具,可以简单地进行配置,因此更容易管理。
使用基于项目的管理工具
还有一种方法是使用类似于GB的项目基础的代码管理工具。例如,在“第10节”中介绍的tcnksm/gcli的构建环境可以使用GB进行搭建。
C:> cd C:\workspace\gcli
C:\workspace\gcli>git clone https://github.com/tcnksm/gcli.git src\github.com/tcnksm/gcli
Cloning into 'src\github.com/tcnksm/gcli'...
remote: Counting objects: 766, done.
remote: Total 766 (delta 0), reused 0 (delta 0), pack-reused 766Receiving objects: 90% (690/766), 2.11 MiB | 828.00 KiB/s
Receiving objects: 100% (766/766), 2.50 MiB | 828.00 KiB/s, done.
Resolving deltas: 100% (415/415), done.
Checking connectivity... done.
C:\workspace\gcli>gb vendor fetch github.com/mitchellh/cli
fetching recursive dependency golang.org/x/crypto/ssh/terminal
C:\workspace\gcli>gb vendor fetch github.com/olekukonko/tablewriter
C:\workspace\gcli>gb vendor fetch github.com/tcnksm/go-gitconfig
C:\workspace\gcli>gb vendor fetch github.com/tcnksm/go-latest
fetching recursive dependency github.com/google/go-github/github
fetching recursive dependency github.com/google/go-querystring/query
fetching recursive dependency github.com/hashicorp/go-version
fetching recursive dependency golang.org/x/net/html
C:\workspace\gcli>pushd src\github.com\tcnksm\gcli\skeleton
C:\workspace\gcli\src\github.com\tcnksm\gcli\skeleton>go-bindata -pkg="skeleton" resource/...
C:\workspace\gcli\src\github.com\tcnksm\gcli\skeleton>popd
C:\workspace\gcli>gb build
github.com/tcnksm/gcli/helper
github.com/tcnksm/go-gitconfig
github.com/google/go-querystring/query
golang.org/x/crypto/ssh/terminal
github.com/hashicorp/go-version
golang.org/x/net/html/atom
github.com/olekukonko/tablewriter
github.com/google/go-github/github
github.com/tcnksm/gcli/skeleton
github.com/mitchellh/cli
golang.org/x/net/html
github.com/tcnksm/go-latest
github.com/tcnksm/gcli/command
github.com/tcnksm/gcli
C:\workspace\gcli>bin\gcli.exe version
[0;0mgcli version v0.2.0[0m
[0;31m
Your versin of gcli is out of date! The latest version is 0.2.1.[0m
C:\workspace\gcli>
C:.
├─bin
│ gcli.exe
│
├─pkg
│ └─windows
│ └─amd64
│ ├─github.com
│ │ ├─google
│ │ │ ├─go-github
│ │ │ └─go-querystring
│ │ ├─hashicorp
│ │ ├─mitchellh
│ │ ├─olekukonko
│ │ └─tcnksm
│ │ └─gcli
│ └─golang.org
│ └─x
│ ├─crypto
│ │ └─ssh
│ └─net
│ └─html
├─src
│ └─github.com
│ └─tcnksm
│ └─gcli
│ ├─command
│ ├─helper
│ ├─skeleton
│ │ └─resource
│ └─tests
└─vendor
│ manifest
│
└─src
├─github.com
│ ├─google
│ │ ├─go-github
│ │ │ └─github
│ │ └─go-querystring
│ │ └─query
│ ├─hashicorp
│ │ └─go-version
│ ├─mitchellh
│ │ └─cli
│ ├─olekukonko
│ │ └─tablewriter
│ │ └─csv2table
│ └─tcnksm
│ ├─go-gitconfig
│ └─go-latest
│ └─latest
└─golang.org
└─x
├─crypto
│ └─ssh
│ └─terminal
└─net
└─html
├─atom
├─charset
└─testdata
(src和pkg文件夹及其子文件夹部分内容已被省略)
在 gb 中,外部包是通过 gb vendor fetch 命令引入的,而不是克隆仓库,只需简单地复制它们。外部包的信息存储在 vendor/manifest 文件中。
{
"version": 0,
"dependencies": [
{
"importpath": "github.com/google/go-github/github",
"repository": "https://github.com/google/go-github",
"revision": "7277108aa3e8823e0e028f6c74aea2f4ce4a1b5a",
"branch": "master",
"path": "/github"
},
{
"importpath": "github.com/google/go-querystring/query",
"repository": "https://github.com/google/go-querystring",
"revision": "547ef5ac979778feb2f760cdb5f4eae1a2207b86",
"branch": "master",
"path": "/query"
},
{
"importpath": "github.com/hashicorp/go-version",
"repository": "https://github.com/hashicorp/go-version",
"revision": "999359b6b7a041ce16e695d51e92145b83f01087",
"branch": "master"
},
{
"importpath": "github.com/mitchellh/cli",
"repository": "https://github.com/mitchellh/cli",
"revision": "8102d0ed5ea2709ade1243798785888175f6e415",
"branch": "master"
},
{
"importpath": "github.com/olekukonko/tablewriter",
"repository": "https://github.com/olekukonko/tablewriter",
"revision": "b9346ac189c55dd419f85c7ad2cd56f810bf19d6",
"branch": "master"
},
{
"importpath": "github.com/tcnksm/go-gitconfig",
"repository": "https://github.com/tcnksm/go-gitconfig",
"revision": "6411ba19847f20afe47f603328d97aaeca6def6f",
"branch": "master"
},
{
"importpath": "github.com/tcnksm/go-latest",
"repository": "https://github.com/tcnksm/go-latest",
"revision": "ef81df8e23895f6e86f9bdfea0576b9c17b9f1f4",
"branch": "master"
},
{
"importpath": "golang.org/x/crypto/ssh/terminal",
"repository": "https://go.googlesource.com/crypto",
"revision": "81bf7719a6b7ce9b665598222362b50122dfc13b",
"branch": "master",
"path": "/ssh/terminal"
},
{
"importpath": "golang.org/x/net/html",
"repository": "https://go.googlesource.com/net",
"revision": "7654728e381988afd88e58cabfd6363a5ea91810",
"branch": "master",
"path": "/html"
}
]
}
换句话说,使用GB创建的开发环境可以将整个文件夹分发和同步给开发团队成员。(当使用Git等工具对使用GB创建的开发环境进行管理时,如果src文件夹中的文件被其他存储库管理,则需要将其作为子模块添加,而不是简单地进行克隆操作)。
gb 的缺点是不能使用 go test。虽然有一个名为 gb test 的选项,几乎与 go test 兼容,但如果采用特殊的文件夹结构,测试结果可能会有所不同。因此,在使用 CI 工具时需要注意。
【解决方案3】使用Go 1.5的vendoring功能
目前正在调查这个问题。如果有好的文章,之后会放上链接。暂时先参考以下内容。
Go 1.5 Release Notes – The Go Programming Language
Go 1.5 Vendor Experiment
补充:
我写了一篇文章:关于内部软件包和供应商签约。
那么,我应该把什么放入GOPATH呢?
最好使用go get来引入诸如godoc和golint等标准工具以及项目成员之间共同使用的工具。
C:>go get -v golang.org/x/tools/cmd/godoc
golang.org/x/tools/blog/atom
golang.org/x/tools/present
golang.org/x/tools/go/ast/astutil
golang.org/x/tools/go/types/typeutil
golang.org/x/tools/go/buildutil
golang.org/x/tools/container/intsets
golang.org/x/tools/blog
golang.org/x/tools/go/ssa
golang.org/x/tools/go/loader
golang.org/x/tools/godoc/vfs
golang.org/x/tools/godoc/redirect
golang.org/x/tools/godoc/static
golang.org/x/tools/go/callgraph
golang.org/x/tools/go/ssa/ssautil
golang.org/x/tools/godoc/util
golang.org/x/tools/godoc/vfs/httpfs
golang.org/x/tools/godoc/vfs/gatefs
golang.org/x/tools/go/pointer
golang.org/x/tools/godoc/vfs/mapfs
golang.org/x/tools/godoc/vfs/zipfs
golang.org/x/tools/playground
golang.org/x/tools/godoc/analysis
golang.org/x/tools/godoc
golang.org/x/tools/cmd/godoc
C:>go get -v golang.org/x/tools/cmd/vet
Fetching https://golang.org/x/tools/cmd/vet?go-get=1
Parsing meta tags from https://golang.org/x/tools/cmd/vet?go-get=1 (status code 200)
get "golang.org/x/tools/cmd/vet": found meta tag main.metaImport{Prefix:"golang.org/x/tools", VCS:"git", RepoRoot:"https://go.googlesource.com/tools"} at https://golang.org/x/tools/cmd/vet?go-get=1
get "golang.org/x/tools/cmd/vet": verifying non-authoritative meta tag
Fetching https://golang.org/x/tools?go-get=1
Parsing meta tags from https://golang.org/x/tools?go-get=1 (status code 200)
golang.org/x/tools (download)
golang.org/x/tools/go/exact
golang.org/x/tools/cmd/vet/whitelist
golang.org/x/tools/go/types
golang.org/x/tools/go/gcimporter
golang.org/x/tools/cmd/vet
C:>go get -v github.com/golang/lint/golint
github.com/golang/lint (download)
github.com/golang/lint
github.com/golang/lint/golint
C:>go get -v github.com/jteeuwen/go-bindata/...
github.com/jteeuwen/go-bindata (download)
github.com/jteeuwen/go-bindata
github.com/jteeuwen/go-bindata/go-bindata
如果您使用Windows作为开发平台,那么最好指定一个工具管理负责人,并使用该负责人分发的二进制文件,这样可能更安全。如果您是独自工作,那么就无所谓了。但实际上,我认为独自开发业务系统的情况并不常见,所以重要的是在团队成员之间进行调整,以确保他们使用相同的环境。
让我们愉快地工作吧。
书签
- Go言語のDependency/Vendoringの問題と今後.gbあるいはGo1.5 | SOTA