use anyhow::Context;
use clap::Parser;
use std::fs;
use std::time::Instant;
use zahirscan::{engine, extract_zahir, setup, utils};
#[derive(Parser)]
#[command(name = zahirscan::PKG_NAME)]
#[command(
about = "Template mining for text/logs and metadata extraction for media, documents, archives, and more"
)]
#[command(version = env!("CARGO_PKG_VERSION"))]
struct Args {
#[command(subcommand)]
subcommand: Option<SubCmd>,
#[arg(short = 'i', long, num_args = 1..)]
input: Vec<String>,
#[arg(short = 'o', long)]
output: Option<String>,
#[command(flatten)]
mode: CliModeArgs,
#[command(flatten)]
processing: CliProcessingArgs,
}
#[derive(Parser)]
struct CliModeArgs {
#[arg(short = 'f', long)]
full: bool,
#[arg(short = 'd', long)]
dev: bool,
#[arg(short = 'r', long)]
redact: bool,
}
#[derive(Parser)]
struct CliProcessingArgs {
#[arg(short = 'n', long)]
no_media: bool,
#[arg(short = 'p', long)]
progress: bool,
}
#[derive(clap::Subcommand)]
enum SubCmd {
Init,
}
fn main() -> anyhow::Result<()> {
let args = Args::parse();
if matches!(args.subcommand, Some(SubCmd::Init)) {
run_init()?;
return Ok(());
}
let start = Instant::now();
setup::build_logger(args.mode.dev);
let mut config = setup::load_config();
setup::apply_cli_to_config(
&mut config,
setup::CliRuntimeFlags {
mode: setup::CliRuntimeMode {
dev: args.mode.dev,
full: args.mode.full,
redact: args.mode.redact,
},
processing: setup::CliRuntimeProcessing {
progress: args.processing.progress,
no_media: args.processing.no_media,
},
},
)?;
let (paths, output) = setup::resolve_output_paths(args.input.clone(), args.output.clone())?;
engine::chunking::setup_rayon_thread_pool(config.max_workers as usize);
let _result = extract_zahir(
&paths,
config.output_mode,
Some(&config),
output.as_deref(),
&zahirscan::OutputSink::Collect,
)?;
utils::path_string_helper::print_progress_handler(
&format!(
"Total time: {}",
utils::path_string_helper::format_duration(start.elapsed())
),
config.flags.show_progress,
);
Ok(())
}
fn run_init() -> anyhow::Result<()> {
let path = setup::xdg_config_path()
.context("Could not determine XDG config directory (HOME or APPDATA not set)")?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.with_context(|| format!("Failed to create config directory {}", parent.display()))?;
}
fs::write(&path, zahirscan::DEFAULT_CONFIG_TOML)
.with_context(|| format!("Failed to write config to {}", path.display()))?;
println!("Wrote default config to {}", path.display());
Ok(())
}