mod check;
mod contract;
mod mutate;
use std::path::Path;
use std::process::ExitCode;
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser)]
#[command(name = "cargo impish", version, about)]
struct Cli {
#[command(subcommand)]
command: Command,
}
#[derive(Subcommand)]
enum Command {
Check {
#[arg(long)]
write: bool,
#[arg(long, value_enum, default_value_t = Format::Text)]
format: Format,
},
Mutate {
primitive: Option<String>,
#[arg(long, value_name = "REF", conflicts_with = "write")]
since: Option<String>,
#[arg(long)]
whole_suite: bool,
#[arg(short, long, value_name = "N")]
jobs: Option<usize>,
#[arg(long)]
write: bool,
#[arg(long, value_enum, default_value_t = Format::Text)]
format: Format,
},
}
#[derive(Clone, Copy, PartialEq, ValueEnum)]
enum Format {
Text,
Json,
}
fn root(cwd: &Path) -> anyhow::Result<&Path> {
cwd.ancestors()
.find(|dir| dir.join("contract").is_dir())
.ok_or_else(|| anyhow::anyhow!("no contract/ in {} or above it", cwd.display()))
}
fn main() -> ExitCode {
run().unwrap_or_else(|e| {
eprintln!("Error: {e:?}");
ExitCode::from(2)
})
}
fn run() -> anyhow::Result<ExitCode> {
let mut args: Vec<String> = std::env::args().collect();
if args.get(1).map(String::as_str) == Some("impish") {
args.remove(1);
}
let cwd = std::env::current_dir()?;
match Cli::parse_from(args).command {
Command::Check { write, format } => check::run(root(&cwd)?, write, format == Format::Json),
Command::Mutate {
primitive,
since,
whole_suite,
jobs,
write,
format,
} => mutate::run(
root(&cwd)?,
primitive.as_deref(),
since.as_deref(),
whole_suite,
write,
format == Format::Json,
jobs.unwrap_or_else(|| std::thread::available_parallelism().map_or(1, |n| n.get() / 2)),
),
}
}