owenthereal / nut

Vendor Go dependencies
https://github.com/jingweno/nut
MIT License
232 stars 11 forks source link

Parse .go files for dependencies? #3

Open ydnar opened 9 years ago

ydnar commented 9 years ago

What if, instead of parsing a separate dependency file, authors could explicitly list their dependencies in the import statements? The nut command would parse Go files looking for vendored dependencies, and fetch / clean as necessary?

We did an experiment in an internal package and the following worked:

import "github.com/user/app/_vendor/github.com/other/package@abf7t4e2"

We manually vendored the dependency in the app’s _vendor directory at _vendor/github.com/other/package@abf7t4e2. The only thing missing is a glue tool to find and fetch dependencies missing from the _vendor directory.

ifraixedes commented 9 years ago

@ydnar I like your approach.

I think the fetch is the tricky part, because the fetcher must get the repository and checkout to the history point, considering the support for the current four version control systems which go get currently support.

I'm not sure, because I haven't check its code, if nut support the four of them.

owenthereal commented 9 years ago

@ydnar & @ifraixedes:

import "github.com/user/app/_vendor/github.com/other/package@abf7t4e2"

This approach is similar to what gopack.in is trying to accomplish except that the dependencies are not vendored. One problem I found with having the package version in the import paths is whenever I need to change the package version, I may have to change more than one place, for example, all paths have to be changed from github.com/user/app/_vendor/github.com/other/package@123 to github.com/user/app/_vendor/github.com/other/package@456.

nut is designed to allow you to update the dependencies without worrying about the referred import paths: only the dependencies in the vendor folder is updated to the version specified in Nut.toml.

I think the fetch is the tricky part, because the fetcher must get the repository and checkout to the history point

Yes, that's exactly what nut gives you - it checks out the version specified in Nut.toml.

ydnar commented 9 years ago

@jingweno you're right—changing dependencies everywhere would be a pain. I suppose you could encode it once via a tagged comment, and check out the specific version in the vendor directory:

import "github.com/user/app/vendor/github.com/other/repo" //+@ b65e2f

Declaring a conflicting version of a dependency in two different files would be an error.

owenthereal commented 9 years ago

I suppose you could encode it once via a tagged comment, and check out the specific version in the vendor directory

It sounds like you'd prefer to declaring import paths with version in the Go code. Any reason of that? Having used this approach for a while, e.g. gopack.in etc, I found it very fragile to define versioned dependencies this way - in your case, I never know what version of a package I'm using unless I find the import statement having the version tag (maybe building a tool to automate that would work, but still not quite straightforward), needless to say updating the version. Why not defining the dependencies and their versions in a "master" file like Nut.toml? It makes updating the version very straightfoward. It also will never have the conflicting version of a dependency problem as you mentioned.

ifraixedes commented 9 years ago

I didn't think before that having the version in the import or a comment as @ydnar suggested in his last comment implies to update all the files when you update them to another version and then you have to commit a lot of changes to the repository, even though to make commit is a big deal, some people don't want to have those changes in the history.

Then the solution to have a metadata file as Nut.toml solves that case.

ydnar commented 9 years ago

If Go natively introduced versioned dependencies, how would they do it? I suspect it would be embedded in .go files rather than an external dependencies file.

Tooling exists for parsing Go source files; embedding in comments has plenty of precedent (build flags, generate commands, C).

owenthereal commented 9 years ago

I suspect it would be embedded in .go files rather than an external dependencies file.

I'd agree with you if Go was to support this, it may be in the Go files. But is it the best solution? I'll need to understand why it's better than a metadata file.

c4milo commented 9 years ago

I personally prefer having my dependencies explicitly declared in one place as oppose to spread out across my code base. I really like Nut's approach, which is pretty similar to Rust's Cargo. Nut may even work pretty well with the upcoming Go's external package and hopefully rewriting import paths will no longer be necessary, in the near future.

owenthereal commented 9 years ago

I really like Nut's approach, which is pretty similar to Rust's Cargo.

Yes, I got the inspiration from cargo :smile:

Nut may even work pretty well with the upcoming Go's external package and hopefully rewriting import paths will no longer be necessary, in the near future.

Could you give me a pointer on Go's external package? It's to my interest to make nut future proof.

c4milo commented 9 years ago

My bad, I was under the impression that it was almost accepted but it turns out it is still under discussion at: https://groups.google.com/forum/#!topic/golang-dev/74zjMON9glU