use clap::{Parser, Subcommand};
use crate::commands::execute::{run_command, ExecOptions};
use crate::commands::spec::IntervalCommandSpec;
use crate::commands::Result;
pub mod compat;
pub mod regular;
#[derive(Parser, Clone, Debug)]
#[command(
name = "polaranges",
version,
about = "Modern interval operations for polaranges. The regular mode is the current default command surface."
)]
pub struct RootCli {
#[command(subcommand)]
pub command: RootCommand,
}
#[derive(Subcommand, Clone, Debug)]
pub enum RootCommand {
Overlap(regular::OverlapArgs),
Nearest(regular::NearestArgs),
Compat(compat::CompatCli),
}
impl RootCli {
pub fn exec_options(&self) -> ExecOptions {
let execution = match &self.command {
RootCommand::Overlap(args) => args.execution,
RootCommand::Nearest(args) => args.execution,
RootCommand::Compat(_) => regular::ExecutionArgs::default(),
};
ExecOptions {
benchmark: execution.benchmark,
reps: execution.reps.max(1),
no_output: execution.no_output,
..ExecOptions::default()
}
}
pub fn into_command_spec(self) -> Result<IntervalCommandSpec> {
match self.command {
RootCommand::Overlap(args) => {
regular::translate_regular_command(regular::RegularCommand::Overlap(args))
}
RootCommand::Nearest(args) => {
regular::translate_regular_command(regular::RegularCommand::Nearest(args))
}
RootCommand::Compat(args) => compat::translate_compat_cli(args),
}
}
}
pub fn run() -> Result<()> {
let cli = RootCli::parse();
let options = cli.exec_options();
let spec = cli.into_command_spec()?;
run_command(&spec, &options)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::spec;
use crate::commands::{execute::run_command, ExecOptions};
#[test]
fn root_cli_routes_direct_commands_into_shared_specs() {
let cli = RootCli::try_parse_from([
"polaranges",
"overlap",
"--a",
"left.bed",
"--b",
"right.bed",
])
.unwrap();
let spec = cli.into_command_spec().unwrap();
match spec {
spec::IntervalCommandSpec::Overlap(spec) => {
assert_eq!(spec.inputs.left_path, std::path::PathBuf::from("left.bed"));
assert_eq!(
spec.inputs.right_path,
std::path::PathBuf::from("right.bed")
);
}
other => panic!("expected overlap spec, got {other:?}"),
}
let dispatcher: fn(
&spec::IntervalCommandSpec,
&ExecOptions,
) -> crate::commands::Result<()> = run_command;
let _ = dispatcher;
}
#[test]
fn root_cli_builds_exec_options_from_regular_flags() {
let cli = RootCli::try_parse_from([
"polaranges",
"nearest",
"--a",
"left.bed",
"--b",
"right.bed",
"--benchmark",
"--reps",
"4",
"--no-output",
])
.unwrap();
let options = cli.exec_options();
assert!(options.benchmark);
assert_eq!(options.reps, 4);
assert!(options.no_output);
}
}