make cargo-miri show_error a bit nicer to use

This commit is contained in:
Ralf Jung 2022-08-08 11:32:49 -04:00
parent 12e3f75fd4
commit 1164815750
4 changed files with 35 additions and 34 deletions

View File

@ -1,10 +1,12 @@
#![feature(let_else)]
#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)]
#[macro_use]
mod util;
mod arg;
mod phases;
mod setup;
mod util;
mod version;
use std::{env, iter};
@ -73,9 +75,9 @@ fn main() {
}
let Some(first) = args.next() else {
show_error(format!(
show_error!(
"`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`"
))
)
};
match first.as_str() {
"miri" => phase_cargo_miri(args),

View File

@ -77,15 +77,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
// We cannot know which of those flags take arguments and which do not,
// so we cannot detect subcommands later.
let Some(subcommand) = args.next() else {
show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)"));
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)");
};
let subcommand = match &*subcommand {
"setup" => MiriCommand::Setup,
"test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
_ =>
show_error(format!(
show_error!(
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
)),
),
};
let verbose = num_arg_flag("-v");
@ -123,7 +123,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
match arg {
Ok(value) => {
if target_dir.is_some() {
show_error(format!("`--target-dir` is provided more than once"));
show_error!("`--target-dir` is provided more than once");
}
target_dir = Some(value.into());
}
@ -456,16 +456,13 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
let binary = binary_args.next().unwrap();
let file = File::open(&binary)
.unwrap_or_else(|_| show_error(format!(
.unwrap_or_else(|_| show_error!(
"file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary
)));
));
let file = BufReader::new(file);
let info = serde_json::from_reader(file).unwrap_or_else(|_| {
show_error(format!(
"file {:?} contains outdated or invalid JSON; try `cargo clean`",
binary
))
show_error!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary)
});
let info = match info {
CrateRunInfo::RunWith(info) => info,
@ -562,7 +559,7 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
// An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
// Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
// otherwise, we won't be called as rustdoc at all.
show_error(format!("cross-interpreting doctests is not currently supported by Miri."));
show_error!("cross-interpreting doctests is not currently supported by Miri.");
} else {
cmd.arg(arg);
}

View File

@ -73,7 +73,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) {
if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) {
if std::env::var_os("XARGO_CHECK").is_some() {
// The user manually gave us a xargo binary; don't do anything automatically.
show_error(format!("xargo is too old; please upgrade to the latest version"))
show_error!("xargo is too old; please upgrade to the latest version")
}
let mut cmd = cargo();
cmd.args(&["install", "xargo"]);
@ -97,10 +97,10 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) {
.output()
.expect("failed to determine sysroot");
if !output.status.success() {
show_error(format!(
show_error!(
"Failed to determine sysroot; Miri said:\n{}",
String::from_utf8_lossy(&output.stderr).trim_end()
));
);
}
let sysroot = std::str::from_utf8(&output.stdout).unwrap();
let sysroot = Path::new(sysroot.trim_end_matches('\n'));
@ -121,14 +121,14 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) {
}
};
if !rust_src.exists() {
show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display()));
show_error!("given Rust source directory `{}` does not exist.", rust_src.display());
}
if rust_src.file_name().and_then(OsStr::to_str) != Some("library") {
show_error(format!(
show_error!(
"given Rust source directory `{}` does not seem to be the `library` subdirectory of \
a Rust source checkout.",
rust_src.display()
));
);
}
// Next, we need our own libstd. Prepare a xargo project for that purpose.
@ -226,11 +226,9 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) {
// Finally run it!
if command.status().expect("failed to run xargo").success().not() {
if only_setup {
show_error(format!("failed to run xargo, see error details above"))
show_error!("failed to run xargo, see error details above")
} else {
show_error(format!(
"failed to run xargo; run `cargo miri setup` to see the error details"
))
show_error!("failed to run xargo; run `cargo miri setup` to see the error details")
}
}

View File

@ -14,6 +14,15 @@
pub use crate::arg::*;
pub fn show_error(msg: &str) -> ! {
eprintln!("fatal error: {msg}");
std::process::exit(1)
}
macro_rules! show_error {
($($tt:tt)*) => { show_error(&format!($($tt)*)) };
}
/// The information to run a crate with the given environment.
#[derive(Clone, Serialize, Deserialize)]
pub struct CrateRunEnv {
@ -55,10 +64,10 @@ pub enum CrateRunInfo {
impl CrateRunInfo {
pub fn store(&self, filename: &Path) {
let file = File::create(filename)
.unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display())));
.unwrap_or_else(|_| show_error!("cannot create `{}`", filename.display()));
let file = BufWriter::new(file);
serde_json::ser::to_writer(file, self)
.unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display())));
.unwrap_or_else(|_| show_error!("cannot write to `{}`", filename.display()));
}
}
@ -70,11 +79,6 @@ pub enum MiriCommand {
Forward(String),
}
pub fn show_error(msg: String) -> ! {
eprintln!("fatal error: {}", msg);
std::process::exit(1)
}
/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
pub fn escape_for_toml(s: &str) -> String {
// We want to surround this string in quotes `"`. So we first escape all quotes,
@ -187,15 +191,15 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) {
match buf.trim().to_lowercase().as_ref() {
// Proceed.
"" | "y" | "yes" => {}
"n" | "no" => show_error(format!("aborting as per your request")),
a => show_error(format!("invalid answer `{}`", a)),
"n" | "no" => show_error!("aborting as per your request"),
a => show_error!("invalid answer `{}`", a),
};
} else {
eprintln!("Running `{:?}` to {}.", cmd, text);
}
if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() {
show_error(format!("failed to {}", text));
show_error!("failed to {}", text);
}
}