use clap::Parser;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
#[derive(clap::Parser)]
#[expect(
clippy::struct_excessive_bools,
reason = "the bools are clap CLI flags, not an accumulating design"
)]
#[command(
name = "dejadoc",
bin_name = "cargo dejadoc",
version,
about = "Find duplicated Rust doctests across a workspace"
)]
struct Args {
#[arg(short, long)]
package: Option<String>,
#[arg(long)]
all_targets: bool,
#[arg(long)]
json: bool,
#[arg(short = 't', long, value_name = "N")]
threshold: Option<usize>,
#[arg(long, value_name = "N")]
min_tokens: Option<usize>,
#[arg(long, value_name = "PATH")]
config: Option<PathBuf>,
#[arg(long)]
no_fail: bool,
#[arg(short, long)]
verbose: bool,
}
fn main() -> ExitCode {
let mut args: Vec<String> = std::env::args().collect();
if args.get(1).is_some_and(|a| a == "dejadoc") {
args.remove(1);
}
let args = Args::parse_from(args);
let scan = match build(&args) {
Ok(scan) => scan,
Err(err) => {
eprintln!("dejadoc: {err}");
return ExitCode::from(2);
}
};
match scan.run(Path::new(".")) {
Ok(report) => {
let out = if args.json {
dejadoc::json(&report)
} else {
dejadoc::human(&report, args.verbose)
};
println!("{out}");
dejadoc::exit_code(&report, args.no_fail)
}
Err(err) => {
eprintln!("dejadoc: {err}");
ExitCode::from(2)
}
}
}
fn build(args: &Args) -> dejadoc::Result<dejadoc::Dejadoc> {
let mut scan = dejadoc::Dejadoc::default();
if let Some(package) = &args.package {
scan = scan.package(package);
}
if args.all_targets {
scan = scan.all_targets();
}
if let Some(threshold) = args.threshold {
scan = scan.threshold(threshold);
}
if let Some(min_tokens) = args.min_tokens {
scan = scan.min_tokens(min_tokens);
}
if let Some(config) = &args.config {
scan = scan.config(config)?;
}
Ok(scan)
}