-
Notifications
You must be signed in to change notification settings - Fork 540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve deps in cache and mirrors #547
Conversation
This was previously re-implemented code in numerous places A central location provides an single place to handle global overrides
Aliases are stored in an overrides.yaml file in the GLIDE_HOME
Not sure why GitHub didn't register the passing travis tests. that's at https://travis-ci.org/Masterminds/glide/builds/151840337. |
// Export from the cache to the vendor directory | ||
func (i *Installer) Export(conf *cfg.Config) error { | ||
msg.Info("Removing existing vendor dependencies") | ||
err := os.RemoveAll(i.VendorPath()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's probably preferable to write out to a temporary directory, then remove the old vendor dir and move the new one into in place if and only if creating the new one succeeded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I'll make that change.
gpath "github.com/Masterminds/glide/path" | ||
) | ||
|
||
var overrides map[string]*override |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen any, but asking just in case - is there any possibility of parallel goroutine access to this map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a great question. I'm pretty sure there is so I'm not sure why it's not complained. I'll fix this. Thanks.
Edit: There is only parallel read. No chance of parallel write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool cool, then we're good.
in general, i think this looks good. 🎉 i do have some concerns about the implications of overrides, though. i'm going to try to return to write that up this evening. |
So, overrides. Lemme preface by saying that I think this is a crucial use case - #548 is just the most recent example. I just want to make sure we do it in such a way that we minimize the potentially nasty second-order effects. My basic concern is, from the examples given, overrides allow/encourage the user to name local paths as substitutions for ordinary upstream paths. As a result, lock files produced when such overrides are in place may be non-portable, as they now rely on potentially arbitrary versions of code that just happen to be on peoples' local system. If the goal is to create a portable lock file (which...yes, right?), then the list of weird failures modes preventing that goes something like this:
All of these are cases in which glide would either be unable to write out a rev to the lock, or would write out one that's incorrect or unusable. Now, I realize that these were all situations that could occur without this PR if the appropriate flags were passed and packages were sourced from This PR, though, introduces a new element - instead of implicitly searching Sadly, I don't have a really good alternative right now. The work I just finished (sdboyer/gps#83) lays the groundwork for "path-based" import satisfaction, which is how I envision satisfying this class of requirement. But it's not there yet. The only real idea I have at this point is to define "portability" levels, and incorporate that information into the lock file, so that we can at least provide saner errors to other users when they fail to install from a |
Oh, also - do you have specific stories around referencing
I do not think the "performance/waste" argument for this is valid - the one that goes, "it's already on my |
Ugh, I did forget a couple things. Sorry. First, kinda more a nit, but - Second - if this kind of information is going to be included, there's also an approach here that puts this information in the manifest. Yes, it's a bunch more work to decide on how to reconcile it with everything else, but...having it in the manifest at least makes it publicly visible (to humans, and to solvers on other machines/importing this as a dep) that "this path is not sourced from a repo." If that doesn't match the use case you have in mind, then a) good, let's talk use cases and b) i think that should highlight how varied the use of this may be, and maybe some of the classes of problems that could arise. |
@sdboyer A few things...
|
Could you please explain that requirement in terms of use cases? Are there ones beyond what I already described?
"any tooling" referring to, e.g., bundler/npm? Well, bundler calls them "local git repos," and yes, they require that it be a valid repository, and they have several other requirements as well, in order to ensure that the generated lock file remains sane:
emphasis mine, to highlight that yes, they consider it important that the generated lock file is portable.
My subjective experience? Often. Just last night, when I was updating #384, I had an error occur because I had extra uncommitted files in my local gps tree that I unintentionally rsynced into glide's vendored copy (I have to use a weird workflow to pull in updates). Even though that workflow is weird, it's symptomatic of case no. 5. Unpushed changes (no. 3) happened to me all the time when using that feature in bundler, and no. 4 bit me on a hobby project this past winter.
I think we do it by focusing on the strict use cases the feature is trying to meet, satisfying those, and then constraining its power or layering on additional checks/requirements that reduce and clarify the failure modes. IMO, not having bad failure modes is also an important component of success. Users may still be shooting themselves in the foot, but we can give them a BB-gun instead of a bazooka. |
@sdboyer thanks for the link and all the thoughts on this. I think there might be a use case gap here. So, let me outline a couple.
Your example of Bundler installing Gems is an interesting one. The link you provided is about switching from Gems to the source and the rules around that switch. In Go we always use the source. What caught my attention was the way you can configure bundler to use a mirror for your gems. Bundler is a different case because it's a central package repo. Go is distributed so the mirroring functionality needs to handle distributed. Another place to look is at PyPI mirrors and caches. Once you have a mirror up you can specify it in your I renamed it to Now, some folks are going to use this to route to their What kinds of problems can come up if a developer doesn't push commits from a dependency stilling in a dev environment to their public normal distribution locations?
The first one, where it exits in error, is due to a The second one, at first, seemed a bit more painful. But, if the resolver matches for compatible versions than you should be ok. It's not idea but it matched the version range support. It's not ideal. Can you think of other bad situations and explain how they would be bad in ways where something doesn't tell you? I imagine there are other cases. Again, using mirrors for a dev environment is not the goal of this. It never was the goal of the gopath flags in glide either. I just realize there will be some abuse of that situation. |
Two more notes:
|
Ahh cool, OK - I realize my comments were probably too focused in on
Cool, this is the use case I was trying to describe in my earlier comment.
Ah, yes. Pretty much functionally identical to the other use case (which is why they can both be serviced by the one feature).
Right, so, let's dispatch with this first - the issue I was really centrally focused on was allowing
If we allow
Yes, I gave five, one of which I think is equivalent to the two you gave. The latter three all involve subtle, reasonably easy slip-ups that the dev could make during the course of normal development - I did.
Right, SO! This is the crux of the issue. It's also a facet of a general problem in distributed architectures - who decides what names mean? (I won't wax poetic - just want to point out that this is known, and not easy.) I think the safest way to approach the issue is to allow for a URL rewrite - perhaps as a regex - that is applied during the process of transforming an import path into a URL for source retrieval. This would, I think, satisfy #372. I haven't written support for doing it into Now, URL rewrites + scheme validation would, I think, cover the true mirroring cases. True mirrors don't need to be reflected in the lock file, because they generally don't affect build outcomes (in practice they do, but those are distributed systems problems that we don't need to touch in this discussion). URL rewrite + scheme validation would not cover #548, however, as that use case, while important, is not for a mirror; it's a fundamentally different type of source. I'm moving |
@sdboyer I don't think we really can block Rewrite rules is an interesting idea some of us have talked about in the past. That's worth doing. |
@mattfarina I don't see how NFS is relevant? I could have source files mounted RO through ZFS into a container with the host machine synchronizing them over the network through a Cassandra-backed FUSE filesystem...or just have them on local disk. The filesystem is not the problem; provenance is. Knowing provenance is how a tool can create a lock file, because provenance tells us how we can recreate the source code later. This is exactly why bundler imposes the requirements it does. If |
@@ -248,6 +248,16 @@ func (i *Installer) Export(conf *cfg.Config) error { | |||
if err != nil { | |||
return err | |||
} | |||
// defer func() { | |||
// err = os.RemoveAll(tempDir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, i may have had this problem before, if the issue was os.RemoveAll()
failing on windows? if so, it's fixed in go1.7, but for previous versions, this will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a goof from debugging. Thanks for catching it.
In reading #548, i realize that i'd, again, misunderstood something about how you're intending that this be used. Sorry. You're picturing that whatever's at that location be treated as a source. So, we have to inspect the path, determine if it is, or contains, a repo - or read this from the OK, yeah, I think this is a lot less harmful. Lemme ponder a bit, too. (The mechanism to feed this in to |
ah i see |
Seems new functionality completely removed my 'vendor' folder onupdate because I've /tmp on tmpfs:
|
This implements two complementary features that are linked.
First, dependencies are resolved in the cache rather than the
vendor/
directory. If the dependency tree is successfully figured out the source is exported tovendor/
. This deprecates a number of flags that dealt with stripping VCS information as they are no longer needed. For the time their use will display a deprecation warning that will be removed in a future version.There are a few reasons for this change:
In using the cache this removes the use of flags to pull dependencies from the
GOPATH
. To alleviate that change a mirrors feature has been added. This allows a repo location (rather than a package) to be overridden. This feature is currently global to a user on a system.So, you can take a repo location such as
https://github.com/example/foo
and tell Glide to usehttps://git.example.com/example/foo.git
instead. Or,file:///path/to/local/repo
if you want to fetch from theGOPATH
or other local location.This is a major change and feedback is requested.