Dep: Unclear why dep ensure -add adds a constraint

Created on 25 Oct 2017  ·  4Comments  ·  Source: golang/dep

I'm trying to build a mental model of what I expect dep to do, and where I'm at is approximately:

  • the toml file is only for exceptions, specific constraints, and maybe libraries (unclear on this last one)
  • the lock file depends from the imports, not from the toml, except for "required"
  • to change versions use dep ensure -update
  • the vendor folder is exclusively a representation of the lock file
  • run dep ensure && dep prune to make sure all is right in the world

So from this worldview I would expect my toml file for a binary to be empty most of the time.

But then I want to vendor a package before using it, so I go to the README and I'm told to use dep ensure -add. Ok.

But now I have a constraint in my toml file! Why? Am I not supposed not to have any?

So I go to the issue tracker and search for wisdom, and I find https://github.com/golang/dep/issues/1054#issuecomment-325154327 which actually makes me feel like my understanding is mostly correct, but then why does dep ensure -add add a constraint?

So I'm confused.

Most helpful comment

  • the lock file depends from the imports, not from the toml, except for "required"

required, but also ignored - they're dual to each other in their effect on depgraph. required is literally the equivalent to an import statement (though i'm currently pondering softening that a tad to facilitate #1306). ignored is really the more powerful one as it's unique - it lets you basically blackhole a node in the import graph. some more on it in the old gps docs.

  • the toml file is only for exceptions, specific constraints, and maybe libraries (unclear on this last one)

you _could_ operate that way - @nathany made an argument for an approach that scarcely used Gopkg.toml at all in #213. and doing so wouldn't be fundamentally wrong (as my comments in that post indicate). assuming you've reached a Gopkg.lock that works for you, then the only real drawback for a binary-only project would be that your dep ensure -update might be a bit of a wild and wooly experience. without a constraint, you could end up hopping from semver to branches to tags to... 🤷‍♂️

and that's generally why we've leaned away from recommending that route - it's can make updates a lot crazier. that's particularly the case when, say, you have A -> B -> C and A -> D -> C, B and D don't agree on C very well, but there's some _really_ old version of B that doesn't require C at all. without constraints to guide it away from that super old version, dep will likely end up picking the very old version of B. version constraints can do a lot to help narrow the field.

that, and because we've tried to dep in such a way that your use of it for "binary" vs. "lib" projects is basically the same - we, intentionally, do not distinguish between these.

But now I have a constraint in my toml file! Why? Am I not supposed not to have any?

so right, the above is why we append the constraint: it's based on the observation that the version we happened to grab just now is the first version that's guaranteed to have all the things you _might_ use from that dependency. so, we stick it in Gopkg.toml in order to keep your project on a sane, likely-to-work path - whether that's the purpose of your own dep ensure -updates later, or if the project is being brought in as something else's dependency.

All 4 comments

A related thing I'm confused on is: should I have constraints pinning the major version of everything I use directly? If so, why doesn't dep ensure -add add one of those instead?

  • the lock file depends from the imports, not from the toml, except for "required"

required, but also ignored - they're dual to each other in their effect on depgraph. required is literally the equivalent to an import statement (though i'm currently pondering softening that a tad to facilitate #1306). ignored is really the more powerful one as it's unique - it lets you basically blackhole a node in the import graph. some more on it in the old gps docs.

  • the toml file is only for exceptions, specific constraints, and maybe libraries (unclear on this last one)

you _could_ operate that way - @nathany made an argument for an approach that scarcely used Gopkg.toml at all in #213. and doing so wouldn't be fundamentally wrong (as my comments in that post indicate). assuming you've reached a Gopkg.lock that works for you, then the only real drawback for a binary-only project would be that your dep ensure -update might be a bit of a wild and wooly experience. without a constraint, you could end up hopping from semver to branches to tags to... 🤷‍♂️

and that's generally why we've leaned away from recommending that route - it's can make updates a lot crazier. that's particularly the case when, say, you have A -> B -> C and A -> D -> C, B and D don't agree on C very well, but there's some _really_ old version of B that doesn't require C at all. without constraints to guide it away from that super old version, dep will likely end up picking the very old version of B. version constraints can do a lot to help narrow the field.

that, and because we've tried to dep in such a way that your use of it for "binary" vs. "lib" projects is basically the same - we, intentionally, do not distinguish between these.

But now I have a constraint in my toml file! Why? Am I not supposed not to have any?

so right, the above is why we append the constraint: it's based on the observation that the version we happened to grab just now is the first version that's guaranteed to have all the things you _might_ use from that dependency. so, we stick it in Gopkg.toml in order to keep your project on a sane, likely-to-work path - whether that's the purpose of your own dep ensure -updates later, or if the project is being brought in as something else's dependency.

Ok, so it was the other way around: I should always use dep ensure -add, and always have constraints. (For fuzzy values of "always".)

The final piece here was:

Note: When you specify a version without an operator, dep automatically uses the ^ operator by default.

To be fair, the README says to just use dep ensure -add to add deps, even if it says that after mentioning that imports win.

I think the dep ensure -add docs in the README would benefit from mentioning that the added constraint is major-range, even if it's explained below.

Maybe even explicitly say "you could have imports w/o constraints, but that might make your updates weird, don't do that".

(Thanks for the patient explanations, @sdboyer.)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cemremengu picture cemremengu  ·  3Comments

angryrobot picture angryrobot  ·  3Comments

deejross picture deejross  ·  3Comments

mildred picture mildred  ·  3Comments

eleijonmarck picture eleijonmarck  ·  3Comments