-
Notifications
You must be signed in to change notification settings - Fork 2.9k
fix(resolve): detect unused patches when multiple patches share a PackageId #16987
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -511,8 +511,7 @@ pub fn resolve_with_previous<'gctx>( | |
| Some(ws.gctx()), | ||
| )?; | ||
|
|
||
| let patches = registry.patches().values().flat_map(|v| v.iter()); | ||
| resolved.register_used_patches(patches); | ||
| resolved.register_used_patches(registry.patches()); | ||
|
|
||
| if register_patches && !resolved.unused_patches().is_empty() { | ||
| emit_warnings_of_unused_patches(ws, &resolved, registry)?; | ||
|
|
@@ -818,14 +817,12 @@ fn emit_warnings_of_unused_patches( | |
| ) -> CargoResult<()> { | ||
| const MESSAGE: &str = "was not used in the crate graph"; | ||
|
|
||
| // Patch package with the source URLs being patch | ||
| let mut patch_pkgid_to_urls = HashMap::new(); | ||
| for (url, summaries) in registry.patches().iter() { | ||
| for summary in summaries.iter() { | ||
| patch_pkgid_to_urls | ||
| .entry(summary.package_id()) | ||
| .or_insert_with(HashSet::new) | ||
| .insert(url); | ||
| let mut used_patches = HashSet::new(); | ||
| for pkg in resolve.iter() { | ||
| for (dep_pkg_id, deps) in resolve.deps_not_replaced(pkg) { | ||
| for dep in deps { | ||
| used_patches.insert((dep.source_id().canonical_url().clone(), dep_pkg_id)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -839,34 +836,38 @@ fn emit_warnings_of_unused_patches( | |
| } | ||
|
|
||
| let mut unemitted_unused_patches = Vec::new(); | ||
| for unused in resolve.unused_patches().iter() { | ||
| // Show alternative source URLs if the source URLs being patched | ||
| // cannot be found in the crate graph. | ||
| match ( | ||
| source_ids_grouped_by_pkg_name.get(&unused.name()), | ||
| patch_pkgid_to_urls.get(unused), | ||
| ) { | ||
| (Some(ids), Some(patched_urls)) | ||
| if ids | ||
| .iter() | ||
| .all(|id| !patched_urls.contains(id.canonical_url())) => | ||
| { | ||
| let mut help = "perhaps you meant one of the following:".to_owned(); | ||
| for id in ids { | ||
| help.push_str("\n\t"); | ||
| help.push_str(&id.display_registry_name()); | ||
| for (url, summaries) in registry.patches().iter() { | ||
| for summary in summaries.iter() { | ||
| let unused = summary.package_id(); | ||
| if !used_patches.contains(&(url.clone(), unused)) { | ||
| // Show alternative source URLs if the source URLs being patched | ||
| // cannot be found in the crate graph. | ||
| match source_ids_grouped_by_pkg_name.get(&unused.name()) { | ||
| Some(ids) if ids.iter().all(|id| id.canonical_url() != url) => { | ||
| let mut ids: Vec<_> = ids.into_iter().collect(); | ||
| ids.sort_by_key(|id| id.url()); // SourceId implements Ord but url() is safe | ||
| let mut help = "perhaps you meant one of the following:".to_owned(); | ||
| for id in ids { | ||
| help.push_str("\n\t"); | ||
| help.push_str(&id.display_registry_name()); | ||
| } | ||
| ws.gctx().shell().print_report( | ||
| &[Level::WARNING | ||
| .secondary_title(format!("patch `{unused}` {MESSAGE}")) | ||
| .element(Level::HELP.message(help))], | ||
| false, | ||
| )?; | ||
| } | ||
| _ => unemitted_unused_patches.push(unused), | ||
|
Comment on lines
+839
to
+861
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change means X is in Will this cause any issues for consumers of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my exploration, the main consumers of With this change, if a To fully fix this ambiguity without confusion, we might actually need to make |
||
| } | ||
| ws.gctx().shell().print_report( | ||
| &[Level::WARNING | ||
| .secondary_title(format!("patch `{unused}` {MESSAGE}")) | ||
| .element(Level::HELP.message(help))], | ||
| false, | ||
| )?; | ||
| } | ||
| _ => unemitted_unused_patches.push(unused), | ||
| } | ||
| } | ||
|
|
||
| // Deduplicate general warnings by PackageId | ||
| unemitted_unused_patches.sort(); | ||
| unemitted_unused_patches.dedup(); | ||
|
|
||
| // Show general help message. | ||
| if !unemitted_unused_patches.is_empty() { | ||
| let mut warnings: Vec<_> = unemitted_unused_patches | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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 seems we literally build the same set twice: once in
register_used_patchesand once here.View changes since the review
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.
One solution could be to maintain an
unused_patches_with_urlthat also includes the URL. But we need to consider this issue first to evaluate the real impact of this change.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 intentionally built the set twice locally to strictly avoid altering the
Resolvestruct, because modifying or replacingunused_patchescould affect how[patch.unused]is encoded incargo.lockviaencode.rs.If we add
unused_patches_with_urltoResolve, should we keep it as a purely in-memory field (and skip serializing it), or are you open to modifying the lockfile structure to store the URLs as well?