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)] #![feature(let_else)]
#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)]
#[macro_use]
mod util;
mod arg; mod arg;
mod phases; mod phases;
mod setup; mod setup;
mod util;
mod version; mod version;
use std::{env, iter}; use std::{env, iter};
@ -73,9 +75,9 @@ fn main() {
} }
let Some(first) = args.next() else { 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`" "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`"
)) )
}; };
match first.as_str() { match first.as_str() {
"miri" => phase_cargo_miri(args), "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, // We cannot know which of those flags take arguments and which do not,
// so we cannot detect subcommands later. // so we cannot detect subcommands later.
let Some(subcommand) = args.next() else { 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 { let subcommand = match &*subcommand {
"setup" => MiriCommand::Setup, "setup" => MiriCommand::Setup,
"test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
_ => _ =>
show_error(format!( show_error!(
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
)), ),
}; };
let verbose = num_arg_flag("-v"); let verbose = num_arg_flag("-v");
@ -123,7 +123,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
match arg { match arg {
Ok(value) => { Ok(value) => {
if target_dir.is_some() { 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()); 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 binary = binary_args.next().unwrap();
let file = File::open(&binary) 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 "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary
))); ));
let file = BufReader::new(file); let file = BufReader::new(file);
let info = serde_json::from_reader(file).unwrap_or_else(|_| { let info = serde_json::from_reader(file).unwrap_or_else(|_| {
show_error(format!( show_error!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary)
"file {:?} contains outdated or invalid JSON; try `cargo clean`",
binary
))
}); });
let info = match info { let info = match info {
CrateRunInfo::RunWith(info) => 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. // 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; // 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. // 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 { } else {
cmd.arg(arg); 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 xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) {
if std::env::var_os("XARGO_CHECK").is_some() { if std::env::var_os("XARGO_CHECK").is_some() {
// The user manually gave us a xargo binary; don't do anything automatically. // 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(); let mut cmd = cargo();
cmd.args(&["install", "xargo"]); cmd.args(&["install", "xargo"]);
@ -97,10 +97,10 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) {
.output() .output()
.expect("failed to determine sysroot"); .expect("failed to determine sysroot");
if !output.status.success() { if !output.status.success() {
show_error(format!( show_error!(
"Failed to determine sysroot; Miri said:\n{}", "Failed to determine sysroot; Miri said:\n{}",
String::from_utf8_lossy(&output.stderr).trim_end() String::from_utf8_lossy(&output.stderr).trim_end()
)); );
} }
let sysroot = std::str::from_utf8(&output.stdout).unwrap(); let sysroot = std::str::from_utf8(&output.stdout).unwrap();
let sysroot = Path::new(sysroot.trim_end_matches('\n')); 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() { 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") { 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 \ "given Rust source directory `{}` does not seem to be the `library` subdirectory of \
a Rust source checkout.", a Rust source checkout.",
rust_src.display() rust_src.display()
)); );
} }
// Next, we need our own libstd. Prepare a xargo project for that purpose. // 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! // Finally run it!
if command.status().expect("failed to run xargo").success().not() { if command.status().expect("failed to run xargo").success().not() {
if only_setup { 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 { } else {
show_error(format!( show_error!("failed to run xargo; run `cargo miri setup` to see the error details")
"failed to run xargo; run `cargo miri setup` to see the error details"
))
} }
} }

View File

@ -14,6 +14,15 @@
pub use crate::arg::*; 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. /// The information to run a crate with the given environment.
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct CrateRunEnv { pub struct CrateRunEnv {
@ -55,10 +64,10 @@ pub enum CrateRunInfo {
impl CrateRunInfo { impl CrateRunInfo {
pub fn store(&self, filename: &Path) { pub fn store(&self, filename: &Path) {
let file = File::create(filename) 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); let file = BufWriter::new(file);
serde_json::ser::to_writer(file, self) 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), 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. /// 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 { pub fn escape_for_toml(s: &str) -> String {
// We want to surround this string in quotes `"`. So we first escape all quotes, // 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() { match buf.trim().to_lowercase().as_ref() {
// Proceed. // Proceed.
"" | "y" | "yes" => {} "" | "y" | "yes" => {}
"n" | "no" => show_error(format!("aborting as per your request")), "n" | "no" => show_error!("aborting as per your request"),
a => show_error(format!("invalid answer `{}`", a)), a => show_error!("invalid answer `{}`", a),
}; };
} else { } else {
eprintln!("Running `{:?}` to {}.", cmd, text); eprintln!("Running `{:?}` to {}.", cmd, text);
} }
if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() {
show_error(format!("failed to {}", text)); show_error!("failed to {}", text);
} }
} }