eanderton / grapnel

A dependency management solution for the Go Programming Language.
20 stars 3 forks source link

Support For Dependency Version Conflicts #11

Open willhlaw opened 10 years ago

willhlaw commented 10 years ago

I'm not sure if I've seen if Grapnel currently has conflict resolution for the same 3rd party repo but specifying different versions. Nate Finch summarizes the issues but others chime in here on golang-nuts:

"I had the same thought, but in talking to Dave Cheney about it, he convinced me that it's not an easy fix.

Assuming the build number is separate from the package name, i.e.

import "github.com/foo/bar" // #2.6.0-2

You then have to worry about what happens when you import two different versions in different files. Both, in this case, will be called bar. Also, they would be downloaded to the same place on disk by "go get".

If the version number is part of the name, it munges the namespace, so any change to the version requires changing all references from bar_2_6.FooType{} to bar_2_7.FooType{}

One way to get around this is to put the version number in the path above the name... so for example github.com/foo/1.1/bar for bar version 1.1. That works with the current go get, makes sure the path is unique, etc. It's a bit of a hassle on the part of the repo maintainer, but it's the best we have for now.

It's tricky. If it wasn't, it would have already been implemented :)"

May want to look at some of the links I've posted in this gist and contemplate some of the approaches or solutions proposed.

eanderton commented 10 years ago

It's technically allowed via gopkg.in. Gopkg is a live proxy service that allows coders to use an import path that maps to a github repo and branch, so multiple versions like this should be able to stand side-by-side.

http://labix.org/gopkg.in

But overall, it's discouraged by Go's import path design, the behavior of 'go get', and with Grapnel. The problem is that an import path is (canonically via 'go get') tied to the repo name:

import "github.com/pelletier/go-toml"

Also, consider that imports within any such library are not supposed to use relative import paths. So there's no clean way to automate the inclusion of multiple versions into the same source tree, without rewriting import statements of libraries as Grapnel places them into the target directory. Granted, it can be done - and there are tools out there that do "vendoring" like this - but I'm not convinced that it's the right way to go; it's a fiendishly complicated thing to attempt when considering the entire dependency graph.

The problem, as others on golang-nuts have mentioned, is that having two slightly different versions of a lib in your program can have subtle side-effects. Basically, you're guaranteed to be using an untested configuration, which is contrary to the over-aching goal of trying to improve stability through versioning.

Grapnel's current implementation is incomplete in this area, but the goal is to instead have the tool reconcile dependency ranges for the same dependency specification, and fail fast if there is no such version that meets the requirements of the graph. Right now, you can place a dependency in the root grapnel.toml file with a pinned version, to override the tools' preference for the latest compatible version. A future possibility would be an override flag of some kind to disregard the version matching in such cases where a patched or special fork of a library resolves incompatibilities for you.

eanderton commented 10 years ago

We're gonna need a bigger test suite.

eanderton commented 10 years ago

Oh, I forgot to mention, the latest code handles gopkg.in imports via rewrite rules.

Input grapnel.toml file:

[[depenencies]
import = "gopkg.in/inconshreveable/log15.v2"

Output grapnel-lock.toml file:

[[dependencies]]
# Unversioned
type = "git"
import = "gopkg.in/inconshreveable/log15.v2"
url = "http://github.com/inconshreveable/log15"
branch = "v2"
tag = "b082f4ccf0a77fc393b1778b4d94a68635de968f"

As you can see, Grapnel handles the special case of mapping the import to github.com. But notice that the import path includes the 'v2' branch name - that can't be changed without rewriting code that depends on this library.

eanderton commented 9 years ago

There was a recent groundswell surrounding recursively vendored dependencies. This may be available as some kind of preview/beta feature on Go 1.5. It's not a pattern I'm fond of supporting for a host of reasons, but it wouldn't be impossible to train Grapnel to do that.

In the meantime, Grapnel may need an interactive conflict resolver.

eanderton commented 9 years ago

Re-titled ticket to better reflect what this is about.