Skip to content

Commit ba8b394

Browse files
committed
Auto merge of #14401 - epage:required-rust, r=weihanglo
feat(update): Report when incompatible-rust-version packages are selected ### What does this PR try to resolve? In discussin this in #13873, it highlighted that we need to make sure we tell people when incompatible-rust-version packages are selected. I decided to keep "latest" and "required rust version" messages mutually exclusive to avoid too much noise. I gave "required rust version" higher precedence as its the more critical to operation and, if you are using an MSRV-incompatible package, it likely is "latest" already. ### How should we test and review this PR? ### Additional information I was tempted to change colors to make "required rust version" stand out from "latest" but was unsure what direction to go, so I held off. Options included - red for "required rust version", yellow for "latest" - yellow for "required rust version", nothing for "latest" There is also more discussion on how to format "latest" at #13908.
2 parents beab81a + 428e173 commit ba8b394

File tree

2 files changed

+91
-88
lines changed

2 files changed

+91
-88
lines changed

src/cargo/ops/cargo_update.rs

+83-87
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::core::{PackageId, PackageIdSpec, PackageIdSpecQuery};
77
use crate::core::{Resolve, SourceId, Workspace};
88
use crate::ops;
99
use crate::sources::source::QueryKind;
10+
use crate::sources::IndexSummary;
1011
use crate::util::cache_lock::CacheLockMode;
1112
use crate::util::context::GlobalContext;
1213
use crate::util::toml_mut::dependency::{MaybeWorkspace, Source};
@@ -15,6 +16,7 @@ use crate::util::toml_mut::upgrade::upgrade_requirement;
1516
use crate::util::{style, OptVersionReq};
1617
use crate::util::{CargoResult, VersionExt};
1718
use anyhow::Context as _;
19+
use cargo_util_schemas::core::PartialVersion;
1820
use itertools::Itertools;
1921
use semver::{Op, Version, VersionReq};
2022
use std::cmp::Ordering;
@@ -498,10 +500,6 @@ fn print_lockfile_generation(
498500
status_locking(ws, num_pkgs)?;
499501

500502
for diff in diff {
501-
fn format_latest(version: semver::Version) -> String {
502-
let warn = style::WARN;
503-
format!(" {warn}(latest: v{version}){warn:#}")
504-
}
505503
let possibilities = if let Some(query) = diff.alternatives_query() {
506504
loop {
507505
match registry.query_vec(&query, QueryKind::Exact) {
@@ -516,22 +514,14 @@ fn print_lockfile_generation(
516514
};
517515

518516
for package in diff.added.iter() {
519-
let latest = if !possibilities.is_empty() {
520-
possibilities
521-
.iter()
522-
.map(|s| s.as_summary())
523-
.filter(|s| is_latest(s.version(), package.version()))
524-
.map(|s| s.version().clone())
525-
.max()
526-
.map(format_latest)
527-
} else {
528-
None
529-
};
517+
let required_rust_version = report_required_rust_version(ws, resolve, *package);
518+
let latest = report_latest(&possibilities, *package);
519+
let note = required_rust_version.or(latest);
530520

531-
if let Some(latest) = latest {
521+
if let Some(note) = note {
532522
ws.gctx().shell().status_with_color(
533523
"Adding",
534-
format!("{package}{latest}"),
524+
format!("{package}{note}"),
535525
&style::NOTE,
536526
)?;
537527
}
@@ -555,10 +545,6 @@ fn print_lockfile_sync(
555545
status_locking(ws, num_pkgs)?;
556546

557547
for diff in diff {
558-
fn format_latest(version: semver::Version) -> String {
559-
let warn = style::WARN;
560-
format!(" {warn}(latest: v{version}){warn:#}")
561-
}
562548
let possibilities = if let Some(query) = diff.alternatives_query() {
563549
loop {
564550
match registry.query_vec(&query, QueryKind::Exact) {
@@ -610,22 +596,13 @@ fn print_lockfile_sync(
610596
}
611597
} else {
612598
for package in diff.added.iter() {
613-
let latest = if !possibilities.is_empty() {
614-
possibilities
615-
.iter()
616-
.map(|s| s.as_summary())
617-
.filter(|s| is_latest(s.version(), package.version()))
618-
.map(|s| s.version().clone())
619-
.max()
620-
.map(format_latest)
621-
} else {
622-
None
623-
}
624-
.unwrap_or_default();
599+
let required_rust_version = report_required_rust_version(ws, resolve, *package);
600+
let latest = report_latest(&possibilities, *package);
601+
let note = required_rust_version.or(latest).unwrap_or_default();
625602

626603
ws.gctx().shell().status_with_color(
627604
"Adding",
628-
format!("{package}{latest}"),
605+
format!("{package}{note}"),
629606
&style::NOTE,
630607
)?;
631608
}
@@ -650,10 +627,6 @@ fn print_lockfile_updates(
650627

651628
let mut unchanged_behind = 0;
652629
for diff in diff {
653-
fn format_latest(version: semver::Version) -> String {
654-
let warn = style::WARN;
655-
format!(" {warn}(latest: v{version}){warn:#}")
656-
}
657630
let possibilities = if let Some(query) = diff.alternatives_query() {
658631
loop {
659632
match registry.query_vec(&query, QueryKind::Exact) {
@@ -668,26 +641,17 @@ fn print_lockfile_updates(
668641
};
669642

670643
if let Some((removed, added)) = diff.change() {
671-
let latest = if !possibilities.is_empty() {
672-
possibilities
673-
.iter()
674-
.map(|s| s.as_summary())
675-
.filter(|s| is_latest(s.version(), added.version()))
676-
.map(|s| s.version().clone())
677-
.max()
678-
.map(format_latest)
679-
} else {
680-
None
681-
}
682-
.unwrap_or_default();
644+
let required_rust_version = report_required_rust_version(ws, resolve, *added);
645+
let latest = report_latest(&possibilities, *added);
646+
let note = required_rust_version.or(latest).unwrap_or_default();
683647

684648
let msg = if removed.source_id().is_git() {
685649
format!(
686-
"{removed} -> #{}",
650+
"{removed} -> #{}{note}",
687651
&added.source_id().precise_git_fragment().unwrap()[..8],
688652
)
689653
} else {
690-
format!("{removed} -> v{}{latest}", added.version())
654+
format!("{removed} -> v{}{note}", added.version())
691655
};
692656

693657
// If versions differ only in build metadata, we call it an "update"
@@ -712,45 +676,30 @@ fn print_lockfile_updates(
712676
)?;
713677
}
714678
for package in diff.added.iter() {
715-
let latest = if !possibilities.is_empty() {
716-
possibilities
717-
.iter()
718-
.map(|s| s.as_summary())
719-
.filter(|s| is_latest(s.version(), package.version()))
720-
.map(|s| s.version().clone())
721-
.max()
722-
.map(format_latest)
723-
} else {
724-
None
725-
}
726-
.unwrap_or_default();
679+
let required_rust_version = report_required_rust_version(ws, resolve, *package);
680+
let latest = report_latest(&possibilities, *package);
681+
let note = required_rust_version.or(latest).unwrap_or_default();
727682

728683
ws.gctx().shell().status_with_color(
729684
"Adding",
730-
format!("{package}{latest}"),
685+
format!("{package}{note}"),
731686
&style::NOTE,
732687
)?;
733688
}
734689
}
735690
for package in &diff.unchanged {
736-
let latest = if !possibilities.is_empty() {
737-
possibilities
738-
.iter()
739-
.map(|s| s.as_summary())
740-
.filter(|s| is_latest(s.version(), package.version()))
741-
.map(|s| s.version().clone())
742-
.max()
743-
.map(format_latest)
744-
} else {
745-
None
746-
};
691+
let required_rust_version = report_required_rust_version(ws, resolve, *package);
692+
let latest = report_latest(&possibilities, *package);
693+
let note = required_rust_version.as_deref().or(latest.as_deref());
747694

748-
if let Some(latest) = latest {
749-
unchanged_behind += 1;
695+
if let Some(note) = note {
696+
if latest.is_some() {
697+
unchanged_behind += 1;
698+
}
750699
if ws.gctx().shell().verbosity() == Verbosity::Verbose {
751700
ws.gctx().shell().status_with_color(
752701
"Unchanged",
753-
format!("{package}{latest}"),
702+
format!("{package}{note}"),
754703
&anstyle::Style::new().bold(),
755704
)?;
756705
}
@@ -788,14 +737,7 @@ fn status_locking(ws: &Workspace<'_>, num_pkgs: usize) -> CargoResult<()> {
788737
write!(&mut cfg, " latest")?;
789738
}
790739

791-
if ws.resolve_honors_rust_version() {
792-
let rust_version = if let Some(ver) = ws.rust_version() {
793-
ver.clone().into_partial()
794-
} else {
795-
let rustc = ws.gctx().load_global_rustc(Some(ws))?;
796-
let rustc_version = rustc.version.clone().into();
797-
rustc_version
798-
};
740+
if let Some(rust_version) = required_rust_version(ws) {
799741
write!(&mut cfg, " Rust {rust_version}")?;
800742
}
801743
write!(&mut cfg, " compatible version{plural}")?;
@@ -807,6 +749,60 @@ fn status_locking(ws: &Workspace<'_>, num_pkgs: usize) -> CargoResult<()> {
807749
Ok(())
808750
}
809751

752+
fn required_rust_version(ws: &Workspace<'_>) -> Option<PartialVersion> {
753+
if !ws.resolve_honors_rust_version() {
754+
return None;
755+
}
756+
757+
if let Some(ver) = ws.rust_version() {
758+
Some(ver.clone().into_partial())
759+
} else {
760+
let rustc = ws.gctx().load_global_rustc(Some(ws)).ok()?;
761+
let rustc_version = rustc.version.clone().into();
762+
Some(rustc_version)
763+
}
764+
}
765+
766+
fn report_required_rust_version(
767+
ws: &Workspace<'_>,
768+
resolve: &Resolve,
769+
package: PackageId,
770+
) -> Option<String> {
771+
if package.source_id().is_path() {
772+
return None;
773+
}
774+
let summary = resolve.summary(package);
775+
let package_rust_version = summary.rust_version()?;
776+
let workspace_rust_version = required_rust_version(ws)?;
777+
if package_rust_version.is_compatible_with(&workspace_rust_version) {
778+
return None;
779+
}
780+
781+
let warn = style::WARN;
782+
Some(format!(
783+
" {warn}(requires Rust {package_rust_version}){warn:#}"
784+
))
785+
}
786+
787+
fn report_latest(possibilities: &[IndexSummary], package: PackageId) -> Option<String> {
788+
if !package.source_id().is_registry() {
789+
return None;
790+
}
791+
792+
possibilities
793+
.iter()
794+
.map(|s| s.as_summary())
795+
.filter(|s| is_latest(s.version(), package.version()))
796+
.map(|s| s.version().clone())
797+
.max()
798+
.map(format_latest)
799+
}
800+
801+
fn format_latest(version: semver::Version) -> String {
802+
let warn = style::WARN;
803+
format!(" {warn}(latest: v{version}){warn:#}")
804+
}
805+
810806
fn is_latest(candidate: &semver::Version, current: &semver::Version) -> bool {
811807
current < candidate
812808
// Only match pre-release if major.minor.patch are the same

tests/testsuite/rust_version.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ foo v0.0.1 ([ROOT]/foo)
241241
[UPDATING] `dummy-registry` index
242242
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
243243
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
244+
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
244245
245246
"#]])
246247
.run();
@@ -315,6 +316,7 @@ foo v0.0.1 ([ROOT]/foo)
315316
[UPDATING] `dummy-registry` index
316317
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
317318
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
319+
[ADDING] only-newer v1.6.0 (requires Rust 1.2345)
318320
319321
"#]])
320322
.run();
@@ -387,6 +389,7 @@ foo v0.0.1 ([ROOT]/foo)
387389
.with_stderr_data(str![[r#"
388390
[UPDATING] `dummy-registry` index
389391
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
392+
[ADDING] has-rust-version v1.6.0 (requires Rust 1.65.0)
390393
391394
"#]])
392395
.run();
@@ -484,6 +487,7 @@ higher v0.0.1 ([ROOT]/foo)
484487
[UPDATING] `dummy-registry` index
485488
[LOCKING] 4 packages to latest Rust 1.50.0 compatible versions
486489
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
490+
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
487491
488492
"#]])
489493
.run();
@@ -612,6 +616,7 @@ fn resolve_edition2024() {
612616
[UPDATING] `dummy-registry` index
613617
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
614618
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
619+
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
615620
616621
"#]])
617622
.run();
@@ -715,6 +720,7 @@ fn resolve_v3() {
715720
[UPDATING] `dummy-registry` index
716721
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
717722
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
723+
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
718724
719725
"#]])
720726
.run();
@@ -932,7 +938,7 @@ fn update_precise_overrides_msrv_resolver() {
932938
.masquerade_as_nightly_cargo(&["msrv-policy"])
933939
.with_stderr_data(str![[r#"
934940
[UPDATING] `dummy-registry` index
935-
[UPDATING] bar v1.5.0 -> v1.6.0
941+
[UPDATING] bar v1.5.0 -> v1.6.0 (requires Rust 1.65.0)
936942
937943
"#]])
938944
.run();
@@ -1010,6 +1016,7 @@ foo v0.0.1 ([ROOT]/foo)
10101016
[UPDATING] `dummy-registry` index
10111017
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
10121018
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
1019+
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
10131020
[DOWNLOADING] crates ...
10141021
[DOWNLOADED] newer-and-older v1.5.0 (registry `dummy-registry`)
10151022
[CHECKING] newer-and-older v1.5.0

0 commit comments

Comments
 (0)