mirror of
https://github.com/rust-lang/cargo
synced 2024-07-17 11:08:08 +00:00
Updates to future-incompatible reporting.
This commit is contained in:
parent
f2c22a3690
commit
c2b02b3926
|
@ -73,7 +73,6 @@ itertools = "0.10.0"
|
|||
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
|
||||
# for more information.
|
||||
rustc-workspace-hack = "1.0.0"
|
||||
rand = "0.8.3"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
fwdansi = "1.1.0"
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use crate::command_prelude::*;
|
||||
use anyhow::{anyhow, Context as _};
|
||||
use cargo::core::compiler::future_incompat::{OnDiskReport, FUTURE_INCOMPAT_FILE};
|
||||
use cargo::drop_eprint;
|
||||
use std::io::Read;
|
||||
use anyhow::anyhow;
|
||||
use cargo::core::compiler::future_incompat::OnDiskReports;
|
||||
use cargo::drop_println;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("report")
|
||||
|
@ -17,8 +16,7 @@ pub fn cli() -> App {
|
|||
"id",
|
||||
"identifier of the report generated by a Cargo command invocation",
|
||||
)
|
||||
.value_name("id")
|
||||
.required(true),
|
||||
.value_name("id"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -35,31 +33,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
|||
|
||||
fn report_future_incompatibilies(config: &Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
let report_file = ws.target_dir().open_ro(
|
||||
FUTURE_INCOMPAT_FILE,
|
||||
ws.config(),
|
||||
"Future incompatible report",
|
||||
)?;
|
||||
|
||||
let mut file_contents = String::new();
|
||||
report_file
|
||||
.file()
|
||||
.read_to_string(&mut file_contents)
|
||||
.with_context(|| "failed to read report")?;
|
||||
let on_disk_report: OnDiskReport =
|
||||
serde_json::from_str(&file_contents).with_context(|| "failed to load report")?;
|
||||
|
||||
let id = args.value_of("id").unwrap();
|
||||
if id != on_disk_report.id {
|
||||
return Err(anyhow!(
|
||||
"Expected an id of `{}`, but `{}` was provided on the command line. \
|
||||
Your report may have been overwritten by a different one.",
|
||||
on_disk_report.id,
|
||||
id
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
drop_eprint!(config, "{}", on_disk_report.report);
|
||||
let reports = OnDiskReports::load(&ws)?;
|
||||
let id = args
|
||||
.value_of_u32("id")?
|
||||
.unwrap_or_else(|| reports.last_id());
|
||||
let report = reports.get_report(id, config)?;
|
||||
drop_println!(config, "{}", report);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
//! Support for future-incompatible warning reporting.
|
||||
|
||||
use crate::core::{PackageId, Workspace};
|
||||
use crate::util::{iter_join, CargoResult, Config};
|
||||
use anyhow::{bail, format_err, Context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// The future incompatibility report, emitted by the compiler as a JSON message.
|
||||
#[derive(serde::Deserialize)]
|
||||
|
@ -6,6 +12,13 @@ pub struct FutureIncompatReport {
|
|||
pub future_incompat_report: Vec<FutureBreakageItem>,
|
||||
}
|
||||
|
||||
/// Structure used for collecting reports in-memory.
|
||||
pub struct FutureIncompatReportPackage {
|
||||
pub package_id: PackageId,
|
||||
pub items: Vec<FutureBreakageItem>,
|
||||
}
|
||||
|
||||
/// A single future-incompatible warning emitted by rustc.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FutureBreakageItem {
|
||||
/// The date at which this lint will become an error.
|
||||
|
@ -24,13 +37,166 @@ pub struct Diagnostic {
|
|||
|
||||
/// The filename in the top-level `target` directory where we store
|
||||
/// the report
|
||||
pub const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json";
|
||||
const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json";
|
||||
/// Max number of reports to save on disk.
|
||||
const MAX_REPORTS: usize = 5;
|
||||
|
||||
/// The structure saved to disk containing the reports.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct OnDiskReport {
|
||||
// A Cargo-generated id used to detect when a report has been overwritten
|
||||
pub id: String,
|
||||
// Cannot be a &str, since Serde needs
|
||||
// to be able to un-escape the JSON
|
||||
pub report: String,
|
||||
pub struct OnDiskReports {
|
||||
/// A schema version number, to handle older cargo's from trying to read
|
||||
/// something that they don't understand.
|
||||
version: u32,
|
||||
/// The report ID to use for the next report to save.
|
||||
next_id: u32,
|
||||
/// Available reports.
|
||||
reports: Vec<OnDiskReport>,
|
||||
}
|
||||
|
||||
/// A single report for a given compilation session.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OnDiskReport {
|
||||
/// Unique reference to the report for the `--id` CLI flag.
|
||||
id: u32,
|
||||
/// Report, suitable for printing to the console.
|
||||
report: String,
|
||||
}
|
||||
|
||||
impl Default for OnDiskReports {
|
||||
fn default() -> OnDiskReports {
|
||||
OnDiskReports {
|
||||
version: 0,
|
||||
next_id: 1,
|
||||
reports: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OnDiskReports {
|
||||
/// Saves a new report.
|
||||
pub fn save_report(
|
||||
ws: &Workspace<'_>,
|
||||
per_package_reports: &[FutureIncompatReportPackage],
|
||||
) -> OnDiskReports {
|
||||
let mut current_reports = match Self::load(ws) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::debug!(
|
||||
"saving future-incompatible reports failed to load current reports: {:?}",
|
||||
e
|
||||
);
|
||||
OnDiskReports::default()
|
||||
}
|
||||
};
|
||||
let report = OnDiskReport {
|
||||
id: current_reports.next_id,
|
||||
report: render_report(per_package_reports),
|
||||
};
|
||||
current_reports.next_id += 1;
|
||||
current_reports.reports.push(report);
|
||||
if current_reports.reports.len() > MAX_REPORTS {
|
||||
current_reports.reports.remove(0);
|
||||
}
|
||||
let on_disk = serde_json::to_vec(¤t_reports).unwrap();
|
||||
if let Err(e) = ws
|
||||
.target_dir()
|
||||
.open_rw(
|
||||
FUTURE_INCOMPAT_FILE,
|
||||
ws.config(),
|
||||
"Future incompatibility report",
|
||||
)
|
||||
.and_then(|file| {
|
||||
let mut file = file.file();
|
||||
file.set_len(0)?;
|
||||
file.write_all(&on_disk)?;
|
||||
Ok(())
|
||||
})
|
||||
{
|
||||
crate::display_warning_with_error(
|
||||
"failed to write on-disk future incompatible report",
|
||||
&e,
|
||||
&mut ws.config().shell(),
|
||||
);
|
||||
}
|
||||
current_reports
|
||||
}
|
||||
|
||||
/// Loads the on-disk reports.
|
||||
pub fn load(ws: &Workspace<'_>) -> CargoResult<OnDiskReports> {
|
||||
let report_file = match ws.target_dir().open_ro(
|
||||
FUTURE_INCOMPAT_FILE,
|
||||
ws.config(),
|
||||
"Future incompatible report",
|
||||
) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
|
||||
if io_err.kind() == std::io::ErrorKind::NotFound {
|
||||
bail!("no reports are currently available");
|
||||
}
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
let mut file_contents = String::new();
|
||||
report_file
|
||||
.file()
|
||||
.read_to_string(&mut file_contents)
|
||||
.with_context(|| "failed to read report")?;
|
||||
let on_disk_reports: OnDiskReports =
|
||||
serde_json::from_str(&file_contents).with_context(|| "failed to load report")?;
|
||||
if on_disk_reports.version != 0 {
|
||||
bail!("unable to read reports; reports were saved from a future version of Cargo");
|
||||
}
|
||||
Ok(on_disk_reports)
|
||||
}
|
||||
|
||||
/// Returns the most recent report ID.
|
||||
pub fn last_id(&self) -> u32 {
|
||||
self.reports.last().map(|r| r.id).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_report(&self, id: u32, config: &Config) -> CargoResult<String> {
|
||||
let report = self.reports.iter().find(|r| r.id == id).ok_or_else(|| {
|
||||
let available = iter_join(self.reports.iter().map(|r| r.id.to_string()), ", ");
|
||||
format_err!(
|
||||
"could not find report with ID {}\n\
|
||||
Available IDs are: {}",
|
||||
id,
|
||||
available
|
||||
)
|
||||
})?;
|
||||
let report = if config.shell().err_supports_color() {
|
||||
report.report.clone()
|
||||
} else {
|
||||
strip_ansi_escapes::strip(&report.report)
|
||||
.map(|v| String::from_utf8(v).expect("utf8"))
|
||||
.expect("strip should never fail")
|
||||
};
|
||||
Ok(report)
|
||||
}
|
||||
}
|
||||
|
||||
fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> String {
|
||||
let mut per_package_reports: Vec<_> = per_package_reports.iter().collect();
|
||||
per_package_reports.sort_by_key(|r| r.package_id);
|
||||
let mut rendered = String::new();
|
||||
for per_package in per_package_reports {
|
||||
rendered.push_str(&format!(
|
||||
"The package `{}` currently triggers the following future \
|
||||
incompatibility lints:\n",
|
||||
per_package.package_id
|
||||
));
|
||||
for item in &per_package.items {
|
||||
rendered.extend(
|
||||
item.diagnostic
|
||||
.rendered
|
||||
.lines()
|
||||
.map(|l| format!("> {}\n", l)),
|
||||
);
|
||||
}
|
||||
rendered.push('\n');
|
||||
}
|
||||
rendered
|
||||
}
|
||||
|
|
|
@ -50,8 +50,7 @@
|
|||
//! improved.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::io;
|
||||
use std::marker;
|
||||
use std::sync::Arc;
|
||||
|
@ -62,8 +61,6 @@ use cargo_util::ProcessBuilder;
|
|||
use crossbeam_utils::thread::Scope;
|
||||
use jobserver::{Acquired, Client, HelperThread};
|
||||
use log::{debug, info, trace};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use super::context::OutputFile;
|
||||
use super::job::{
|
||||
|
@ -73,7 +70,7 @@ use super::job::{
|
|||
use super::timings::Timings;
|
||||
use super::{BuildContext, BuildPlan, CompileMode, Context, Unit};
|
||||
use crate::core::compiler::future_incompat::{
|
||||
FutureBreakageItem, OnDiskReport, FUTURE_INCOMPAT_FILE,
|
||||
FutureBreakageItem, FutureIncompatReportPackage, OnDiskReports,
|
||||
};
|
||||
use crate::core::resolver::ResolveBehavior;
|
||||
use crate::core::{FeatureValue, PackageId, Shell, TargetKind};
|
||||
|
@ -161,7 +158,7 @@ struct DrainState<'cfg> {
|
|||
|
||||
/// How many jobs we've finished
|
||||
finished: usize,
|
||||
per_crate_future_incompat_reports: Vec<FutureIncompatReportCrate>,
|
||||
per_package_future_incompat_reports: Vec<FutureIncompatReportPackage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
|
@ -173,11 +170,6 @@ impl std::fmt::Display for JobId {
|
|||
}
|
||||
}
|
||||
|
||||
struct FutureIncompatReportCrate {
|
||||
package_id: PackageId,
|
||||
report: Vec<FutureBreakageItem>,
|
||||
}
|
||||
|
||||
/// A `JobState` is constructed by `JobQueue::run` and passed to `Job::run`. It includes everything
|
||||
/// necessary to communicate between the main thread and the execution of the job.
|
||||
///
|
||||
|
@ -432,7 +424,7 @@ impl<'cfg> JobQueue<'cfg> {
|
|||
pending_queue: Vec::new(),
|
||||
print: DiagnosticPrinter::new(cx.bcx.config),
|
||||
finished: 0,
|
||||
per_crate_future_incompat_reports: Vec::new(),
|
||||
per_package_future_incompat_reports: Vec::new(),
|
||||
};
|
||||
|
||||
// Create a helper thread for acquiring jobserver tokens
|
||||
|
@ -615,10 +607,10 @@ impl<'cfg> DrainState<'cfg> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::FutureIncompatReport(id, report) => {
|
||||
Message::FutureIncompatReport(id, items) => {
|
||||
let package_id = self.active[&id].pkg.package_id();
|
||||
self.per_crate_future_incompat_reports
|
||||
.push(FutureIncompatReportCrate { package_id, report });
|
||||
self.per_package_future_incompat_reports
|
||||
.push(FutureIncompatReportPackage { package_id, items });
|
||||
}
|
||||
Message::Token(acquired_token) => {
|
||||
let token = acquired_token.with_context(|| "failed to acquire jobserver token")?;
|
||||
|
@ -801,7 +793,7 @@ impl<'cfg> DrainState<'cfg> {
|
|||
if !cx.bcx.build_config.build_plan {
|
||||
// It doesn't really matter if this fails.
|
||||
drop(cx.bcx.config.shell().status("Finished", message));
|
||||
self.emit_future_incompat(cx);
|
||||
self.emit_future_incompat(cx.bcx);
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -811,93 +803,57 @@ impl<'cfg> DrainState<'cfg> {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_future_incompat(&mut self, cx: &mut Context<'_, '_>) {
|
||||
if cx.bcx.config.cli_unstable().future_incompat_report {
|
||||
if self.per_crate_future_incompat_reports.is_empty() {
|
||||
fn emit_future_incompat(&mut self, bcx: &BuildContext<'_, '_>) {
|
||||
if !bcx.config.cli_unstable().future_incompat_report {
|
||||
return;
|
||||
}
|
||||
if self.per_package_future_incompat_reports.is_empty() {
|
||||
if bcx.build_config.future_incompat_report {
|
||||
drop(
|
||||
cx.bcx
|
||||
.config
|
||||
bcx.config
|
||||
.shell()
|
||||
.note("0 dependencies had future-incompat warnings"),
|
||||
.note("0 dependencies had future-incompatible warnings"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.per_crate_future_incompat_reports
|
||||
.sort_by_key(|r| r.package_id);
|
||||
return;
|
||||
}
|
||||
|
||||
let crates_and_versions = self
|
||||
.per_crate_future_incompat_reports
|
||||
.iter()
|
||||
.map(|r| r.package_id.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
// Get a list of unique and sorted package name/versions.
|
||||
let package_vers: BTreeSet<_> = self
|
||||
.per_package_future_incompat_reports
|
||||
.iter()
|
||||
.map(|r| r.package_id)
|
||||
.collect();
|
||||
let package_vers: Vec<_> = package_vers
|
||||
.into_iter()
|
||||
.map(|pid| pid.to_string())
|
||||
.collect();
|
||||
|
||||
drop(cx.bcx.config.shell().warn(&format!(
|
||||
"the following crates contain code that will be rejected by a future version of Rust: {}",
|
||||
crates_and_versions
|
||||
drop(bcx.config.shell().warn(&format!(
|
||||
"the following packages contain code that will be rejected by a future \
|
||||
version of Rust: {}",
|
||||
package_vers.join(", ")
|
||||
)));
|
||||
|
||||
let on_disk_reports =
|
||||
OnDiskReports::save_report(bcx.ws, &self.per_package_future_incompat_reports);
|
||||
let report_id = on_disk_reports.last_id();
|
||||
|
||||
if bcx.build_config.future_incompat_report {
|
||||
let rendered = on_disk_reports.get_report(report_id, bcx.config).unwrap();
|
||||
drop_eprint!(bcx.config, "{}", rendered);
|
||||
drop(bcx.config.shell().note(&format!(
|
||||
"this report can be shown with `cargo report \
|
||||
future-incompatibilities -Z future-incompat-report --id {}`",
|
||||
report_id
|
||||
)));
|
||||
} else {
|
||||
drop(bcx.config.shell().note(&format!(
|
||||
"to see what the problems were, use the option \
|
||||
`--future-incompat-report`, or run `cargo report \
|
||||
future-incompatibilities --id {}`",
|
||||
report_id
|
||||
)));
|
||||
|
||||
let mut full_report = String::new();
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// Generate a short ID to allow detecting if a report gets overwritten
|
||||
let id: String = std::iter::repeat(())
|
||||
.map(|()| char::from(rng.sample(Alphanumeric)))
|
||||
.take(4)
|
||||
.collect();
|
||||
|
||||
for report in std::mem::take(&mut self.per_crate_future_incompat_reports) {
|
||||
full_report.push_str(&format!(
|
||||
"The crate `{}` currently triggers the following future incompatibility lints:\n",
|
||||
report.package_id
|
||||
));
|
||||
for item in report.report {
|
||||
let rendered = if cx.bcx.config.shell().err_supports_color() {
|
||||
item.diagnostic.rendered
|
||||
} else {
|
||||
strip_ansi_escapes::strip(&item.diagnostic.rendered)
|
||||
.map(|v| String::from_utf8(v).expect("utf8"))
|
||||
.expect("strip should never fail")
|
||||
};
|
||||
|
||||
for line in rendered.lines() {
|
||||
full_report.push_str(&format!("> {}\n", line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let report_file = cx.bcx.ws.target_dir().open_rw(
|
||||
FUTURE_INCOMPAT_FILE,
|
||||
cx.bcx.config,
|
||||
"Future incompatibility report",
|
||||
);
|
||||
let err = report_file
|
||||
.and_then(|report_file| {
|
||||
let on_disk_report = OnDiskReport {
|
||||
id: id.clone(),
|
||||
report: full_report.clone(),
|
||||
};
|
||||
serde_json::to_writer(report_file, &on_disk_report).map_err(|e| e.into())
|
||||
})
|
||||
.err();
|
||||
if let Some(e) = err {
|
||||
crate::display_warning_with_error(
|
||||
"failed to write on-disk future incompat report",
|
||||
&e,
|
||||
&mut cx.bcx.config.shell(),
|
||||
);
|
||||
}
|
||||
|
||||
if cx.bcx.build_config.future_incompat_report {
|
||||
drop_eprint!(cx.bcx.config, "{}", full_report);
|
||||
drop(cx.bcx.config.shell().note(
|
||||
&format!("this report can be shown with `cargo report future-incompatibilities -Z future-incompat-report --id {}`", id)
|
||||
));
|
||||
} else {
|
||||
drop(cx.bcx.config.shell().note(
|
||||
&format!("to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id {}`", id)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
//! Tests for future-incompat-report messages
|
||||
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::{basic_manifest, is_nightly, project};
|
||||
use cargo_test_support::{basic_manifest, is_nightly, project, Project};
|
||||
|
||||
// An arbitrary lint (array_into_iter) that triggers a report.
|
||||
const FUTURE_EXAMPLE: &'static str = "fn main() { [true].into_iter(); }";
|
||||
// Some text that will be displayed when the lint fires.
|
||||
const FUTURE_OUTPUT: &'static str = "[..]array_into_iter[..]";
|
||||
|
||||
fn simple_project() -> Project {
|
||||
project()
|
||||
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
|
||||
.file("src/main.rs", FUTURE_EXAMPLE)
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn no_output_on_stable() {
|
||||
let p = project()
|
||||
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
|
||||
.file("src/main.rs", "fn main() { [true].into_iter(); }")
|
||||
.build();
|
||||
let p = simple_project();
|
||||
|
||||
p.cargo("build")
|
||||
.with_stderr_contains(" = note: `#[warn(array_into_iter)]` on by default")
|
||||
.with_stderr_does_not_contain("[..]crates[..]")
|
||||
.with_stderr_contains(FUTURE_OUTPUT)
|
||||
.with_stderr_does_not_contain("[..]cargo report[..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gate_future_incompat_report() {
|
||||
let p = project()
|
||||
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
|
||||
.file("src/main.rs", "fn main() { [true].into_iter(); }")
|
||||
.build();
|
||||
let p = simple_project();
|
||||
|
||||
p.cargo("build --future-incompat-report")
|
||||
.with_stderr_contains("error: the `--future-incompat-report` flag is unstable[..]")
|
||||
|
@ -60,9 +66,25 @@ fn test_zero_future_incompat() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
// No note if --future-incompat-report is not specified.
|
||||
p.cargo("build -Z future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.0.0 [..]
|
||||
[FINISHED] [..]
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
p.cargo("build --future-incompat-report -Z unstable-options -Z future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("note: 0 dependencies had future-incompat warnings")
|
||||
.with_stderr(
|
||||
"\
|
||||
[FINISHED] [..]
|
||||
note: 0 dependencies had future-incompatible warnings
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
@ -72,24 +94,21 @@ fn test_single_crate() {
|
|||
return;
|
||||
}
|
||||
|
||||
let p = project()
|
||||
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
|
||||
.file("src/main.rs", "fn main() { [true].into_iter(); }")
|
||||
.build();
|
||||
let p = simple_project();
|
||||
|
||||
for command in &["build", "check", "rustc", "test"] {
|
||||
p.cargo(command).arg("-Zfuture-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains(" = note: `#[warn(array_into_iter)]` on by default")
|
||||
.with_stderr_contains("warning: the following crates contain code that will be rejected by a future version of Rust: foo v0.0.0 [..]")
|
||||
.with_stderr_contains(FUTURE_OUTPUT)
|
||||
.with_stderr_contains("warning: the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 [..]")
|
||||
.with_stderr_does_not_contain("[..]incompatibility[..]")
|
||||
.run();
|
||||
|
||||
p.cargo(command).arg("-Zfuture-incompat-report").arg("-Zunstable-options").arg("--future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains(" = note: `#[warn(array_into_iter)]` on by default")
|
||||
.with_stderr_contains("warning: the following crates contain code that will be rejected by a future version of Rust: foo v0.0.0 [..]")
|
||||
.with_stderr_contains("The crate `foo v0.0.0 ([..])` currently triggers the following future incompatibility lints:")
|
||||
.with_stderr_contains(FUTURE_OUTPUT)
|
||||
.with_stderr_contains("warning: the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 [..]")
|
||||
.with_stderr_contains("The package `foo v0.0.0 ([..])` currently triggers the following future incompatibility lints:")
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
@ -101,10 +120,10 @@ fn test_multi_crate() {
|
|||
}
|
||||
|
||||
Package::new("first-dep", "0.0.1")
|
||||
.file("src/lib.rs", "fn foo() { [25].into_iter(); }")
|
||||
.file("src/lib.rs", FUTURE_EXAMPLE)
|
||||
.publish();
|
||||
Package::new("second-dep", "0.0.2")
|
||||
.file("src/lib.rs", "fn foo() { ['a'].into_iter(); }")
|
||||
.file("src/lib.rs", FUTURE_EXAMPLE)
|
||||
.publish();
|
||||
|
||||
let p = project()
|
||||
|
@ -126,24 +145,17 @@ fn test_multi_crate() {
|
|||
for command in &["build", "check", "rustc", "test"] {
|
||||
p.cargo(command).arg("-Zfuture-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_does_not_contain("[..]array_into_iter[..]")
|
||||
.with_stderr_contains("warning: the following crates contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2")
|
||||
.with_stderr_does_not_contain(FUTURE_OUTPUT)
|
||||
.with_stderr_contains("warning: the following packages contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2")
|
||||
// Check that we don't have the 'triggers' message shown at the bottom of this loop
|
||||
.with_stderr_does_not_contain("[..]triggers[..]")
|
||||
.run();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report --id bad-id")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("error: Expected an id of [..]")
|
||||
.with_stderr_does_not_contain("[..]triggers[..]")
|
||||
.with_status(101)
|
||||
.run();
|
||||
|
||||
p.cargo(command).arg("-Zunstable-options").arg("-Zfuture-incompat-report").arg("--future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("warning: the following crates contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2")
|
||||
.with_stderr_contains("The crate `first-dep v0.0.1` currently triggers the following future incompatibility lints:")
|
||||
.with_stderr_contains("The crate `second-dep v0.0.2` currently triggers the following future incompatibility lints:")
|
||||
.with_stderr_contains("warning: the following packages contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2")
|
||||
.with_stderr_contains("The package `first-dep v0.0.1` currently triggers the following future incompatibility lints:")
|
||||
.with_stderr_contains("The package `second-dep v0.0.2` currently triggers the following future incompatibility lints:")
|
||||
.run();
|
||||
}
|
||||
|
||||
|
@ -172,7 +184,95 @@ fn test_multi_crate() {
|
|||
|
||||
p.cargo(&format!("report future-incompatibilities -Z future-incompat-report --id {}", id))
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("The crate `first-dep v0.0.1` currently triggers the following future incompatibility lints:")
|
||||
.with_stderr_contains("The crate `second-dep v0.0.2` currently triggers the following future incompatibility lints:")
|
||||
.with_stdout_contains("The package `first-dep v0.0.1` currently triggers the following future incompatibility lints:")
|
||||
.with_stdout_contains("The package `second-dep v0.0.2` currently triggers the following future incompatibility lints:")
|
||||
.run();
|
||||
|
||||
// Test without --id, and also the full output of the report.
|
||||
let output = p
|
||||
.cargo("report future-incompatibilities -Z future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.exec_with_output()
|
||||
.unwrap();
|
||||
let output = std::str::from_utf8(&output.stdout).unwrap();
|
||||
let mut lines = output.lines();
|
||||
for expected in &["first-dep v0.0.1", "second-dep v0.0.2"] {
|
||||
assert_eq!(
|
||||
&format!(
|
||||
"The package `{}` currently triggers the following future incompatibility lints:",
|
||||
expected
|
||||
),
|
||||
lines.next().unwrap()
|
||||
);
|
||||
let mut count = 0;
|
||||
while let Some(line) = lines.next() {
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
assert!(count > 0);
|
||||
}
|
||||
assert_eq!(lines.next(), Some(""));
|
||||
assert_eq!(lines.next(), None);
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn color() {
|
||||
if !is_nightly() {
|
||||
return;
|
||||
}
|
||||
|
||||
let p = simple_project();
|
||||
|
||||
p.cargo("check -Zfuture-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.run();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_does_not_contain("[..]\x1b[[..]")
|
||||
.run();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.env("CARGO_TERM_COLOR", "always")
|
||||
.with_stdout_contains("[..]\x1b[[..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn bad_ids() {
|
||||
if !is_nightly() {
|
||||
return;
|
||||
}
|
||||
|
||||
let p = simple_project();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report --id 1")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr("error: no reports are currently available")
|
||||
.run();
|
||||
|
||||
p.cargo("check -Zfuture-incompat-report")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.run();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report --id foo")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(1)
|
||||
.with_stderr("error: Invalid value: could not parse `foo` as a number")
|
||||
.run();
|
||||
|
||||
p.cargo("report future-incompatibilities -Z future-incompat-report --id 7")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
error: could not find report with ID 7
|
||||
Available IDs are: 1
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue