diff --git a/NEWS.md b/NEWS.md index bca34f04..950b7eee 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,8 @@ - Added: Alternative aliases for command line options, so you don't need to remember if it's "regex" or "re": `--regex`, `--examine-re`, `--examine-regex` (all for names to include) and `--exclude-regex`. +- Added: Accept `--manifest-path` as an alternative to `-d`, for consistency with other cargo commands. + ## 23.11.1 - New `--in-diff FILE` option tests only mutants that are in the diff from the diff --git a/src/main.rs b/src/main.rs index 9092b89c..b0ca5072 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,7 @@ use std::fs::read_to_string; use std::io; use std::process::exit; +use anyhow::ensure; use anyhow::Context; use anyhow::Result; use camino::Utf8Path; @@ -156,6 +157,10 @@ struct Args { #[arg(long)] list_files: bool, + /// path to Cargo.toml for the package to mutate. + #[arg(long)] + manifest_path: Option, + /// don't read .cargo/mutants.toml. #[arg(long)] no_config: bool, @@ -240,10 +245,19 @@ fn main() -> Result<()> { console.setup_global_trace(args.level)?; interrupt::install_handler(); - let start_dir: &Utf8Path = args.dir.as_deref().unwrap_or(Utf8Path::new(".")); + let start_dir: &Utf8Path = if let Some(manifest_path) = &args.manifest_path { + ensure!(manifest_path.is_file(), "Manifest path is not a file"); + ensure!( + args.dir.is_none(), + "--dir and --manifest-path are mutually exclusive" + ); + manifest_path.parent().expect("Manifest path has no parent") + } else if let Some(dir) = &args.dir { + dir + } else { + Utf8Path::new(".") + }; let workspace = Workspace::open(start_dir)?; - // let discovered_workspace = discover_packages(start_dir, false, &args.mutate_packages)?; - // let workspace_dir = &discovered_workspace.workspace_dir; let config = if args.no_config { config::Config::default() } else { diff --git a/src/workspace.rs b/src/workspace.rs index 955fa287..bf2d834e 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -107,16 +107,18 @@ struct PackageTop { } impl Workspace { + /// Open the workspace containing a given directory. pub fn open>(start_dir: P) -> Result { let dir = locate_project(start_dir.as_ref(), true)?; - let cargo_toml_path = dir.join("Cargo.toml"); - debug!(?cargo_toml_path, ?dir, "Find root files"); + let manifest_path = dir.join("Cargo.toml"); + debug!(?manifest_path, ?dir, "Find root files"); check_interrupted()?; let metadata = cargo_metadata::MetadataCommand::new() .no_deps() - .manifest_path(&cargo_toml_path) + .manifest_path(&manifest_path) .exec() - .context("run cargo metadata")?; + .with_context(|| format!("Failed to run cargo metadata on {:?}", manifest_path))?; + debug!(workspace_root = ?metadata.workspace_root, "Found workspace root"); Ok(Workspace { dir, metadata }) } diff --git a/tests/cli/workspace.rs b/tests/cli/workspace.rs index 1fb12ea1..4f73c278 100644 --- a/tests/cli/workspace.rs +++ b/tests/cli/workspace.rs @@ -10,6 +10,24 @@ use serde_json::json; use super::{assert_bytes_eq_json, copy_of_testdata, run}; +#[test] +fn open_by_manifest_path() { + run() + .args([ + "mutants", + "--list", + "--manifest-path", + "testdata/factorial/Cargo.toml", + ]) + .assert() + .success() + .stdout(indoc! {" + src/bin/factorial.rs:1: replace main with () + src/bin/factorial.rs:7: replace factorial -> u32 with 0 + src/bin/factorial.rs:7: replace factorial -> u32 with 1 + "}); +} + #[test] fn list_warns_about_unmatched_packages() { run()