英文:
Handle dependencies in Go
问题
在Go语言中,如果你引用了另一个包,比如GitHub上的某个包,那么Go总是会获取master
分支上的最新版本。虽然这在开发过程中很好,但我想在生产环境中可能会有问题:这样构建就不可复现了。
那么,在Go语言中修复依赖项的版本的正确方法是什么,如何高效地处理这个问题呢?
一个朋友向我推荐了godep,这个工具似乎不错,但我想知道还有哪些替代方案,以及godep的优缺点是什么?
英文:
In Go, if you reference another package, e.g. something on GitHub, then Go always gets the latest version from the master
branch. While this is great for development, I guess it's a problem in production: This way a build is not reproducible.
So, what is the correct way in Go to fix a version of a dependency, and how to handle this efficiently?
A friend pointed me to godep, and this seems fine, but I wanted to know what alternatives are there, and what's good / bad about godep?
答案1
得分: 9
2018年更新的Go 1.11版本引入了模块的概念,用于替代GOPATH
,并集成了版本控制和包分发的支持。使用模块,开发者不再受限于GOPATH
,版本依赖信息更加明确且轻量化,构建更加可靠和可复现。具体使用方法可以参考定义模块。2015年6月,Go 1.5版本开始支持供应商目录(vendoring)。当环境变量GO15VENDOREXPERIMENT=1
时,导入路径的解析方式会根据Go 1.5的供应商提案进行更改。2015年3月,Go团队考虑在语言中定义一个集成的依赖管理系统,以解决依赖和供应商问题。他们建议将供应商目录放在“internal”目录下,并进行导入重写,而不是修改GOPATH
,并定义一个通用的配置文件格式来管理依赖和供应商。其中,外部工具如“godep”或“nut”将实现这些功能。另外,还介绍了godep和glide作为Go的依赖管理工具。文章还提到,Go语言的作者们在选择实现某个功能时会考虑权衡利弊,避免编译速度慢和二进制文件过大的问题。他们选择不实现某些功能是因为目前还没有一个他们认为可接受的解决方案。
英文:
Update 2018 with Go 1.11
Dependencies should now be referenced with modules (derived from the vgo project):
> Go 1.11 adds preliminary support for a new concept called “modules,” an alternative to GOPATH
with integrated support for versioning and package distribution.
Using modules, developers are no longer confined to working inside GOPATH
, version dependency information is explicit yet lightweight, and builds are more reliable and reproducible.
See Defining a module. (and the original design proposal)
Update June 2015: first support for vendoring is making its way in Go 1.5!
See c/10923/:
> When GO15VENDOREXPERIMENT=1
is in the environment, this CL changes the resolution of import paths according to the Go 1.5 vendor proposal:
> - If there is a source directory d/vendor
, then, when compiling a source file within the subtree rooted at d
, import "p"
is interpreted as import "d/vendor/p"
if that exists.
- When there are multiple possible resolutions, the most specific (longest) path wins.
- The short form must always be used: no import path can contain “
/vendor/
” explicitly. - Import comments are ignored in vendored packages.
Update March 2015: the go team is thinking about defining a go dependency management system integrated to the language: the debate is in this thread.
> We think it’s time to start addressing the dependency & vendoring issue, especially before too many conflicting tools arise and fragment best practices in the Go ecosystem, unnecessarily complicating tooling. It would be nice if the community could converge on a standard way to vendor.
> Our proposal is that the Go project,
> 1. officially recommends vendoring into an “internal” directory with import rewriting (not GOPATH
modifications) as the canonical way to pin dependencies.
2. defines a common config file format for dependencies & vendoring
3. makes no code changes to cmd/go
in Go 1.5. External tools such as “godep
” or “nut
” will implement 1) and 2). We can reevaluate including such a tool in Go 1.6+.
One possible downside of godep is that you can no longer use "go build" or "go test" directly.
You need to precede those commands with godep
(or type godep save
).
An alternative is glide, which remains compatible with classic go commands.
> - Manage project-specific GOPATHs
- Ease dependency management
- Support versioning packages
- Support aliasing packages (e.g. for working with github forks)
- Remove the need for "vendoring" or munging import statements
- Work with all of the go tools
More generally, the article "Know your guarantees, Go edition" is interesting:
> It’s also a deliberate choice, where the Go authors chose not to implement a feature when they felt that the trade-offs were no good.
> One low-level reason they made this choice is to avoid slow compilation and bloated binaries (which are two sides of the same coin).
Remember, packages depend on other packages. So Foo
might depend on Bar
2.1. Foo
might also depend on Baz
which in turn depends on Bar
1.9, and on down the tree. So that would mean compiling and linking several copies of nearly identical code.
> Depending on several versions of the same package also means knowing which version one is calling, whereby the dependency mess seeps into your source code.
> Which leads us to the high-level reasoning behind the Go platform punting on this feature: they did not have a logical solution they considered acceptable. It’s not that they don’t understand the problem; it’s that, at the moment, there is not a solution they like. So they choose no feature over over a regressive one.
答案2
得分: 1
你处理依赖项的方式与其他语言处理依赖项的方式相同:使用供应商。对于Go语言来说,没有类似于Nexus的供应商管理工具,所以大多数人会将外部库复制到一个名为"vendor"的文件夹中,有一些工具可以帮助处理这个过程。就个人而言,我觉得所有这些"修复版本"的恐慌有点夸张,因为即使没有这些操作,它也能正常工作得很好。
你可能想看一下http://labix.org/gopkg.in,并在golang-nuts上搜索依赖管理相关的内容。我认为甚至有一个专门讨论这个问题的邮件列表。
英文:
You handle dependencies like you do handle dependencies in other languages too: You vendor. For Go there is no Nexus which does the vendoring so most just copy external libraries into a "vendor" folder, there are tools helping here. Personally I found all this "fix version" panic a bit exaggerated as it works pretty well without.
You might wanna take a look at http://labix.org/gopkg.in and search golang-nuts for dependency management. I think there is even a whole mailing list devoted to this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论