4 ms·
The author mentions Go's vendor/ implementation, and I just have to comment about my issues with it (I am filled with the rage of a thousand suns each time I ha
by cyphar 10y ago
The author mentions Go's vendor/ implementation, and I just have to comment about my issues with it (I am filled with the rage of a thousand suns each time I have to deal with vendor/). I hope this will serve as an example to other language designers to understand why you should always listen to your community. [ Disclaimer: I am a maintainer of runC and have been contributing to Docker and other Go projects for almost 3 years. ]
Go didn't have vendoring support in the old days, so the solution that people came up with was to hack with the GOPATH. The idea is quite ingenious, you just have to create a directory in your project of the form vendor/src/... and the set GOPATH=vendor:$GOPATH. Now, it's a hack around the fact that Go tries to take control of your filesystem (something that I'm still bitter about, and have near-daily issues with) but it's a fairly good one.
There are several benefits to this method that are quite crucial to point out:
1. It doesn't require any source code changes to implement. It's entirely a build system trick. It also makes the version tagging completely separate from the source code. Luckily this is true for the new vendor/ implementation. But note that this is actually a complaint people have about vendoring. At least this brokenness is maintained... Lovely.
2. You can turn off the vendoring by no longer changing your GOPATH. Or you could point your GOPATH to somewhere else.
3. Go's importing of the package path is unchanged by vendoring (look at the output of `go list -f '{{ .PkgPath }}'` to see what I mean). This may seem like a trivial thing to point out but it has an impact on building in certain contexts, as well as users of the reflect package.
4. It worked with every version of the Go compiler (even gcc-go).
There is also a few downsides (though you could see them as upsides). The main one is:
5. All of the vendoring is done globally. This means that if you pin a version of a repository, and one of your dependencies also uses that repository they will both use the same version. This could cause issues, but also ensures that you know what version of the code you're running.
But the solution that Go went with (where vendor/ becomes a magical directory within every project and changes how package imports are resolved) doesn't fix all of the same problems. Namely, it breaks points (2), (3), and (4). (2) is hard to do (you have to manually delete the vendor/ directories), (3) is just simply not possible to fix and (4) is a fun exercise to try to hack around (trust me, I've tried) but because (3) is broken it's not possible [ Did I mention that Go _really_ hates symlinks? ].
Now, you could argue that it fixes (5) (but the GOPATH trick could've fixed it too). So really the solution Go went with was worse than the solution the community came up with. And it was incompatible with the GOPATH trick (fixing (4) involves trying to convert the vendor/ to a GOPATH -- it only works sometimes but because the trick involves symlinks good luck with that).
And now Go is going to work on packaging. I can't wait to see how they break it. I really regret that the containerisation community went with Go as their language of choice.
- Skinney 10y agoGo essentially went with the node solution (node_modules). Go's pm will essentially just ensure the version that resides in vendor/, and will work more like yarn than npm. This is, of course, not unique to node. Having a global vendor folder where everything is the same version regardless of the project seems like a fragile solution to me, especially if you work on a lot of projects. And how would that work with third party libraries? Those would still have to vendor? I think it's a good thing that Go standardizes vendoring.
- cyphar 10y ago> Having a global vendor folder where everything is the same version regardless of the project seems like a fragile solution to me That's not what I said. The way that every Go project used to do this (which was how Godep solved the problem) is that you have a vendor/src directory in the project. It's very similar to having vendor/ in your project, but the issues I mention are because of the lack of the "src" prefix. If it sounds like a trivial difference, that's because it is (but because of Go's lovely filesystem dependencies it makes everything awful). > I think it's a good thing that Go standardizes vendoring. Sure. I don't think it's a good thing that they standardised an incompatible solution, apparently ignoring how everyone else in the Go community had solved the problem before them.