Goop – Dependency Manager for Go
github.com
github.com
Godep wants you to touch your GOPATH. For example, `godep save` saves revisions of packages currently installed in your GOPATH and `godep restore` downloads packages into your current GOPATH. If you don't want to pollute global GOPATH, you will have to change it. This works for some people, doesn't for others.
Goop doesn't want you to worry about GOPATH. Goop also encourages you to explicitly state which packages you are using in the Goopfile, rather than "capturing" what is already in use.
First off, I will say that I'm not a great fan of godep, so I'm not looking to advocate for it. That said:
> Godep wants you to mangle with your GOPATH. For example, `godep save` saves revisions of packages currently installed in your GOPATH and `godep restore` downloads packages into your current GOPATH. If you don't have to pollute global GOPATH, you will have to change it. This works for some people, doesn't for others.
Your $GOPATH is a list of directories, not a single directory. This is almost never useful in practice (most people should just use a single directory as their GOPATH). However, for what you're trying to do here, that would be far simpler than introducing a third-party tool, especially one that requires adoption from all project contributors.
> Goop doesn't want you to worry about GOPATH.
The $GOPATH is technically not part of the Go language (spec), but it is a language-wide idiom respected by all build tools. I'd be very nervous about a project that eschews such firm idioms in favor of its own inventions.
I disagree. I use and recommend a 2 directory GOPATH setup. The first path being the one where all 'go get' packages are installed and the second being where you put your packages. I've found keeping these separated makes long term management easier.
Go import directories, are, by definition, unique. My work code is under github.com/juju/. Why should I put labix.org/v2/mgo under some other root path? They're unique directories either way.
GOPATH := ${CURDIR}/build
build:
@env GOPATH="${GOPATH}" godep restore
@test -d "${GOPATH}/src/github.com/user/repo" || ln -s "${CURDIR}" "${GOPATH}/src/github.com/user/repo"
@env GOPATH="${GOPATH}" go install github.com/user/repo
I do like the look of Goop's dep format file though. The Godeps file is pretty ugly in comparison.https://github.com/tools/godep/commit/983ff9241cead0f7e6ad0a...
Edit: Though, perhaps the final solution could be cleaner with a vendoring tool written from the ground up with the purpose of import path rewriting.
From what I can tell, goop has the same GOPATH issues as godep, but godep allows you to address it in different ways. save/restore is one way, and there is also the proxy to the go tool `godep go` which looks to be the goop approach.
I see godep as a swiss knife of tools, and different people use godep in completely different ways (which has its advantages and disadvantages). Personally, the only godep commands I use are:
rm ./Godeps && godep save --copy=false # Save current dep versions
rm -rf $TMPDIR/godep && godep go build/test # build/test using saved dep versionshttps://github.com/pote/gvp - virtualenv in go's world
https://github.com/pote/gpm - pip in go's world
Package author blub shares his package with the world, or his team, which depends on github.com/blab/blab. Unfortunately a week later github.com/blab/blab goes through a major rewrite, and breaks blub, but people doing go get blub get the new blab, and their build is broken, so they start complaining to the blub author.
Solutions to this:
Expect blab never to make a breaking change (somewhat optimistic)
Vendor a specific version of blab into blub and update manually
Explicitly specify a version of blab to use with a dependency tool
Each approach has some drawbacks.
I honestly don't care for all these version managers. If I didn't trust the author of whatever library I'm pulling in to keep their API stable, then I wouldn't use that library or I'd preemptively fork. This is actually a language convention and if more people were familiar with it, there would be even less issues (though I haven't ever had any personally). If you're interested in helping the community familiarize themselves with Go's language conventions, I made a package[0] that developers should read after going through the Go Tour. It's meant to teach best practices and conventions for library design in Go.
Having your own checked-in vendor dir, perhaps managed with git submodules, on the other hand moves the mapping to git and letting the import path point exactly to your "fork"[0] of choice.
I find both of these approaches clumsy.
What if we could do something like:
import "pinfor.io/github.com/me/thisproject/->/github.com/other/dep"
A server responding at pinfor.io would just behave like a proxy for whatever comes after "/->/"[1], but you'd have a cmdline/web tool to actually override some mappings, like pinning a tag, a sha, another repo (your private fork).
The advantage is that it would work be compatible with go get, meaning that you use this for your libraries
The disadvantage is that it depends on an external site. On the other hand you'd be already depending on an external site to host your repo. It would be nice if this kind of redirector was actually supported by your repo host (e.g. github).
Or perhaps we could just have special support in "go get", e.g. some kind of redirects, perhaps declared as json files so it's easy to host without having access to server side software.
I guess there have been already some discussions about that. Does anybody have some pointers/thoughts about this?
[0] Here I'm broadly defining fork as any DVCS commit; that's all that matters for the build; how you advance that commit defines which "repository" you are following, whether the upstream or your fork.
[1] need a better symbol
It's interesting that go get supports reading version tags, though it's a bit pointless to support them for language changes, since go1 is stable, go2 is unlikely to arrive for years, and Gofix would be best used to fix any issues with a major transition like that anyway. So in practice this feature is not used.
It'd be nice if go get instead supported reading version tags for packages, and had some simple scheme for getting the latest compatible version using semver and versioning import dirs, rather than simply pulling the latest master. I think to do that they'd have to adjust go get and go build/run though, perhaps to add a lock file and to take dirs like github.com/foo/bar-v1.2 into account. Simple versioning would not be a difficult change or an incompatible one, it just wouldn't deal with the very difficult issues of conflict resolution on larger projects, which I think was the golang team's objection (correct me if I'm wrong). I do see why they don't want to introduce a half-baked solution without dependency resolution.
At present either library authors are expected to never break compatibility ever (your proposed solution), or everyone has to update their code when they do. This particular detail seems like undesirable behaviour or an unresolved problem in golang to me, rather than a carefully thought out convention. Just because that's the way it is doesn't mean that's the way it should be.
Sorry, that wasn't clear, I was talking about the language itself - the language is now versioned, but it wasn't for initial releases - they had weekly snapshots, then moved to formal versioning and gave up on the idea of being version-less. See these slides about version 1:
http://talks.golang.org/2012/go1.slide
What holds for the language holds also for libraries I think - having explicit versioned releases and being able to sometimes break backwards compatibility is really useful, esp. if others can pin whatever version they import easily and migrate at their own pace.
I think it's good people are experimenting with pkg versioning - if someone comes up with an elegant solution and deals with most of the edge cases, it'll probably get into the bundled tools like go get eventually, or people will stop using go get and use another better tool. go get is not essential for fetching go libraries, it's just the blessed method.
Most of Google's code base is one big repository, and everyone is working at HEAD. It's nice not having to support a matrix of dependency versions, but that really only works when you can also modify downstream dependencies with ease.
That works within Google because there's a culture of constant maintenance; but out in the real world, you can't expect OSS package maintainers to be constantly active & willing to accept patches.
Goop has `Goopfile.lock` and `goop exec`, inspired by Bundler's `Gemfile.lock` and `bundle exec`.
Couldn't you use tags for versioning? Often people use tag v1.1.1 etc?
You need some way to create a complete dependency graph for a given project. If your project has a list of its immediate dependencies, but those dependencies in turn require specific versions of other packages, how do know what those versions are? You need some consistent way of getting this metadata.
There are a couple solutions, but a few that come to mind: each project stores their deps metadata in a consistent location in their repo, or there's some central package repo (a la RubyGems) where such metadata can be queried.
For any solution to work, all of your dependencies (both direct and indirect) need to opt in to the same metadata scheme, or the system falls apart. Unfortunately, there isn't any consensus in the Go community on how to fix this.
This is what the parent meant by "there isn't much you can do with git hashes."
And committing stuff in git when it matters.
gvm is also nice for testing stuff with different versions of go.
git subtree add --prefix _vendor/src/github.com/crowdmob/goamz https://github.com/crowdmob/goamz.git master --squash
go='GOPATH=`pwd`:$GOPATH go'