use std::path::PathBuf;
use clap::{Parser, Subcommand, ValueEnum};
use crate::network::AdapterKind;
#[derive(Debug, Parser)]
#[command(name = "ddns-a")]
#[command(version, about, long_about = None)]
#[allow(clippy::struct_excessive_bools)] pub struct Cli {
#[command(subcommand)]
pub command: Option<Command>,
#[arg(long, global = true)]
pub url: Option<String>,
#[arg(long = "ip-version", value_enum, global = true)]
pub ip_version: Option<IpVersionArg>,
#[arg(long = "change-kind", value_enum, global = true)]
pub change_kind: Option<ChangeKindArg>,
#[arg(long)]
pub method: Option<String>,
#[arg(long = "header", value_name = "K=V")]
pub headers: Vec<String>,
#[arg(long)]
pub bearer: Option<String>,
#[arg(long = "body-template")]
pub body_template: Option<String>,
#[arg(long = "include-adapter", value_name = "PATTERN")]
pub include_adapters: Vec<String>,
#[arg(long = "exclude-adapter", value_name = "PATTERN")]
pub exclude_adapters: Vec<String>,
#[arg(long = "include-kind", value_name = "KIND", value_delimiter = ',')]
pub include_kinds: Vec<AdapterKindArg>,
#[arg(long = "exclude-kind", value_name = "KIND", value_delimiter = ',')]
pub exclude_kinds: Vec<AdapterKindArg>,
#[arg(long = "poll-interval")]
pub poll_interval: Option<u64>,
#[arg(long = "poll-only")]
pub poll_only: bool,
#[arg(long = "retry-max")]
pub retry_max: Option<u32>,
#[arg(long = "retry-delay")]
pub retry_delay: Option<u64>,
#[arg(long, short)]
pub config: Option<PathBuf>,
#[arg(long = "state-file")]
pub state_file: Option<PathBuf>,
#[arg(long)]
pub dry_run: bool,
#[arg(long, short)]
pub verbose: bool,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Init {
#[arg(long, short, default_value = "ddns-a.toml")]
output: PathBuf,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum IpVersionArg {
#[value(name = "ipv4")]
V4,
#[value(name = "ipv6")]
V6,
#[value(name = "both")]
Both,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum ChangeKindArg {
#[value(name = "added")]
Added,
#[value(name = "removed")]
Removed,
#[value(name = "both")]
Both,
}
impl From<IpVersionArg> for crate::network::IpVersion {
fn from(arg: IpVersionArg) -> Self {
match arg {
IpVersionArg::V4 => Self::V4,
IpVersionArg::V6 => Self::V6,
IpVersionArg::Both => Self::Both,
}
}
}
impl From<ChangeKindArg> for crate::monitor::ChangeKind {
fn from(arg: ChangeKindArg) -> Self {
match arg {
ChangeKindArg::Added => Self::Added,
ChangeKindArg::Removed => Self::Removed,
ChangeKindArg::Both => Self::Both,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
#[value(rename_all = "lowercase")]
pub enum AdapterKindArg {
Ethernet,
Wireless,
Virtual,
Loopback,
}
impl From<AdapterKindArg> for AdapterKind {
fn from(arg: AdapterKindArg) -> Self {
match arg {
AdapterKindArg::Ethernet => Self::Ethernet,
AdapterKindArg::Wireless => Self::Wireless,
AdapterKindArg::Virtual => Self::Virtual,
AdapterKindArg::Loopback => Self::Loopback,
}
}
}
impl Cli {
#[must_use]
pub fn parse_args() -> Self {
Self::parse()
}
pub fn parse_from_iter<I, T>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
Self::parse_from(iter)
}
#[must_use]
pub const fn is_init(&self) -> bool {
matches!(self.command, Some(Command::Init { .. }))
}
}