use std::{fmt::Display, net::SocketAddr, path::PathBuf, str::FromStr};
use argh::FromArgs;
use github_webhook_extract::EventDiscriminants;
use serde::{Deserialize, Serialize};
use crate::error::TcpOrUnixParseError;
#[derive(Debug, Clone, FromArgs)]
pub struct AppArgs {
#[argh(option)]
pub log_level: Option<String>,
#[argh(option)]
pub log_file: Option<PathBuf>,
#[argh(subcommand)]
pub action: Action,
}
#[derive(Debug, Clone, FromArgs)]
#[argh(subcommand)]
pub enum Action {
Init(Init),
Serve(Serve),
Daemon(Daemon),
Version(Version),
}
#[derive(Debug, Clone, FromArgs)]
#[argh(subcommand, name = "init")]
pub struct Init {
#[argh(option)]
pub username: Option<String>,
#[argh(option)]
pub repo_path: Option<PathBuf>,
#[argh(option)]
pub remote: Option<String>,
#[argh(option)]
pub branch: Option<String>,
#[argh(option)]
pub system_name: Option<String>,
#[argh(option, from_str_fn(parse_multiple_events))]
pub update_events: Option<Vec<EventDiscriminants>>,
#[argh(option)]
pub addr: Option<TcpOrUnix>,
#[argh(option)]
pub socket_group: Option<String>,
#[argh(option)]
pub socket_user: Option<String>,
#[argh(option)]
pub pre_restart_command: Option<String>,
#[argh(option)]
pub shook_service_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitConfig {
pub username: String,
pub repo_path: PathBuf,
pub remote: String,
pub branch: String,
pub system_name: String,
pub update_events: Vec<EventDiscriminants>,
pub addr: TcpOrUnix,
pub socket_group: String,
pub socket_user: String,
pub pre_restart_command: String,
pub shook_service_name: String,
}
#[derive(Debug, Clone, FromArgs)]
#[argh(subcommand, name = "serve")]
pub struct Serve {
#[argh(option)]
pub username: Option<String>,
#[argh(option)]
pub repo_path: Option<PathBuf>,
#[argh(option)]
pub remote: Option<String>,
#[argh(option)]
pub branch: Option<String>,
#[argh(option)]
pub system_name: Option<String>,
#[argh(option, from_str_fn(parse_multiple_events))]
pub update_events: Option<Vec<EventDiscriminants>>,
#[argh(option)]
pub addr: Option<TcpOrUnix>,
#[argh(option)]
pub socket_group: Option<String>,
#[argh(option)]
pub socket_user: Option<String>,
#[argh(option)]
pub pre_restart_command: Option<String>,
}
pub fn parse_multiple_events(s: &str) -> Result<Vec<EventDiscriminants>, String> {
s.split(',')
.map(|s| EventDiscriminants::from_str(s).map_err(|e| e.to_string()))
.collect::<Result<Vec<_>, _>>()
}
#[derive(Debug, Clone, FromArgs)]
#[argh(subcommand, name = "daemon")]
pub struct Daemon {
#[argh(subcommand)]
pub action: DaemonAction,
#[argh(positional)]
pub config_path: PathBuf,
}
#[derive(Debug, Clone, Copy, FromArgs)]
#[argh(subcommand)]
pub enum DaemonAction {
Start(DaemonStart),
Enable(DaemonEnable),
Stop(DaemonStop),
}
#[derive(Debug, Clone, FromArgs)]
#[argh(subcommand, name = "version")]
pub struct Version {}
#[derive(Debug, Clone, Copy, FromArgs)]
#[argh(subcommand, name = "start")]
pub struct DaemonStart {}
#[derive(Debug, Clone, Copy, FromArgs)]
#[argh(subcommand, name = "stop")]
pub struct DaemonStop {}
#[derive(Debug, Clone, Copy, FromArgs)]
#[argh(subcommand, name = "enable")]
pub struct DaemonEnable {}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerConfig {
pub username: String,
pub repo_path: PathBuf,
pub remote: String,
pub branch: String,
pub system_name: String,
pub update_events: Vec<EventDiscriminants>,
pub addr: TcpOrUnix,
pub socket_group: String,
pub socket_user: String,
pub pre_restart_command: String,
}
impl ServerConfig {
pub fn merge(&mut self, cli: Serve) {
if let Some(p) = cli.repo_path {
self.repo_path = p;
}
if let Some(n) = cli.system_name {
self.system_name = n;
}
if let Some(e) = cli.update_events {
self.update_events = e;
}
if let Some(a) = cli.addr {
self.addr = a;
}
if let Some(u) = cli.username {
self.username = u;
}
if let Some(r) = cli.remote {
self.remote = r;
}
if let Some(b) = cli.branch {
self.branch = b;
}
if let Some(g) = cli.socket_group {
self.socket_group = g;
}
if let Some(u) = cli.socket_user {
self.socket_user = u;
}
if let Some(c) = cli.pre_restart_command {
self.pre_restart_command = c;
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", content = "value")]
pub enum TcpOrUnix {
Tcp(SocketAddr),
Unix(PathBuf),
}
impl FromStr for TcpOrUnix {
type Err = TcpOrUnixParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(s) = SocketAddr::from_str(s) {
return Ok(Self::Tcp(s));
}
Ok(Self::Unix(PathBuf::from_str(s).unwrap()))
}
}
impl Display for TcpOrUnix {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Tcp(s) => write!(f, "{}", s),
Self::Unix(p) => write!(f, "{}", p.to_string_lossy()),
}
}
}