use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug, Clone)]
#[command(name = "litho-tui", about = "Interactive terminal UI for litho")]
pub struct TuiCli {
#[arg(short, long)]
pub mode: Option<String>,
#[arg(short, long)]
pub device: Option<String>,
#[arg(short, long)]
pub image: Option<String>,
#[arg(short, long)]
pub file: Option<String>,
#[arg(long)]
pub start: bool,
#[arg(long)]
pub log_file: Option<PathBuf>,
#[arg(long, default_value = "info")]
pub log_level: String,
}
#[derive(Debug, Clone, Default)]
pub struct LaunchParams {
pub mode: Option<String>,
pub device: Option<String>,
pub image: Option<String>,
pub start: bool,
}
impl From<TuiCli> for LaunchParams {
fn from(cli: TuiCli) -> Self {
let mode = cli.mode.map(|m| normalize_mode(&m));
let image = cli.image.or(cli.file);
LaunchParams {
mode,
device: cli.device,
image,
start: cli.start,
}
}
}
pub fn normalize_mode(mode: &str) -> String {
let lower = mode.to_lowercase();
if lower == "clone" || lower == "backup" {
"clone".to_string()
} else {
"flash".to_string()
}
}
pub fn launch_prefilled(launch: &LaunchParams, image_file_nonempty: bool) -> bool {
launch.mode.is_some() || launch.device.is_some() || image_file_nonempty
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalize_mode_maps_backup_to_clone() {
assert_eq!(normalize_mode("backup"), "clone");
assert_eq!(normalize_mode("CLONE"), "clone");
assert_eq!(normalize_mode("flash"), "flash");
}
#[test]
fn tui_cli_parses_launch_args() {
let cli = TuiCli::try_parse_from([
"litho-tui",
"--mode",
"clone",
"--device",
"/dev/sdb",
"--image",
"/tmp/out.img",
"--start",
"--log-level",
"debug",
])
.expect("parse");
assert_eq!(cli.mode.as_deref(), Some("clone"));
assert_eq!(cli.device.as_deref(), Some("/dev/sdb"));
assert_eq!(cli.image.as_deref(), Some("/tmp/out.img"));
assert!(cli.start);
assert_eq!(cli.log_level, "debug");
let launch: LaunchParams = cli.into();
assert_eq!(launch.mode.as_deref(), Some("clone"));
assert_eq!(launch.device.as_deref(), Some("/dev/sdb"));
assert_eq!(launch.image.as_deref(), Some("/tmp/out.img"));
assert!(launch.start);
}
#[test]
fn tui_cli_file_alias_maps_to_image() {
let cli = TuiCli::try_parse_from(["litho-tui", "-f", "/tmp/disk.img"]).unwrap();
let launch: LaunchParams = cli.into();
assert_eq!(launch.image.as_deref(), Some("/tmp/disk.img"));
}
#[test]
fn launch_prefilled_detects_any_launch_arg() {
assert!(launch_prefilled(
&LaunchParams {
mode: Some("flash".into()),
..Default::default()
},
false
));
assert!(launch_prefilled(
&LaunchParams {
device: Some("/dev/sdb".into()),
..Default::default()
},
false
));
assert!(launch_prefilled(&LaunchParams::default(), true));
assert!(!launch_prefilled(&LaunchParams::default(), false));
}
}