-
Notifications
You must be signed in to change notification settings - Fork 147
[rfc] gb build/test automatically download missing dependencies #536
Description
This rather blandly titled issue is a placeholder to discuss the changes to gb for the 0.4 series, which the roadmap hints "improve gb vendor".
Backstory
gb cares about reliable builds, a lot. Giving Go developers the tools they need to achieve repeatable builds was the motivation for developing gb, and the main way gb does this is via the $PROJECT/vendor/src directory. A bit later gb-vendor came along when it was clear that users wanted tooling to help them manage their vendor'd code.
But it also clear that not everyone is comfortable with actually having copies of the source in their tree; they would rather have a manifest file that explains where to get those dependencies on request. This catalyzed around the gb vendor restore command which I now regret accepting as it confused the message that gb's reliable build story is based on vendoring. See #498.
To be very clear, the answer for how to get the most reliable builds with gb is always to copy your dependencies into $PROJECT/vendor/src. But sometimes there is an argument for trading reliability for convenience, this is the motivation for this proposal.
Proposal
I propose that during package resolution (which happens for build and test, but may happen at other stages in the future) once the standard search locations have been exhausted (see below), a per user cache of source code is consulted, and if the package is not found in the cache, we attempt to fetch it using the standard gb vendor fetch lookup rules.
Importantly, this is not a proposal to automatically invoke gb vendor fetch, but a separate mechanism that is invoked once all the per project source locations have been exhausted.
TODO:
-
decide if this is opt in or opt out; should there be a flag to disable / enable this behaviour, and if so, what its default state will be?This feature will be opt in, it will be enabled by the presence of a dependency file in the project root.
Updating
Maintaining a cache means establishing rules for when the cache is updated. My proposal for this is updating the cache, ie fetching from upstream if the entry is present in the cache, should be off by default.
This means adding a new flag, probably -u which effectively marks anything in the cache as stale and forces the upstream to be consulted. This could be a potentially very time consuming operation.
TODO:
-
decide if a partial update is something that should be supported. The UI for this sounds complicated, so it might be simpler to give the user a command to clear a particular cached entry, which accomplishes the same thing.This feature will be enabled only if the dependency file is present, and the dependency file lists explicitly the version required. If the file is updated to reflect a version which is not present locally, that will be downloaded in due course.
Package cache
The package cache, or more correctly a cache of source code, is a location where dependencies can be stored and referenced for gb projects. This cache is per user not per project.
TODO:
- figure out the appropriate location for the package cache, some operating systems have a notion of a per user cache, others don't.
Search order
The search order for packages is currently:
$GOROOT/src$PROJECT/src$PROJECT/vendor/src
With this change, rather than terminating if a package could not be found, the cache will be searched, and if the package is not found, an attempt to fetch it from it's upstream (as defined by gb vendor fetch, which itself is defined by go get's rules) is made, and the cache searched again.
The proposed search order could be considered to be roughly:
$GOROOT/src$PROJECT/src$PROJECT/vendor/src$HOME/$CACHE/src$REMOTE_URL
The key take away is that source code higher up the search order takes precedent. If you need a specific revision of a dependency, you should vendor it to $PROJECT/vendor/src.
One more thing
With this change, I've just reinvented go get, golf clap.
Well, yes, and no. It is correct to say that in the first implementations of this design fetching from upstream would have the same problems as go get has currently. But I believe that gb has all the pieces to improve on this.
In golang/go#12302 I made a proposal for a simple release mechanism for Go packages; use semver tags for package releases.
I propose that gb can use this information to let project owners specify the version (as defined in proposal/design/12302-release-proposal.md) or a version range for a dependent package.
Arrgh, Dave, you've introduced a manifest file; twice!
True, to avoid pulling from head, you'd need to use a manifest file, but just like gb vendor, it's totally optional, if you don't want gb to fetch upstream, make sure the source you need is in $PROJECT/vendor/src.
TODO:
-
decide on where and how to store version information in the gb project; I propose a file in the root of the project that lists the import path prefixes and a semver like range expression.It will be recorded in$PROJECT/depfile