-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Automatically update patch
, and provide better errors if an update is not possible.
#8248
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
Thanks for working on this! I think this is good to give some more useful information here regardless, but I don't think this is the final state we want to end up at. Ideally Cargo would automatically update/manage the lock file, even in the face of stale lock files and updated patches, avoiding the need to print an error asking the user to update. One of the things I run into is when I've got a I think though it may be a small enough change to, if there's one candidate, treat it as if there's no locked version if the previously locked version doesn't match? |
Yea, I agree it would be better to be automatic. I'm uncertain how to do that. The issue is that the old version is "locked" in the Do you have any advice or ideas how to handle that? "Unlocking" the original entry doesn't sound like the right way to go, so maybe making it part of the "avoid" list early on might work? |
Hm I'll try to dig in for a bit and see what I can come up with. |
Ok so I think the general problem is that the I've got an ugly patch which I believe handles the case I run into with wasm-bindgen at least. I think this should work in general to hook into the WDYT about trying to hook into |
OK, I took a stab at making patches update automatically. In the process, I changed it so that if there are multiple possible patches, it picks the one with the greatest version. That might be dangerous, but seems to be decent behavior when patching with an alt registry. There are a million edge cases, and I'm a bit tired of chasing them. I imagine there are still a lot of rough spots. At this point, my hope is that user reports will help guide anything that needs to be fixed. However, if you can think of some other tests to try, I'll give them a shot. One area that I'm uncomfortable with is transitive dependency updates. Somehow they seem to work, but the fact that I didn't make changes to From a high level, the main change is to update the filter ("avoid" set) to include patches when the patch is locked, but the locked value is no longer found. This should make it so that |
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.
Thanks for all the tests! This is looking good to me, and I think the general idea should work out.
FWIW it's taken us years to get the resolver right and it still falls over in some obscure cases. It's unfortunately a really tricky problem and we can't really forsee all the issues all the time. That being said it's worked out pretty well having a solid core implementation where we fix bugs over time, so I think that's fine with [patch]
here to not sweat about "did we think of everything?!". In the limit of time we'll think of everything :)
summaries.sort_by(|a, b| a.version().cmp(b.version())); | ||
summaries.pop().unwrap() | ||
}; | ||
if summaries.len() > 1 { |
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 makes me a bit hesitant here trying to handle multiple candidates being returned. When [patch]
was originally implemented we didn't have custom registries yet, so the only real usage of [patch]
was pointing to git
and path
, neither of which can possibly have multiple versions of a package. With custom registries, though, that's now possible!
My main worry is that the candidates here don't participate in the normal version resolution of everything else. The biggest version may not always be the right one to pick (with other constraints like links
and such).
Could this continue to restrict to only one package? I think it's fine to allow more candidates, but I think what should be done is to add all the candidates to "these can be searched through with version resolution". Version resolution would then do its normal thing to pick which is the best.
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'm not sure if I'm understanding correctly. If you're saying that this function should return multiple summaries, the problem is that any of the entries that aren't selected during version resolution end up in the unused patch list which triggers a warning.
I guess it could group related summaries together, so that the "unused patch" logic could only mark them unused if none in the group were used. However, that would require changes in lots of places (which I'd rather not do right now).
Unless you meant something else, should I just switch it back to an error (maybe with a suggestion to use an =
version requirement)?
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 sorry, let me clarify. Primarily this is a change in behavior from today which I'm worried about, so I would prefer to switch it back to make multiple candidates an error.
Other than that I was thinking that we probably could support this, but not by picking a version here and instead letting version resolution later pick a version. The theoretical idea behind [patch]
was "take this crate and assume it comes from that source". That same idea works for "take this set of crates and assume they all come from that source", but the code here just isn't structured to do that. Ideally what we should do here is that when there's an unlocked (the only way to return multiple versions) dependency we make all matching candidates available for version resolution from the resolver, and the resolver picks one we'd then lock. If it ends up being entirely unused then we could pick the biggest one to lock and it wouldn't be an issue.
Does that make sense?
src/cargo/core/registry.rs
Outdated
// version that matches "0.1.2". It is unusual to explicitly write a | ||
// version in the patch. | ||
anyhow::bail!( | ||
"The patch is locked to {} in Cargo.lock, but the version in the \ |
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 think technically the mention of Cargo.lock here may be superfluous? While true it may not necessarily help that previously you had a successful build and have since modified the version
to be too restrictive.
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 also think it'd be nice, if we're specifically calling out versions, to list the versions in play here.
Could this error case fall-through to the error handling code below to get a similar error message? It'd be nice if the existence of a lock file only guided which packages remained unlocked afterwards.
src/cargo/core/registry.rs
Outdated
locked_patch.version_req(), | ||
); | ||
} | ||
let summary = best_summary(&mut orig_matches); |
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 might be best to restructure this so it's maybe recursive or otherwise shares logic with the above. I'm a bit wary of having two instances of "pick the summary out of this list of summaries" which differ slightly
src/cargo/core/registry.rs
Outdated
name_only_dep, | ||
e | ||
); | ||
"".to_string() |
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 might be a bit simpler to explicitly ignore it with:
let found = source.query_vec(...).unwrap_or_else(|| {
warn!(...);
Vec::new()
});
src/cargo/core/registry.rs
Outdated
}; | ||
if found.is_empty() { | ||
anyhow::bail!( | ||
"The patch location does not appear to contain any packages \ |
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.
Could the patch location be mentioned here and below? (e.g. rendering in source_id()
and such)
I think I covered most of your feedback. |
@bors: r+ 👍 |
📌 Commit 4f2bae9 has been approved by |
☀️ Test successful - checks-azure |
patch
.patch
, and provide better errors if an update is not possible.
Update cargo 7 commits in 500b2bd01c958f5a33b6aa3f080bea015877b83c..9fcb8c1d20c17f51054f7aa4e08ff28d381fe096 2020-05-18 17:12:54 +0000 to 2020-05-25 16:25:36 +0000 - Bump to semver 0.10 for `VersionReq::is_exact` (rust-lang/cargo#8279) - Fix panic with `cargo tree --target=all -Zfeatures=all` (rust-lang/cargo#8269) - Fix nightly tests with llvm-tools. (rust-lang/cargo#8272) - Provide better error messages for a bad `patch`. (rust-lang/cargo#8248) - Try installing exact versions before updating (rust-lang/cargo#8022) - Document unstable `strip` profile feature (rust-lang/cargo#8262) - Add option to strip binaries (rust-lang/cargo#8246)
This attempts to provide more user-friendly error messages for some situations with a bad
patch
. This is a follow-up to #8243.I think this more or less covers all the issues from #4678. I imagine there are other corner cases, but those will need to wait for another day. The main one I can think of is when the patch location is missing required features. Today you get a "blah was not used in the crate graph." warning, with some suggestions added in #6470, but it doesn't actually check if there is a feature mismatch.
Closes #4678