mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
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.
This commit is contained in:
commit
ba8b39413c
@ -7,6 +7,7 @@ use crate::core::{PackageId, PackageIdSpec, PackageIdSpecQuery};
|
|||||||
use crate::core::{Resolve, SourceId, Workspace};
|
use crate::core::{Resolve, SourceId, Workspace};
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::sources::source::QueryKind;
|
use crate::sources::source::QueryKind;
|
||||||
|
use crate::sources::IndexSummary;
|
||||||
use crate::util::cache_lock::CacheLockMode;
|
use crate::util::cache_lock::CacheLockMode;
|
||||||
use crate::util::context::GlobalContext;
|
use crate::util::context::GlobalContext;
|
||||||
use crate::util::toml_mut::dependency::{MaybeWorkspace, Source};
|
use crate::util::toml_mut::dependency::{MaybeWorkspace, Source};
|
||||||
@ -15,6 +16,7 @@ use crate::util::toml_mut::upgrade::upgrade_requirement;
|
|||||||
use crate::util::{style, OptVersionReq};
|
use crate::util::{style, OptVersionReq};
|
||||||
use crate::util::{CargoResult, VersionExt};
|
use crate::util::{CargoResult, VersionExt};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
|
use cargo_util_schemas::core::PartialVersion;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use semver::{Op, Version, VersionReq};
|
use semver::{Op, Version, VersionReq};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@ -498,10 +500,6 @@ fn print_lockfile_generation(
|
|||||||
status_locking(ws, num_pkgs)?;
|
status_locking(ws, num_pkgs)?;
|
||||||
|
|
||||||
for diff in diff {
|
for diff in diff {
|
||||||
fn format_latest(version: semver::Version) -> String {
|
|
||||||
let warn = style::WARN;
|
|
||||||
format!(" {warn}(latest: v{version}){warn:#}")
|
|
||||||
}
|
|
||||||
let possibilities = if let Some(query) = diff.alternatives_query() {
|
let possibilities = if let Some(query) = diff.alternatives_query() {
|
||||||
loop {
|
loop {
|
||||||
match registry.query_vec(&query, QueryKind::Exact) {
|
match registry.query_vec(&query, QueryKind::Exact) {
|
||||||
@ -516,22 +514,14 @@ fn print_lockfile_generation(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for package in diff.added.iter() {
|
for package in diff.added.iter() {
|
||||||
let latest = if !possibilities.is_empty() {
|
let required_rust_version = report_required_rust_version(ws, resolve, *package);
|
||||||
possibilities
|
let latest = report_latest(&possibilities, *package);
|
||||||
.iter()
|
let note = required_rust_version.or(latest);
|
||||||
.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 {
|
if let Some(note) = note {
|
||||||
ws.gctx().shell().status_with_color(
|
ws.gctx().shell().status_with_color(
|
||||||
"Adding",
|
"Adding",
|
||||||
format!("{package}{latest}"),
|
format!("{package}{note}"),
|
||||||
&style::NOTE,
|
&style::NOTE,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -555,10 +545,6 @@ fn print_lockfile_sync(
|
|||||||
status_locking(ws, num_pkgs)?;
|
status_locking(ws, num_pkgs)?;
|
||||||
|
|
||||||
for diff in diff {
|
for diff in diff {
|
||||||
fn format_latest(version: semver::Version) -> String {
|
|
||||||
let warn = style::WARN;
|
|
||||||
format!(" {warn}(latest: v{version}){warn:#}")
|
|
||||||
}
|
|
||||||
let possibilities = if let Some(query) = diff.alternatives_query() {
|
let possibilities = if let Some(query) = diff.alternatives_query() {
|
||||||
loop {
|
loop {
|
||||||
match registry.query_vec(&query, QueryKind::Exact) {
|
match registry.query_vec(&query, QueryKind::Exact) {
|
||||||
@ -610,22 +596,13 @@ fn print_lockfile_sync(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for package in diff.added.iter() {
|
for package in diff.added.iter() {
|
||||||
let latest = if !possibilities.is_empty() {
|
let required_rust_version = report_required_rust_version(ws, resolve, *package);
|
||||||
possibilities
|
let latest = report_latest(&possibilities, *package);
|
||||||
.iter()
|
let note = required_rust_version.or(latest).unwrap_or_default();
|
||||||
.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();
|
|
||||||
|
|
||||||
ws.gctx().shell().status_with_color(
|
ws.gctx().shell().status_with_color(
|
||||||
"Adding",
|
"Adding",
|
||||||
format!("{package}{latest}"),
|
format!("{package}{note}"),
|
||||||
&style::NOTE,
|
&style::NOTE,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -650,10 +627,6 @@ fn print_lockfile_updates(
|
|||||||
|
|
||||||
let mut unchanged_behind = 0;
|
let mut unchanged_behind = 0;
|
||||||
for diff in diff {
|
for diff in diff {
|
||||||
fn format_latest(version: semver::Version) -> String {
|
|
||||||
let warn = style::WARN;
|
|
||||||
format!(" {warn}(latest: v{version}){warn:#}")
|
|
||||||
}
|
|
||||||
let possibilities = if let Some(query) = diff.alternatives_query() {
|
let possibilities = if let Some(query) = diff.alternatives_query() {
|
||||||
loop {
|
loop {
|
||||||
match registry.query_vec(&query, QueryKind::Exact) {
|
match registry.query_vec(&query, QueryKind::Exact) {
|
||||||
@ -668,26 +641,17 @@ fn print_lockfile_updates(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some((removed, added)) = diff.change() {
|
if let Some((removed, added)) = diff.change() {
|
||||||
let latest = if !possibilities.is_empty() {
|
let required_rust_version = report_required_rust_version(ws, resolve, *added);
|
||||||
possibilities
|
let latest = report_latest(&possibilities, *added);
|
||||||
.iter()
|
let note = required_rust_version.or(latest).unwrap_or_default();
|
||||||
.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() {
|
let msg = if removed.source_id().is_git() {
|
||||||
format!(
|
format!(
|
||||||
"{removed} -> #{}",
|
"{removed} -> #{}{note}",
|
||||||
&added.source_id().precise_git_fragment().unwrap()[..8],
|
&added.source_id().precise_git_fragment().unwrap()[..8],
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{removed} -> v{}{latest}", added.version())
|
format!("{removed} -> v{}{note}", added.version())
|
||||||
};
|
};
|
||||||
|
|
||||||
// If versions differ only in build metadata, we call it an "update"
|
// If versions differ only in build metadata, we call it an "update"
|
||||||
@ -712,45 +676,30 @@ fn print_lockfile_updates(
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
for package in diff.added.iter() {
|
for package in diff.added.iter() {
|
||||||
let latest = if !possibilities.is_empty() {
|
let required_rust_version = report_required_rust_version(ws, resolve, *package);
|
||||||
possibilities
|
let latest = report_latest(&possibilities, *package);
|
||||||
.iter()
|
let note = required_rust_version.or(latest).unwrap_or_default();
|
||||||
.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();
|
|
||||||
|
|
||||||
ws.gctx().shell().status_with_color(
|
ws.gctx().shell().status_with_color(
|
||||||
"Adding",
|
"Adding",
|
||||||
format!("{package}{latest}"),
|
format!("{package}{note}"),
|
||||||
&style::NOTE,
|
&style::NOTE,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for package in &diff.unchanged {
|
for package in &diff.unchanged {
|
||||||
let latest = if !possibilities.is_empty() {
|
let required_rust_version = report_required_rust_version(ws, resolve, *package);
|
||||||
possibilities
|
let latest = report_latest(&possibilities, *package);
|
||||||
.iter()
|
let note = required_rust_version.as_deref().or(latest.as_deref());
|
||||||
.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 {
|
if let Some(note) = note {
|
||||||
unchanged_behind += 1;
|
if latest.is_some() {
|
||||||
|
unchanged_behind += 1;
|
||||||
|
}
|
||||||
if ws.gctx().shell().verbosity() == Verbosity::Verbose {
|
if ws.gctx().shell().verbosity() == Verbosity::Verbose {
|
||||||
ws.gctx().shell().status_with_color(
|
ws.gctx().shell().status_with_color(
|
||||||
"Unchanged",
|
"Unchanged",
|
||||||
format!("{package}{latest}"),
|
format!("{package}{note}"),
|
||||||
&anstyle::Style::new().bold(),
|
&anstyle::Style::new().bold(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -788,14 +737,7 @@ fn status_locking(ws: &Workspace<'_>, num_pkgs: usize) -> CargoResult<()> {
|
|||||||
write!(&mut cfg, " latest")?;
|
write!(&mut cfg, " latest")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ws.resolve_honors_rust_version() {
|
if let Some(rust_version) = required_rust_version(ws) {
|
||||||
let rust_version = if let Some(ver) = ws.rust_version() {
|
|
||||||
ver.clone().into_partial()
|
|
||||||
} else {
|
|
||||||
let rustc = ws.gctx().load_global_rustc(Some(ws))?;
|
|
||||||
let rustc_version = rustc.version.clone().into();
|
|
||||||
rustc_version
|
|
||||||
};
|
|
||||||
write!(&mut cfg, " Rust {rust_version}")?;
|
write!(&mut cfg, " Rust {rust_version}")?;
|
||||||
}
|
}
|
||||||
write!(&mut cfg, " compatible version{plural}")?;
|
write!(&mut cfg, " compatible version{plural}")?;
|
||||||
@ -807,6 +749,60 @@ fn status_locking(ws: &Workspace<'_>, num_pkgs: usize) -> CargoResult<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn required_rust_version(ws: &Workspace<'_>) -> Option<PartialVersion> {
|
||||||
|
if !ws.resolve_honors_rust_version() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ver) = ws.rust_version() {
|
||||||
|
Some(ver.clone().into_partial())
|
||||||
|
} else {
|
||||||
|
let rustc = ws.gctx().load_global_rustc(Some(ws)).ok()?;
|
||||||
|
let rustc_version = rustc.version.clone().into();
|
||||||
|
Some(rustc_version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_required_rust_version(
|
||||||
|
ws: &Workspace<'_>,
|
||||||
|
resolve: &Resolve,
|
||||||
|
package: PackageId,
|
||||||
|
) -> Option<String> {
|
||||||
|
if package.source_id().is_path() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let summary = resolve.summary(package);
|
||||||
|
let package_rust_version = summary.rust_version()?;
|
||||||
|
let workspace_rust_version = required_rust_version(ws)?;
|
||||||
|
if package_rust_version.is_compatible_with(&workspace_rust_version) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let warn = style::WARN;
|
||||||
|
Some(format!(
|
||||||
|
" {warn}(requires Rust {package_rust_version}){warn:#}"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_latest(possibilities: &[IndexSummary], package: PackageId) -> Option<String> {
|
||||||
|
if !package.source_id().is_registry() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
possibilities
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.as_summary())
|
||||||
|
.filter(|s| is_latest(s.version(), package.version()))
|
||||||
|
.map(|s| s.version().clone())
|
||||||
|
.max()
|
||||||
|
.map(format_latest)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_latest(version: semver::Version) -> String {
|
||||||
|
let warn = style::WARN;
|
||||||
|
format!(" {warn}(latest: v{version}){warn:#}")
|
||||||
|
}
|
||||||
|
|
||||||
fn is_latest(candidate: &semver::Version, current: &semver::Version) -> bool {
|
fn is_latest(candidate: &semver::Version, current: &semver::Version) -> bool {
|
||||||
current < candidate
|
current < candidate
|
||||||
// Only match pre-release if major.minor.patch are the same
|
// Only match pre-release if major.minor.patch are the same
|
||||||
|
@ -241,6 +241,7 @@ foo v0.0.1 ([ROOT]/foo)
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -315,6 +316,7 @@ foo v0.0.1 ([ROOT]/foo)
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.2345)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -387,6 +389,7 @@ foo v0.0.1 ([ROOT]/foo)
|
|||||||
.with_stderr_data(str![[r#"
|
.with_stderr_data(str![[r#"
|
||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
|
[ADDING] has-rust-version v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -484,6 +487,7 @@ higher v0.0.1 ([ROOT]/foo)
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 4 packages to latest Rust 1.50.0 compatible versions
|
[LOCKING] 4 packages to latest Rust 1.50.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -612,6 +616,7 @@ fn resolve_edition2024() {
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -715,6 +720,7 @@ fn resolve_v3() {
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -932,7 +938,7 @@ fn update_precise_overrides_msrv_resolver() {
|
|||||||
.masquerade_as_nightly_cargo(&["msrv-policy"])
|
.masquerade_as_nightly_cargo(&["msrv-policy"])
|
||||||
.with_stderr_data(str![[r#"
|
.with_stderr_data(str![[r#"
|
||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[UPDATING] bar v1.5.0 -> v1.6.0
|
[UPDATING] bar v1.5.0 -> v1.6.0 (requires Rust 1.65.0)
|
||||||
|
|
||||||
"#]])
|
"#]])
|
||||||
.run();
|
.run();
|
||||||
@ -1010,6 +1016,7 @@ foo v0.0.1 ([ROOT]/foo)
|
|||||||
[UPDATING] `dummy-registry` index
|
[UPDATING] `dummy-registry` index
|
||||||
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
[ADDING] only-newer v1.6.0 (requires Rust 1.65.0)
|
||||||
[DOWNLOADING] crates ...
|
[DOWNLOADING] crates ...
|
||||||
[DOWNLOADED] newer-and-older v1.5.0 (registry `dummy-registry`)
|
[DOWNLOADED] newer-and-older v1.5.0 (registry `dummy-registry`)
|
||||||
[CHECKING] newer-and-older v1.5.0
|
[CHECKING] newer-and-older v1.5.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user