mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Future-incompat report: Add suggestions of newer versions.
This commit is contained in:
parent
1f7141f892
commit
71cb59b6ef
@ -1,6 +1,6 @@
|
|||||||
use crate::command_prelude::*;
|
use crate::command_prelude::*;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use cargo::core::compiler::future_incompat::OnDiskReports;
|
use cargo::core::compiler::future_incompat::{OnDiskReports, REPORT_PREAMBLE};
|
||||||
use cargo::drop_println;
|
use cargo::drop_println;
|
||||||
|
|
||||||
pub fn cli() -> App {
|
pub fn cli() -> App {
|
||||||
@ -39,6 +39,7 @@ fn report_future_incompatibilies(config: &Config, args: &ArgMatches<'_>) -> CliR
|
|||||||
.value_of_u32("id")?
|
.value_of_u32("id")?
|
||||||
.unwrap_or_else(|| reports.last_id());
|
.unwrap_or_else(|| reports.last_id());
|
||||||
let report = reports.get_report(id, config)?;
|
let report = reports.get_report(id, config)?;
|
||||||
|
drop_println!(config, "{}", REPORT_PREAMBLE);
|
||||||
drop_println!(config, "{}", report);
|
drop_println!(config, "{}", report);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,26 @@
|
|||||||
//! Support for future-incompatible warning reporting.
|
//! Support for future-incompatible warning reporting.
|
||||||
|
|
||||||
use crate::core::{PackageId, Workspace};
|
use crate::core::{Dependency, PackageId, Workspace};
|
||||||
|
use crate::sources::SourceConfigMap;
|
||||||
use crate::util::{iter_join, CargoResult, Config};
|
use crate::util::{iter_join, CargoResult, Config};
|
||||||
use anyhow::{bail, format_err, Context};
|
use anyhow::{bail, format_err, Context};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
|
use std::fmt::Write as _;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
pub const REPORT_PREAMBLE: &str = "\
|
||||||
|
The following warnings were discovered during the build. These warnings are an
|
||||||
|
indication that the packages contain code that will become an error in a
|
||||||
|
future release of Rust. These warnings typically cover changes to close
|
||||||
|
soundness problems, unintended or undocumented behavior, or critical problems
|
||||||
|
that cannot be fixed in a backwards-compatible fashion, and are not expected
|
||||||
|
to be in wide use.
|
||||||
|
|
||||||
|
Each warning should contain a link for more information on what the warning
|
||||||
|
means and how to resolve it.
|
||||||
|
";
|
||||||
|
|
||||||
/// The future incompatibility report, emitted by the compiler as a JSON message.
|
/// The future incompatibility report, emitted by the compiler as a JSON message.
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct FutureIncompatReport {
|
pub struct FutureIncompatReport {
|
||||||
@ -90,7 +105,7 @@ impl OnDiskReports {
|
|||||||
};
|
};
|
||||||
let report = OnDiskReport {
|
let report = OnDiskReport {
|
||||||
id: current_reports.next_id,
|
id: current_reports.next_id,
|
||||||
report: render_report(per_package_reports),
|
report: render_report(ws, per_package_reports),
|
||||||
};
|
};
|
||||||
current_reports.next_id += 1;
|
current_reports.next_id += 1;
|
||||||
current_reports.reports.push(report);
|
current_reports.reports.push(report);
|
||||||
@ -178,11 +193,14 @@ impl OnDiskReports {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> String {
|
fn render_report(
|
||||||
|
ws: &Workspace<'_>,
|
||||||
|
per_package_reports: &[FutureIncompatReportPackage],
|
||||||
|
) -> String {
|
||||||
let mut per_package_reports: Vec<_> = per_package_reports.iter().collect();
|
let mut per_package_reports: Vec<_> = per_package_reports.iter().collect();
|
||||||
per_package_reports.sort_by_key(|r| r.package_id);
|
per_package_reports.sort_by_key(|r| r.package_id);
|
||||||
let mut rendered = String::new();
|
let mut rendered = String::new();
|
||||||
for per_package in per_package_reports {
|
for per_package in &per_package_reports {
|
||||||
rendered.push_str(&format!(
|
rendered.push_str(&format!(
|
||||||
"The package `{}` currently triggers the following future \
|
"The package `{}` currently triggers the following future \
|
||||||
incompatibility lints:\n",
|
incompatibility lints:\n",
|
||||||
@ -198,5 +216,75 @@ fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> String
|
|||||||
}
|
}
|
||||||
rendered.push('\n');
|
rendered.push('\n');
|
||||||
}
|
}
|
||||||
|
if let Some(s) = render_suggestions(ws, &per_package_reports) {
|
||||||
|
rendered.push_str(&s);
|
||||||
|
}
|
||||||
rendered
|
rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_suggestions(
|
||||||
|
ws: &Workspace<'_>,
|
||||||
|
per_package_reports: &[&FutureIncompatReportPackage],
|
||||||
|
) -> Option<String> {
|
||||||
|
// This in general ignores all errors since this is opportunistic.
|
||||||
|
let _lock = ws.config().acquire_package_cache_lock().ok()?;
|
||||||
|
// Create a set of updated registry sources.
|
||||||
|
let map = SourceConfigMap::new(ws.config()).ok()?;
|
||||||
|
let package_ids: BTreeSet<_> = per_package_reports
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.package_id)
|
||||||
|
.filter(|pkg_id| pkg_id.source_id().is_registry())
|
||||||
|
.collect();
|
||||||
|
let source_ids: HashSet<_> = package_ids
|
||||||
|
.iter()
|
||||||
|
.map(|pkg_id| pkg_id.source_id())
|
||||||
|
.collect();
|
||||||
|
let mut sources: HashMap<_, _> = source_ids
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|sid| {
|
||||||
|
let unlocked = sid.clone().with_precise(None);
|
||||||
|
let mut source = map.load(unlocked, &HashSet::new()).ok()?;
|
||||||
|
// Ignore errors updating.
|
||||||
|
if let Err(e) = source.update() {
|
||||||
|
log::debug!("failed to update source: {:?}", e);
|
||||||
|
}
|
||||||
|
Some((sid, source))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
// Query the sources for new versions.
|
||||||
|
let mut suggestions = String::new();
|
||||||
|
for pkg_id in package_ids {
|
||||||
|
let source = match sources.get_mut(&pkg_id.source_id()) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let dep = Dependency::parse(pkg_id.name(), None, pkg_id.source_id()).ok()?;
|
||||||
|
let summaries = source.query_vec(&dep).ok()?;
|
||||||
|
let versions = itertools::sorted(
|
||||||
|
summaries
|
||||||
|
.iter()
|
||||||
|
.map(|summary| summary.version())
|
||||||
|
.filter(|version| *version > pkg_id.version()),
|
||||||
|
);
|
||||||
|
let versions = versions.map(|version| version.to_string());
|
||||||
|
let versions = iter_join(versions, ", ");
|
||||||
|
if !versions.is_empty() {
|
||||||
|
writeln!(
|
||||||
|
suggestions,
|
||||||
|
"{} has the following newer versions available: {}",
|
||||||
|
pkg_id, versions
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if suggestions.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(format!(
|
||||||
|
"The following packages appear to have newer versions available.\n\
|
||||||
|
You may want to consider updating them to a newer version to see if the \
|
||||||
|
issue has been fixed.\n\n{}",
|
||||||
|
suggestions
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -195,7 +195,11 @@ fn test_multi_crate() {
|
|||||||
.exec_with_output()
|
.exec_with_output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let output = std::str::from_utf8(&output.stdout).unwrap();
|
let output = std::str::from_utf8(&output.stdout).unwrap();
|
||||||
let mut lines = output.lines();
|
assert!(output.starts_with("The following warnings were discovered"));
|
||||||
|
let mut lines = output
|
||||||
|
.lines()
|
||||||
|
// Skip the beginning of the per-package information.
|
||||||
|
.skip_while(|line| !line.starts_with("The package"));
|
||||||
for expected in &["first-dep v0.0.1", "second-dep v0.0.2"] {
|
for expected in &["first-dep v0.0.1", "second-dep v0.0.2"] {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&format!(
|
&format!(
|
||||||
@ -276,3 +280,67 @@ Available IDs are: 1
|
|||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn suggestions_for_updates() {
|
||||||
|
if !is_nightly() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Package::new("with_updates", "1.0.0")
|
||||||
|
.file("src/lib.rs", FUTURE_EXAMPLE)
|
||||||
|
.publish();
|
||||||
|
Package::new("big_update", "1.0.0")
|
||||||
|
.file("src/lib.rs", FUTURE_EXAMPLE)
|
||||||
|
.publish();
|
||||||
|
Package::new("without_updates", "1.0.0")
|
||||||
|
.file("src/lib.rs", FUTURE_EXAMPLE)
|
||||||
|
.publish();
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
with_updates = "1"
|
||||||
|
big_update = "1"
|
||||||
|
without_updates = "1"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("generate-lockfile").run();
|
||||||
|
|
||||||
|
Package::new("with_updates", "1.0.1")
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.publish();
|
||||||
|
Package::new("with_updates", "1.0.2")
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.publish();
|
||||||
|
Package::new("big_update", "2.0.0")
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.publish();
|
||||||
|
|
||||||
|
p.cargo("check -Zfuture-incompat-report")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stderr_contains("[..]cargo report future-incompatibilities --id 1[..]")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("report future-incompatibilities")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout_contains(
|
||||||
|
"\
|
||||||
|
The following packages appear to have newer versions available.
|
||||||
|
You may want to consider updating them to a newer version to see if the issue has been fixed.
|
||||||
|
|
||||||
|
big_update v1.0.0 has the following newer versions available: 2.0.0
|
||||||
|
with_updates v1.0.0 has the following newer versions available: 1.0.1, 1.0.2
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user