make subcommand configurable

This commit is contained in:
nora 2022-12-21 20:05:30 +01:00
parent a866667545
commit c0289c65f7
6 changed files with 97 additions and 39 deletions

View file

@ -17,15 +17,28 @@ Arguments:
[PATH] The directory/file of the code to be minimized [default: src] [PATH] The directory/file of the code to be minimized [default: src]
Options: Options:
--cargo-args <CARGO_ARGS> Additional arguments to pass to cargo, separated by whitespace --extra-args <EXTRA_ARGS>
--no-color To disable colored output Additional arguments to pass to cargo/rustc, separated by whitespace
--rustc This option bypasses cargo and uses rustc directly. Only works when a single file is passed as an argument --cargo-subcmd <CARGO_SUBCMD>
--no-verify Skips testing whether the regression reproduces and just does the most aggressive minimization. Mostly useful for testing and demonstration purposes The cargo subcommand used to find the reproduction, seperated by whitespace (for example `miri run`) [default: build]
--verify-fn <VERIFY_FN> A Rust closure returning a bool that checks whether a regression reproduces. Example: `--verify-fn='|output| output.contains("internal compiler error")'` --diagnostics-cargo-subcmd <DIAGNOSTICS_CARGO_SUBCMD>
--env <ENV> Additional environment variables to pass to cargo/rustc. Example: `--env NAME=VALUE --env ANOTHER_NAME=VALUE` The cargo subcommand used to get diagnostics like the dead_code lint from the compiler, seperated by whitespace. Defaults to the value of `--cargo-subcmd`
--project-dir <PROJECT_DIR> The working directory where cargo/rustc are invoked in. By default, this is the current working directory --no-color
--script-path <SCRIPT_PATH> NOTE: This is currently broken. A path to a script that is run to check whether code reproduces. When it exits with code 0, the problem reproduces To disable colored output
-h, --help Print help information --rustc
This option bypasses cargo and uses rustc directly. Only works when a single file is passed as an argument
--no-verify
Skips testing whether the regression reproduces and just does the most aggressive minimization. Mostly useful for testing and demonstration purposes
--verify-fn <VERIFY_FN>
A Rust closure returning a bool that checks whether a regression reproduces. Example: `--verify-fn='|output| output.contains("internal compiler error")'`
--env <ENV>
Additional environment variables to pass to cargo/rustc. Example: `--env NAME=VALUE --env ANOTHER_NAME=VALUE`
--project-dir <PROJECT_DIR>
The working directory where cargo/rustc are invoked in. By default, this is the current working directory
--script-path <SCRIPT_PATH>
NOTE: This is currently broken. A path to a script that is run to check whether code reproduces. When it exits with code 0, the problem reproduces
-h, --help
Print help information
``` ```
## What it does ## What it does

View file

@ -41,27 +41,46 @@ struct BuildInner {
env: Vec<EnvVar>, env: Vec<EnvVar>,
allow_color: bool, allow_color: bool,
project_dir: Option<PathBuf>, project_dir: Option<PathBuf>,
extra_args: Vec<String>,
} }
#[derive(Debug)] #[derive(Debug)]
enum BuildMode { enum BuildMode {
Cargo { args: Option<Vec<String>> }, Cargo {
/// May be something like `miri run`.
subcommand: Vec<String>,
diag_subcommand: Vec<String>,
},
Script(PathBuf), Script(PathBuf),
Rustc, Rustc,
} }
impl Build { impl Build {
pub fn new(options: &Options) -> Self { pub fn new(options: &Options) -> Result<Self> {
if options.rustc && options.cargo_subcmd != "build" {
bail!("Cannot specify --rustc together with --cargo-subcmd or --cargo-args");
}
let extra_args = options
.extra_args
.as_deref()
.map(split_args)
.unwrap_or_default();
let mode = if options.rustc { let mode = if options.rustc {
BuildMode::Rustc BuildMode::Rustc
} else if let Some(script) = &options.script_path { } else if let Some(script) = &options.script_path {
BuildMode::Script(script.clone()) BuildMode::Script(script.clone())
} else { } else {
let subcommand = split_args(&options.cargo_subcmd);
let diag_subcommand = options
.diagnostics_cargo_subcmd
.as_deref()
.map(split_args)
.unwrap_or_else(|| subcommand.clone());
BuildMode::Cargo { BuildMode::Cargo {
args: options subcommand,
.cargo_args diag_subcommand,
.as_ref()
.map(|cmd| cmd.split_whitespace().map(ToString::to_string).collect()),
} }
}; };
@ -73,7 +92,7 @@ impl Build {
Verify::Ice Verify::Ice
}; };
Self { Ok(Self {
inner: Rc::new(BuildInner { inner: Rc::new(BuildInner {
mode, mode,
input_path: options.path.clone(), input_path: options.path.clone(),
@ -81,8 +100,9 @@ impl Build {
env: options.env.clone(), env: options.env.clone(),
allow_color: !options.no_color, allow_color: !options.no_color,
project_dir: options.project_dir.clone(), project_dir: options.project_dir.clone(),
extra_args,
}), }),
} })
} }
fn cmd(&self, name: impl AsRef<OsStr>) -> Command { fn cmd(&self, name: impl AsRef<OsStr>) -> Command {
@ -106,17 +126,19 @@ impl Build {
} }
let (is_ice, output) = match &inner.mode { let (is_ice, output) = match &inner.mode {
BuildMode::Cargo { args } => { BuildMode::Cargo {
subcommand,
diag_subcommand: _,
} => {
let mut cmd = self.cmd("cargo"); let mut cmd = self.cmd("cargo");
cmd.arg("build");
cmd.args(subcommand);
if inner.allow_color { if inner.allow_color {
cmd.arg("--color=always"); cmd.arg("--color=always");
} }
for arg in args.iter().flatten() { cmd.args(&inner.extra_args);
cmd.arg(arg);
}
for env in &inner.env { for env in &inner.env {
cmd.env(&env.key, &env.value); cmd.env(&env.key, &env.value);
@ -135,6 +157,8 @@ impl Build {
BuildMode::Script(script_path) => { BuildMode::Script(script_path) => {
let mut cmd = self.cmd(script_path); let mut cmd = self.cmd(script_path);
cmd.args(&inner.extra_args);
for env in &inner.env { for env in &inner.env {
cmd.env(&env.key, &env.value); cmd.env(&env.key, &env.value);
} }
@ -154,6 +178,8 @@ impl Build {
cmd.arg("--color=always"); cmd.arg("--color=always");
} }
cmd.args(&inner.extra_args);
for env in &inner.env { for env in &inner.env {
cmd.env(&env.key, &env.value); cmd.env(&env.key, &env.value);
} }
@ -188,13 +214,17 @@ impl Build {
let inner = &self.inner; let inner = &self.inner;
let diags = match &inner.mode { let diags = match &inner.mode {
BuildMode::Cargo { args } => { BuildMode::Cargo {
subcommand: _,
diag_subcommand,
} => {
let mut cmd = self.cmd("cargo"); let mut cmd = self.cmd("cargo");
cmd.args(["build", "--message-format=json"]);
for arg in args.iter().flatten() { cmd.args(diag_subcommand);
cmd.arg(arg);
} cmd.arg("--message-format=json");
cmd.args(&inner.extra_args);
for env in &inner.env { for env in &inner.env {
cmd.env(&env.key, &env.value); cmd.env(&env.key, &env.value);
@ -295,3 +325,7 @@ pub struct CargoJsonCompileMessage {
pub reason: String, pub reason: String,
pub message: Option<Diagnostic>, pub message: Option<Diagnostic>,
} }
fn split_args(s: &str) -> Vec<String> {
s.split_whitespace().map(ToString::to_string).collect()
}

View file

@ -31,9 +31,18 @@ pub enum Cargo {
#[derive(clap::Args, Debug)] #[derive(clap::Args, Debug)]
pub struct Options { pub struct Options {
/// Additional arguments to pass to cargo, separated by whitespace. /// Additional arguments to pass to cargo/rustc, separated by whitespace.
#[arg(long)] #[arg(long)]
pub cargo_args: Option<String>, pub extra_args: Option<String>,
/// The cargo subcommand used to find the reproduction, seperated by whitespace (for example `miri run`).
#[arg(long, default_value = "build")]
pub cargo_subcmd: String,
/// The cargo subcommand used to get diagnostics like the dead_code lint from the compiler, seperated by whitespace.
/// Defaults to the value of `--cargo-subcmd`.
#[arg(long)]
pub diagnostics_cargo_subcmd: Option<String>,
/// To disable colored output. /// To disable colored output.
#[arg(long)] #[arg(long)]
@ -96,7 +105,7 @@ impl FromStr for EnvVar {
} }
pub fn minimize(options: Options) -> Result<()> { pub fn minimize(options: Options) -> Result<()> {
let build = build::Build::new(&options); let build = build::Build::new(&options)?;
let mut minimizer = Minimizer::new_glob_dir(options, build)?; let mut minimizer = Minimizer::new_glob_dir(options, build)?;
@ -129,7 +138,9 @@ impl Default for Options {
fn default() -> Self { fn default() -> Self {
Self { Self {
script_path: None, script_path: None,
cargo_args: None, extra_args: None,
cargo_subcmd: "build".into(),
diagnostics_cargo_subcmd: None,
no_color: false, no_color: false,
rustc: false, rustc: false,
no_verify: false, no_verify: false,

View file

@ -1 +1,3 @@
pub fn unused() {} pub(crate) fn unused() {
loop {}
}

View file

@ -1,10 +1,8 @@
fn unused() { fn unused() {
other::unused(); loop {}
} }
fn main() { fn main() {
unused(); loop {}
} }
mod folder; mod folder;
mod other; mod other;

View file

@ -1,3 +1,3 @@
pub fn unused() { pub(crate) fn unused() {
crate::folder::unused(); loop {}
} }