From f49a8f44ab46e45b9ca52d327f59055acd0ea86e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 20:35:53 -0600 Subject: [PATCH 01/19] test(update): Show behind on breaking --- tests/testsuite/update.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 0d283d58079..90a6dab36bc 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1473,3 +1473,34 @@ fn precise_yanked_multiple_presence() { let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.1\"")); } + +#[cargo_test] +fn report_behind() { + Package::new("breaking", "0.1.0").publish(); + Package::new("breaking", "0.2.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + + [dependencies] + breaking = "0.1" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("generate-lockfile").run(); + Package::new("breaking", "0.1.1").publish(); + + p.cargo("update") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[UPDATING] breaking v0.1.0 -> v0.1.1 +", + ) + .run(); +} From 47a006eeea306243df9aaba676f5e91ef2ffb72e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 20:38:35 -0600 Subject: [PATCH 02/19] feat(update): Show available breaking versions --- src/cargo/ops/cargo_generate_lockfile.rs | 37 ++++++++++++++++++++++-- tests/testsuite/update.rs | 2 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index e638c69390f..66e9a66c267 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -1,8 +1,10 @@ use crate::core::registry::PackageRegistry; use crate::core::resolver::features::{CliFeatures, HasDevUnits}; +use crate::core::Registry as _; use crate::core::{PackageId, PackageIdSpec, PackageIdSpecQuery}; use crate::core::{Resolve, SourceId, Workspace}; use crate::ops; +use crate::sources::source::QueryKind; use crate::util::cache_lock::CacheLockMode; use crate::util::config::Config; use crate::util::style; @@ -162,6 +164,35 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes opts.config.shell().status_with_color(status, msg, color) }; for (removed, added) in compare_dependency_graphs(&previous_resolve, &resolve) { + let latest = if let Some(added) = added + .iter() + .rev() + .next() + .filter(|p| p.source_id().is_registry()) + { + let query = + crate::core::dependency::Dependency::parse(added.name(), None, added.source_id())?; + let possibilities = loop { + match registry.query_vec(&query, QueryKind::Exact) { + std::task::Poll::Ready(res) => { + break res?; + } + std::task::Poll::Pending => registry.block_until_ready()?, + } + }; + let warn = style::WARN; + possibilities + .iter() + .map(|s| s.as_summary()) + .map(|s| s.version().clone()) + .max() + .filter(|v| added.version() < v) + .map(|v| format!(" {warn}(latest: v{v}){warn:#}")) + } else { + None + } + .unwrap_or_default(); + if removed.len() == 1 && added.len() == 1 { let msg = if removed[0].source_id().is_git() { format!( @@ -170,7 +201,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes &added[0].source_id().precise_git_fragment().unwrap()[..8], ) } else { - format!("{} -> v{}", removed[0], added[0].version()) + format!("{} -> v{}{latest}", removed[0], added[0].version()) }; // If versions differ only in build metadata, we call it an "update" @@ -184,10 +215,10 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes } } else { for package in removed.iter() { - print_change("Removing", format!("{}", package), &style::ERROR)?; + print_change("Removing", format!("{package}"), &style::ERROR)?; } for package in added.iter() { - print_change("Adding", format!("{}", package), &style::NOTE)?; + print_change("Adding", format!("{package}{latest}"), &style::NOTE)?; } } } diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 90a6dab36bc..33dc1fa0d08 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1499,7 +1499,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[UPDATING] breaking v0.1.0 -> v0.1.1 +[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) ", ) .run(); From e7f1009bc451d86c0285e68e577a829fd3dc1d4b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 20:41:47 -0600 Subject: [PATCH 03/19] test(update): Latest alpha is shown --- tests/testsuite/update.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 33dc1fa0d08..2a02991da31 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1478,6 +1478,7 @@ fn precise_yanked_multiple_presence() { fn report_behind() { Package::new("breaking", "0.1.0").publish(); Package::new("breaking", "0.2.0").publish(); + Package::new("breaking", "0.2.1-alpha.0").publish(); let p = project() .file( "Cargo.toml", @@ -1499,7 +1500,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) +[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.1-alpha.0) ", ) .run(); From a1db0b1383b40cafe50e24499b28e9ea5f840b4b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 20:45:35 -0600 Subject: [PATCH 04/19] fix(update): Don't bother listing pre-release There might be casses where we want to show pre-release as this grows but, for now, there isn't too often a case where an update is held back, you are on a pre-release, your pre-release is updating, and you want a pre-release. --- src/cargo/ops/cargo_generate_lockfile.rs | 1 + tests/testsuite/update.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 66e9a66c267..051d5306536 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -184,6 +184,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes possibilities .iter() .map(|s| s.as_summary()) + .filter(|s| s.version().pre.is_empty()) .map(|s| s.version().clone()) .max() .filter(|v| added.version() < v) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 2a02991da31..a633a7ab3e5 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1500,7 +1500,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.1-alpha.0) +[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) ", ) .run(); From 94f67d09173af441f3f4b333ea71a22726513c51 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 30 Jan 2024 15:46:17 -0600 Subject: [PATCH 05/19] test(update): Compare verbose with and without updates --- tests/testsuite/update.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index a633a7ab3e5..1577d7d43d6 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1496,11 +1496,42 @@ fn report_behind() { p.cargo("generate-lockfile").run(); Package::new("breaking", "0.1.1").publish(); - p.cargo("update") + p.cargo("update --dry-run") .with_stderr( "\ [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) +[WARNING] not updating lockfile due to dry run +", + ) + .run(); + + p.cargo("update --dry-run --verbose") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) +[WARNING] not updating lockfile due to dry run +", + ) + .run(); + + p.cargo("update").run(); + + p.cargo("update --dry-run") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[WARNING] not updating lockfile due to dry run +", + ) + .run(); + + p.cargo("update --dry-run --verbose") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[WARNING] not updating lockfile due to dry run ", ) .run(); From 8a250857172989e2a8287fa939db929efa2844f0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 21:02:22 -0600 Subject: [PATCH 06/19] refactor(update): Pull out package_id search --- src/cargo/ops/cargo_generate_lockfile.rs | 56 ++++++++++++------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 051d5306536..f1de0f6eb30 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -255,37 +255,35 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes (dep.name().as_str(), dep.source_id()) } - // Removes all package IDs in `b` from `a`. Note that this is somewhat - // more complicated because the equality for source IDs does not take - // precise versions into account (e.g., git shas), but we want to take - // that into account here. fn vec_subtract(a: &[PackageId], b: &[PackageId]) -> Vec { - a.iter() - .filter(|a| { - // If this package ID is not found in `b`, then it's definitely - // in the subtracted set. - let Ok(i) = b.binary_search(a) else { - return true; - }; + a.iter().filter(|a| !contains_id(b, a)).cloned().collect() + } - // If we've found `a` in `b`, then we iterate over all instances - // (we know `b` is sorted) and see if they all have different - // precise versions. If so, then `a` isn't actually in `b` so - // we'll let it through. - // - // Note that we only check this for non-registry sources, - // however, as registries contain enough version information in - // the package ID to disambiguate. - if a.source_id().is_registry() { - return false; - } - b[i..] - .iter() - .take_while(|b| a == b) - .all(|b| !a.source_id().has_same_precise_as(b.source_id())) - }) - .cloned() - .collect() + // Check if a PackageId is present `b` from `a`. + // + // Note that this is somewhat more complicated because the equality for source IDs does not + // take precise versions into account (e.g., git shas), but we want to take that into + // account here. + fn contains_id(haystack: &[PackageId], needle: &PackageId) -> bool { + let Ok(i) = haystack.binary_search(needle) else { + return false; + }; + + // If we've found `a` in `b`, then we iterate over all instances + // (we know `b` is sorted) and see if they all have different + // precise versions. If so, then `a` isn't actually in `b` so + // we'll let it through. + // + // Note that we only check this for non-registry sources, + // however, as registries contain enough version information in + // the package ID to disambiguate. + if needle.source_id().is_registry() { + return true; + } + haystack[i..] + .iter() + .take_while(|b| &needle == b) + .any(|b| needle.source_id().has_same_precise_as(b.source_id())) } // Map `(package name, package source)` to `(removed versions, added versions)`. From c75feb93a8e51b8d806c13aa3e474e0b631ac5eb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 21:04:09 -0600 Subject: [PATCH 07/19] refactor(update): Use set terminology --- src/cargo/ops/cargo_generate_lockfile.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index f1de0f6eb30..cb613bdaae7 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -255,7 +255,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes (dep.name().as_str(), dep.source_id()) } - fn vec_subtract(a: &[PackageId], b: &[PackageId]) -> Vec { + fn vec_subset(a: &[PackageId], b: &[PackageId]) -> Vec { a.iter().filter(|a| !contains_id(b, a)).cloned().collect() } @@ -308,8 +308,8 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes let (ref mut old, ref mut new) = *v; old.sort(); new.sort(); - let removed = vec_subtract(old, new); - let added = vec_subtract(new, old); + let removed = vec_subset(old, new); + let added = vec_subset(new, old); *old = removed; *new = added; } From b4ad2062056924fb096f855995b0834c80eabd43 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 30 Jan 2024 19:29:46 -0600 Subject: [PATCH 08/19] test(update): Show behavior for missing feature --- tests/testsuite/update.rs | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 1577d7d43d6..d6330939a8b 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1536,3 +1536,48 @@ fn report_behind() { ) .run(); } + +#[cargo_test] +fn update_with_missing_feature() { + // Attempting to update a package to a version with a missing feature + // should produce a warning. + Package::new("bar", "0.1.0").feature("feat1", &[]).publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {version="0.1", features=["feat1"]} + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("generate-lockfile").run(); + + // Publish an update that is missing the feature. + Package::new("bar", "0.1.1").publish(); + + p.cargo("update") + .with_stderr( + "\ +[UPDATING] `[..]` index +", + ) + .run(); + + // Publish a fixed version, should not warn. + Package::new("bar", "0.1.2").feature("feat1", &[]).publish(); + p.cargo("update") + .with_stderr( + "\ +[UPDATING] `[..]` index +[UPDATING] bar v0.1.0 -> v0.1.2 +", + ) + .run(); +} From c89ac1f2340672fa9456236be31ad236f300c94f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Jan 2024 21:06:02 -0600 Subject: [PATCH 09/19] feat(update): Summarize unchanged packages with updates `--verbose` will show them. This is prep for telling the user about `--breaking` and other flags. --- crates/cargo-test-support/src/compare.rs | 1 + src/cargo/ops/cargo_generate_lockfile.rs | 55 ++++++++++++++++++------ tests/testsuite/patch.rs | 1 + tests/testsuite/registry.rs | 1 + tests/testsuite/replace.rs | 2 + tests/testsuite/update.rs | 7 +++ 6 files changed, 55 insertions(+), 12 deletions(-) diff --git a/crates/cargo-test-support/src/compare.rs b/crates/cargo-test-support/src/compare.rs index e28c9459206..b9194fcd0f1 100644 --- a/crates/cargo-test-support/src/compare.rs +++ b/crates/cargo-test-support/src/compare.rs @@ -208,6 +208,7 @@ fn substitute_macros(input: &str) -> String { ("[ADDING]", " Adding"), ("[REMOVING]", " Removing"), ("[REMOVED]", " Removed"), + ("[UNCHANGED]", " Unchanged"), ("[DOCTEST]", " Doc-tests"), ("[PACKAGING]", " Packaging"), ("[PACKAGED]", " Packaged"), diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index cb613bdaae7..b0e7b138d64 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -1,5 +1,6 @@ use crate::core::registry::PackageRegistry; use crate::core::resolver::features::{CliFeatures, HasDevUnits}; +use crate::core::shell::Verbosity; use crate::core::Registry as _; use crate::core::{PackageId, PackageIdSpec, PackageIdSpecQuery}; use crate::core::{Resolve, SourceId, Workspace}; @@ -163,15 +164,19 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes let print_change = |status: &str, msg: String, color: &Style| { opts.config.shell().status_with_color(status, msg, color) }; - for (removed, added) in compare_dependency_graphs(&previous_resolve, &resolve) { - let latest = if let Some(added) = added - .iter() - .rev() - .next() - .filter(|p| p.source_id().is_registry()) + let mut unchanged_behind = 0; + for (removed, added, unchanged) in compare_dependency_graphs(&previous_resolve, &resolve) { + let highest_present = [added.iter().rev().next(), unchanged.iter().rev().next()] + .into_iter() + .flatten() + .max_by_key(|s| s.version()); + let latest = if let Some(present) = highest_present.filter(|p| p.source_id().is_registry()) { - let query = - crate::core::dependency::Dependency::parse(added.name(), None, added.source_id())?; + let query = crate::core::dependency::Dependency::parse( + present.name(), + None, + present.source_id(), + )?; let possibilities = loop { match registry.query_vec(&query, QueryKind::Exact) { std::task::Poll::Ready(res) => { @@ -187,7 +192,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes .filter(|s| s.version().pre.is_empty()) .map(|s| s.version().clone()) .max() - .filter(|v| added.version() < v) + .filter(|v| present.version() < v) .map(|v| format!(" {warn}(latest: v{v}){warn:#}")) } else { None @@ -222,6 +227,26 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes print_change("Adding", format!("{package}{latest}"), &style::NOTE)?; } } + if !latest.is_empty() { + if opts.config.shell().verbosity() == Verbosity::Verbose { + for package in &unchanged { + opts.config.shell().status_with_color( + "Unchanged", + format!("{package}{latest}"), + &anstyle::Style::new().bold(), + )?; + } + } else { + if !unchanged.is_empty() { + unchanged_behind += 1; + } + } + } + } + if 0 < unchanged_behind { + opts.config.shell().note(format!( + "Pass `--verbose` to see {unchanged_behind} unchanged dependencies behind latest" + ))?; } if opts.dry_run { opts.config @@ -250,7 +275,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes fn compare_dependency_graphs( previous_resolve: &Resolve, resolve: &Resolve, - ) -> Vec<(Vec, Vec)> { + ) -> Vec<(Vec, Vec, Vec)> { fn key(dep: PackageId) -> (&'static str, SourceId) { (dep.name().as_str(), dep.source_id()) } @@ -259,6 +284,10 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes a.iter().filter(|a| !contains_id(b, a)).cloned().collect() } + fn vec_intersection(a: &[PackageId], b: &[PackageId]) -> Vec { + a.iter().filter(|a| contains_id(b, a)).cloned().collect() + } + // Check if a PackageId is present `b` from `a`. // // Note that this is somewhat more complicated because the equality for source IDs does not @@ -288,7 +317,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes // Map `(package name, package source)` to `(removed versions, added versions)`. let mut changes = BTreeMap::new(); - let empty = (Vec::new(), Vec::new()); + let empty = (Vec::new(), Vec::new(), Vec::new()); for dep in previous_resolve.iter() { changes .entry(key(dep)) @@ -305,13 +334,15 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes } for v in changes.values_mut() { - let (ref mut old, ref mut new) = *v; + let (ref mut old, ref mut new, ref mut other) = *v; old.sort(); new.sort(); let removed = vec_subset(old, new); let added = vec_subset(new, old); + let unchanged = vec_intersection(new, old); *old = removed; *new = added; + *other = unchanged; } debug!("{:#?}", changes); diff --git a/tests/testsuite/patch.rs b/tests/testsuite/patch.rs index 55cab58c8b5..e75f6f73068 100644 --- a/tests/testsuite/patch.rs +++ b/tests/testsuite/patch.rs @@ -2430,6 +2430,7 @@ fn can_update_with_alt_reg() { "\ [UPDATING] `alternative` index [UPDATING] `dummy-registry` index +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index df174c0fa6a..5df94b7692d 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -1572,6 +1572,7 @@ fn update_multiple_packages() { [UPDATING] `[..]` index [UPDATING] a v0.1.0 -> v0.1.1 [UPDATING] b v0.1.0 -> v0.1.1 +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/replace.rs b/tests/testsuite/replace.rs index 6c31a023e79..b7550194776 100644 --- a/tests/testsuite/replace.rs +++ b/tests/testsuite/replace.rs @@ -539,6 +539,7 @@ fn override_adds_some_deps() { "\ [UPDATING] git repository `file://[..]` [UPDATING] `dummy-registry` index +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -546,6 +547,7 @@ fn override_adds_some_deps() { .with_stderr( "\ [UPDATING] `dummy-registry` index +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index d6330939a8b..23243ea4029 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -109,6 +109,7 @@ fn transitive_minor_update() { .with_stderr( "\ [UPDATING] `[..]` index +[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest ", ) .run(); @@ -160,6 +161,7 @@ fn conservative() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.1.0 -> v0.1.1 +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -520,6 +522,7 @@ fn update_precise_do_not_force_update_deps() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.2.1 -> v0.2.2 +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -898,6 +901,7 @@ fn dry_run_update() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.1.0 -> v0.1.1 +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1522,6 +1526,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1531,6 +1536,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index +[UNCHANGED] breaking v0.1.1 (latest: v0.2.0) [WARNING] not updating lockfile due to dry run ", ) @@ -1566,6 +1572,7 @@ fn update_with_missing_feature() { .with_stderr( "\ [UPDATING] `[..]` index +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); From 21dfe88079f94e58919a15969c4a9277243b9e5b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 30 Jan 2024 16:34:54 -0600 Subject: [PATCH 10/19] fix(update): Call out pre-releases when relevant --- src/cargo/ops/cargo_generate_lockfile.rs | 10 +++++++++- tests/testsuite/update.rs | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index b0e7b138d64..f401001bd42 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -186,10 +186,18 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes } }; let warn = style::WARN; + let present_version = present.version(); possibilities .iter() .map(|s| s.as_summary()) - .filter(|s| s.version().pre.is_empty()) + .filter(|s| { + let s_version = s.version(); + s_version.pre.is_empty() + // Only match pre-release if major.minor.patch are the same + || (s_version.major == present_version.major + && s_version.minor == present_version.minor + && s_version.patch == present_version.patch) + }) .map(|s| s.version().clone()) .max() .filter(|v| present.version() < v) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 23243ea4029..5dd8d726e91 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1480,6 +1480,8 @@ fn precise_yanked_multiple_presence() { #[cargo_test] fn report_behind() { + Package::new("pre", "1.0.0-alpha.0").publish(); + Package::new("pre", "1.0.0-alpha.1").publish(); Package::new("breaking", "0.1.0").publish(); Package::new("breaking", "0.2.0").publish(); Package::new("breaking", "0.2.1-alpha.0").publish(); @@ -1492,6 +1494,7 @@ fn report_behind() { [dependencies] breaking = "0.1" + pre = "=1.0.0-alpha.0" "#, ) .file("src/lib.rs", "") @@ -1505,6 +1508,7 @@ fn report_behind() { "\ [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1515,6 +1519,7 @@ fn report_behind() { "\ [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) +[UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) [WARNING] not updating lockfile due to dry run ", ) @@ -1526,7 +1531,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1537,6 +1542,7 @@ fn report_behind() { "\ [UPDATING] `dummy-registry` index [UNCHANGED] breaking v0.1.1 (latest: v0.2.0) +[UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) [WARNING] not updating lockfile due to dry run ", ) From 967e199be79b34aae9db89632919f4c605f5a8f8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 30 Jan 2024 20:49:21 -0600 Subject: [PATCH 11/19] test(update): Remove unnecesary verbose --- tests/testsuite/git.rs | 2 +- tests/testsuite/local_registry.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index 96d35a45993..6007f04732d 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -1372,7 +1372,7 @@ fn dep_with_changed_submodule() { sleep_ms(1000); // Update the dependency and carry on! println!("update"); - p.cargo("update -v") + p.cargo("update") .with_stderr("") .with_stderr(&format!( "[UPDATING] git repository `{}`\n\ diff --git a/tests/testsuite/local_registry.rs b/tests/testsuite/local_registry.rs index 4e00e0ecd62..3c08f4662b1 100644 --- a/tests/testsuite/local_registry.rs +++ b/tests/testsuite/local_registry.rs @@ -183,7 +183,7 @@ fn multiple_versions() { .file("src/lib.rs", "pub fn bar() {}") .publish(); - p.cargo("update -v") + p.cargo("update") .with_stderr("[UPDATING] bar v0.1.0 -> v0.2.0") .run(); } From b05dc26a084a3fec764f8129649572327de10c86 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 30 Jan 2024 19:20:23 -0600 Subject: [PATCH 12/19] fix(update): Help people discover how they pull in a stale dep I put this behind `--verbose` - To keep the output down in the standard case - Because its assuming most people's "behind" dependencies will be "Unchanged" and so that is when knowing how to look up how its pulled in is useful --- src/cargo/ops/cargo_generate_lockfile.rs | 19 +++++++++++-------- tests/testsuite/update.rs | 2 ++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index f401001bd42..e13894bba3d 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -244,17 +244,20 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes &anstyle::Style::new().bold(), )?; } - } else { - if !unchanged.is_empty() { - unchanged_behind += 1; - } } + unchanged_behind += unchanged.len(); } } - if 0 < unchanged_behind { - opts.config.shell().note(format!( - "Pass `--verbose` to see {unchanged_behind} unchanged dependencies behind latest" - ))?; + if opts.config.shell().verbosity() == Verbosity::Verbose { + opts.config.shell().note( + "To see how you depend on a package, run `cargo tree --invert --package @`", + )?; + } else { + if 0 < unchanged_behind { + opts.config.shell().note(format!( + "Pass `--verbose` to see {unchanged_behind} unchanged dependencies behind latest" + ))?; + } } if opts.dry_run { opts.config diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 5dd8d726e91..73baa7a3419 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1520,6 +1520,7 @@ fn report_behind() { [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) +[NOTE] To see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", ) @@ -1543,6 +1544,7 @@ fn report_behind() { [UPDATING] `dummy-registry` index [UNCHANGED] breaking v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) +[NOTE] To see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", ) From 0034ea3bbfb3fe90f3310c84460f24b90848cee8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Feb 2024 12:59:30 -0600 Subject: [PATCH 13/19] test(update): Show lack of message on old --- tests/testsuite/update.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 73baa7a3419..5337d1b409c 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -1480,6 +1480,8 @@ fn precise_yanked_multiple_presence() { #[cargo_test] fn report_behind() { + Package::new("two-ver", "0.1.0").publish(); + Package::new("two-ver", "0.2.0").publish(); Package::new("pre", "1.0.0-alpha.0").publish(); Package::new("pre", "1.0.0-alpha.1").publish(); Package::new("breaking", "0.1.0").publish(); @@ -1495,6 +1497,8 @@ fn report_behind() { [dependencies] breaking = "0.1" pre = "=1.0.0-alpha.0" + two-ver = "0.2.0" + two-ver-one = { version = "0.1.0", package = "two-ver" } "#, ) .file("src/lib.rs", "") From b7a0d9b94c2295bc8d0ff70c9040f992249d07c2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Feb 2024 13:01:24 -0600 Subject: [PATCH 14/19] refactor(update): Pull out latest formatting logic --- src/cargo/ops/cargo_generate_lockfile.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index e13894bba3d..232d64115a5 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -166,6 +166,11 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes }; let mut unchanged_behind = 0; for (removed, added, unchanged) in compare_dependency_graphs(&previous_resolve, &resolve) { + fn format_latest(version: semver::Version) -> String { + let warn = style::WARN; + format!(" {warn}(latest: v{version}){warn:#}") + } + let highest_present = [added.iter().rev().next(), unchanged.iter().rev().next()] .into_iter() .flatten() @@ -185,7 +190,6 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes std::task::Poll::Pending => registry.block_until_ready()?, } }; - let warn = style::WARN; let present_version = present.version(); possibilities .iter() @@ -201,7 +205,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes .map(|s| s.version().clone()) .max() .filter(|v| present.version() < v) - .map(|v| format!(" {warn}(latest: v{v}){warn:#}")) + .map(format_latest) } else { None } From de15651fa8986a0f8a9a3a0f69c1d6cb253980ee Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Feb 2024 13:06:46 -0600 Subject: [PATCH 15/19] refactor(update): Pull out is_latest check --- src/cargo/ops/cargo_generate_lockfile.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 232d64115a5..61ac9ee3e06 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -170,6 +170,14 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes let warn = style::WARN; format!(" {warn}(latest: v{version}){warn:#}") } + fn is_latest(candidate: &semver::Version, current: &semver::Version) -> bool { + current < candidate + // Only match pre-release if major.minor.patch are the same + && (candidate.pre.is_empty() + || (candidate.major == current.major + && candidate.minor == current.minor + && candidate.patch == current.patch)) + } let highest_present = [added.iter().rev().next(), unchanged.iter().rev().next()] .into_iter() @@ -194,17 +202,9 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes possibilities .iter() .map(|s| s.as_summary()) - .filter(|s| { - let s_version = s.version(); - s_version.pre.is_empty() - // Only match pre-release if major.minor.patch are the same - || (s_version.major == present_version.major - && s_version.minor == present_version.minor - && s_version.patch == present_version.patch) - }) + .filter(|s| is_latest(s.version(), present_version)) .map(|s| s.version().clone()) .max() - .filter(|v| present.version() < v) .map(format_latest) } else { None From 90b10cd2a23b54630b0d8d31473cd7d3b2e10da1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Feb 2024 13:14:48 -0600 Subject: [PATCH 16/19] refactor(update): Simplify Upgrade/Downgrade display logic --- src/cargo/ops/cargo_generate_lockfile.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 61ac9ee3e06..ecc434c9c09 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -212,21 +212,22 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes .unwrap_or_default(); if removed.len() == 1 && added.len() == 1 { - let msg = if removed[0].source_id().is_git() { + let added = added.into_iter().next().unwrap(); + let removed = removed.into_iter().next().unwrap(); + let msg = if removed.source_id().is_git() { format!( - "{} -> #{}", - removed[0], - &added[0].source_id().precise_git_fragment().unwrap()[..8], + "{removed} -> #{}", + &added.source_id().precise_git_fragment().unwrap()[..8], ) } else { - format!("{} -> v{}{latest}", removed[0], added[0].version()) + format!("{removed} -> v{}{latest}", added.version()) }; // If versions differ only in build metadata, we call it an "update" // regardless of whether the build metadata has gone up or down. // This metadata is often stuff like git commit hashes, which are // not meaningfully ordered. - if removed[0].version().cmp_precedence(added[0].version()) == Ordering::Greater { + if removed.version().cmp_precedence(added.version()) == Ordering::Greater { print_change("Downgrading", msg, &style::WARN)?; } else { print_change("Updating", msg, &style::GOOD)?; From dce58dc76d2ce47162bb78469bf70ac8ed6eab0a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Feb 2024 14:01:07 -0600 Subject: [PATCH 17/19] fix(update): Show updates for all relevant packages --- src/cargo/ops/cargo_generate_lockfile.rs | 78 ++++++++++++++++-------- tests/testsuite/update.rs | 7 ++- 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index ecc434c9c09..2d02622cfa1 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -178,42 +178,43 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes && candidate.minor == current.minor && candidate.patch == current.patch)) } - - let highest_present = [added.iter().rev().next(), unchanged.iter().rev().next()] + let possibilities = if let Some(query) = [added.iter(), unchanged.iter()] .into_iter() .flatten() - .max_by_key(|s| s.version()); - let latest = if let Some(present) = highest_present.filter(|p| p.source_id().is_registry()) + .next() + .filter(|s| s.source_id().is_registry()) { - let query = crate::core::dependency::Dependency::parse( - present.name(), - None, - present.source_id(), - )?; - let possibilities = loop { + let query = + crate::core::dependency::Dependency::parse(query.name(), None, query.source_id())?; + loop { match registry.query_vec(&query, QueryKind::Exact) { std::task::Poll::Ready(res) => { break res?; } std::task::Poll::Pending => registry.block_until_ready()?, } - }; - let present_version = present.version(); - possibilities - .iter() - .map(|s| s.as_summary()) - .filter(|s| is_latest(s.version(), present_version)) - .map(|s| s.version().clone()) - .max() - .map(format_latest) + } } else { - None - } - .unwrap_or_default(); + vec![] + }; if removed.len() == 1 && added.len() == 1 { let added = added.into_iter().next().unwrap(); let removed = removed.into_iter().next().unwrap(); + + let latest = if !possibilities.is_empty() { + possibilities + .iter() + .map(|s| s.as_summary()) + .filter(|s| is_latest(s.version(), added.version())) + .map(|s| s.version().clone()) + .max() + .map(format_latest) + } else { + None + } + .unwrap_or_default(); + let msg = if removed.source_id().is_git() { format!( "{removed} -> #{}", @@ -237,12 +238,38 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes print_change("Removing", format!("{package}"), &style::ERROR)?; } for package in added.iter() { + let latest = if !possibilities.is_empty() { + possibilities + .iter() + .map(|s| s.as_summary()) + .filter(|s| is_latest(s.version(), package.version())) + .map(|s| s.version().clone()) + .max() + .map(format_latest) + } else { + None + } + .unwrap_or_default(); + print_change("Adding", format!("{package}{latest}"), &style::NOTE)?; } } - if !latest.is_empty() { - if opts.config.shell().verbosity() == Verbosity::Verbose { - for package in &unchanged { + for package in &unchanged { + let latest = if !possibilities.is_empty() { + possibilities + .iter() + .map(|s| s.as_summary()) + .filter(|s| is_latest(s.version(), package.version())) + .map(|s| s.version().clone()) + .max() + .map(format_latest) + } else { + None + }; + + if let Some(latest) = latest { + unchanged_behind += 1; + if opts.config.shell().verbosity() == Verbosity::Verbose { opts.config.shell().status_with_color( "Unchanged", format!("{package}{latest}"), @@ -250,7 +277,6 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes )?; } } - unchanged_behind += unchanged.len(); } } if opts.config.shell().verbosity() == Verbosity::Verbose { diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 5337d1b409c..9d0ba38fcea 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -388,6 +388,7 @@ fn update_precise() { "\ [UPDATING] `[..]` index [DOWNGRADING] serde v0.2.1 -> v0.2.0 +[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -1512,7 +1513,7 @@ fn report_behind() { "\ [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1524,6 +1525,7 @@ fn report_behind() { [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) +[UNCHANGED] two-ver v0.1.0 (latest: v0.2.0) [NOTE] To see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", @@ -1536,7 +1538,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest +[NOTE] Pass `--verbose` to see 3 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1548,6 +1550,7 @@ fn report_behind() { [UPDATING] `dummy-registry` index [UNCHANGED] breaking v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) +[UNCHANGED] two-ver v0.1.0 (latest: v0.2.0) [NOTE] To see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", From 012ca52bcccc5f56da366194c72a368f15ad8c6e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 5 Feb 2024 10:55:01 -0600 Subject: [PATCH 18/19] fix(update): Start note/warn with lowercase --- src/cargo/ops/cargo_generate_lockfile.rs | 4 ++-- tests/testsuite/patch.rs | 2 +- tests/testsuite/registry.rs | 2 +- tests/testsuite/replace.rs | 4 ++-- tests/testsuite/update.rs | 20 ++++++++++---------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 2d02622cfa1..2149bbfbfa1 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -281,12 +281,12 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes } if opts.config.shell().verbosity() == Verbosity::Verbose { opts.config.shell().note( - "To see how you depend on a package, run `cargo tree --invert --package @`", + "to see how you depend on a package, run `cargo tree --invert --package @`", )?; } else { if 0 < unchanged_behind { opts.config.shell().note(format!( - "Pass `--verbose` to see {unchanged_behind} unchanged dependencies behind latest" + "pass `--verbose` to see {unchanged_behind} unchanged dependencies behind latest" ))?; } } diff --git a/tests/testsuite/patch.rs b/tests/testsuite/patch.rs index e75f6f73068..d5ab1182170 100644 --- a/tests/testsuite/patch.rs +++ b/tests/testsuite/patch.rs @@ -2430,7 +2430,7 @@ fn can_update_with_alt_reg() { "\ [UPDATING] `alternative` index [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index 5df94b7692d..3c73ce50101 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -1572,7 +1572,7 @@ fn update_multiple_packages() { [UPDATING] `[..]` index [UPDATING] a v0.1.0 -> v0.1.1 [UPDATING] b v0.1.0 -> v0.1.1 -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/replace.rs b/tests/testsuite/replace.rs index b7550194776..df684187607 100644 --- a/tests/testsuite/replace.rs +++ b/tests/testsuite/replace.rs @@ -539,7 +539,7 @@ fn override_adds_some_deps() { "\ [UPDATING] git repository `file://[..]` [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -547,7 +547,7 @@ fn override_adds_some_deps() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index 9d0ba38fcea..6f90aacbdff 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -109,7 +109,7 @@ fn transitive_minor_update() { .with_stderr( "\ [UPDATING] `[..]` index -[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 2 unchanged dependencies behind latest ", ) .run(); @@ -161,7 +161,7 @@ fn conservative() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.1.0 -> v0.1.1 -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -388,7 +388,7 @@ fn update_precise() { "\ [UPDATING] `[..]` index [DOWNGRADING] serde v0.2.1 -> v0.2.0 -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -523,7 +523,7 @@ fn update_precise_do_not_force_update_deps() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.2.1 -> v0.2.2 -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); @@ -902,7 +902,7 @@ fn dry_run_update() { "\ [UPDATING] `[..]` index [UPDATING] serde v0.1.0 -> v0.1.1 -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1513,7 +1513,7 @@ fn report_behind() { "\ [UPDATING] `dummy-registry` index [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) -[NOTE] Pass `--verbose` to see 2 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 2 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1526,7 +1526,7 @@ fn report_behind() { [UPDATING] breaking v0.1.0 -> v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) [UNCHANGED] two-ver v0.1.0 (latest: v0.2.0) -[NOTE] To see how you depend on a package, run `cargo tree --invert --package @` +[NOTE] to see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", ) @@ -1538,7 +1538,7 @@ fn report_behind() { .with_stderr( "\ [UPDATING] `dummy-registry` index -[NOTE] Pass `--verbose` to see 3 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 3 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run ", ) @@ -1551,7 +1551,7 @@ fn report_behind() { [UNCHANGED] breaking v0.1.1 (latest: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (latest: v1.0.0-alpha.1) [UNCHANGED] two-ver v0.1.0 (latest: v0.2.0) -[NOTE] To see how you depend on a package, run `cargo tree --invert --package @` +[NOTE] to see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run ", ) @@ -1587,7 +1587,7 @@ fn update_with_missing_feature() { .with_stderr( "\ [UPDATING] `[..]` index -[NOTE] Pass `--verbose` to see 1 unchanged dependencies behind latest +[NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest ", ) .run(); From 93e369a2ae99b28e18c6c7542dd2c51f96fcf015 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 5 Feb 2024 11:03:55 -0600 Subject: [PATCH 19/19] refactor(update): Clarify return type --- src/cargo/ops/cargo_generate_lockfile.rs | 27 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs index 2149bbfbfa1..fa75ad1bb72 100644 --- a/src/cargo/ops/cargo_generate_lockfile.rs +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -165,7 +165,12 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes opts.config.shell().status_with_color(status, msg, color) }; let mut unchanged_behind = 0; - for (removed, added, unchanged) in compare_dependency_graphs(&previous_resolve, &resolve) { + for ResolvedPackageVersions { + removed, + added, + unchanged, + } in compare_dependency_graphs(&previous_resolve, &resolve) + { fn format_latest(version: semver::Version) -> String { let warn = style::WARN; format!(" {warn}(latest: v{version}){warn:#}") @@ -314,10 +319,16 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes } } + #[derive(Default, Clone, Debug)] + struct ResolvedPackageVersions { + removed: Vec, + added: Vec, + unchanged: Vec, + } fn compare_dependency_graphs( previous_resolve: &Resolve, resolve: &Resolve, - ) -> Vec<(Vec, Vec, Vec)> { + ) -> Vec { fn key(dep: PackageId) -> (&'static str, SourceId) { (dep.name().as_str(), dep.source_id()) } @@ -359,24 +370,28 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes // Map `(package name, package source)` to `(removed versions, added versions)`. let mut changes = BTreeMap::new(); - let empty = (Vec::new(), Vec::new(), Vec::new()); + let empty = ResolvedPackageVersions::default(); for dep in previous_resolve.iter() { changes .entry(key(dep)) .or_insert_with(|| empty.clone()) - .0 + .removed .push(dep); } for dep in resolve.iter() { changes .entry(key(dep)) .or_insert_with(|| empty.clone()) - .1 + .added .push(dep); } for v in changes.values_mut() { - let (ref mut old, ref mut new, ref mut other) = *v; + let ResolvedPackageVersions { + removed: ref mut old, + added: ref mut new, + unchanged: ref mut other, + } = *v; old.sort(); new.sort(); let removed = vec_subset(old, new);