1use std::path::PathBuf;
2
3use clap::{Parser, ValueEnum};
4use clap_complete::Shell;
5use log::LevelFilter;
6use regex::Regex;
7use serde::Deserialize;
8
9#[derive(Parser)]
10#[command(about = "CLI to watch a git repo and automatically commit changes")]
11pub struct Cli {
12 #[command(subcommand)]
13 pub command: Commands,
14}
15
16#[derive(Parser)]
17pub enum Commands {
18 Watch(CliOptions),
20
21 Completion {
23 #[arg(value_enum)]
25 shell: Shell,
26 },
27}
28
29#[derive(Parser)]
30pub struct CliOptions {
31 #[clap(default_value = ".")]
33 pub repository: PathBuf,
34
35 #[clap(flatten)]
36 pub commit_message: CommitMessageOptions,
37
38 #[clap(long = "commit-on-start", default_value = "true")]
40 pub commit_on_start: std::primitive::bool,
41
42 #[clap(long = "debounce-seconds", default_value = "1", verbatim_doc_comment)]
45 pub debounce_seconds: u64,
46
47 #[clap(long = "dry-run", default_value = "false")]
49 pub dry_run: bool,
50
51 #[clap(short = 'i', long = "ignore-regex", verbatim_doc_comment)]
56 pub ignore_regex: Option<Regex>,
57
58 #[arg(long, value_enum, default_value_t = LogLevel::Info)]
60 pub log_level: LogLevel,
61
62 #[clap(short = 'r', long = "remote", verbatim_doc_comment)]
65 pub remote: Option<String>,
66
67 #[clap(long = "retries", default_value = "3", verbatim_doc_comment)]
70 pub retries: i32,
71
72 #[clap(
75 short = 'w',
76 long = "watch",
77 default_value = "true",
78 verbatim_doc_comment
79 )]
80 pub watch: std::primitive::bool,
81}
82
83#[derive(Clone, Debug, clap::Args)]
84#[group(multiple = false)]
85pub struct CommitMessageOptions {
86 #[clap(short = 'm', long = "commit-message")]
87 pub message: Option<String>,
89
90 #[clap(long = "commit-message-script", verbatim_doc_comment)]
95 pub script: Option<PathBuf>,
96}
97
98#[derive(Copy, Clone, Debug, Default, Deserialize, ValueEnum)]
99pub enum LogLevel {
100 Trace,
101 Debug,
102 #[default]
103 Info,
104 Warn,
105 Error,
106}
107
108impl From<LogLevel> for LevelFilter {
109 fn from(level: LogLevel) -> Self {
110 match level {
111 LogLevel::Trace => LevelFilter::Trace,
112 LogLevel::Debug => LevelFilter::Debug,
113 LogLevel::Info => LevelFilter::Info,
114 LogLevel::Warn => LevelFilter::Warn,
115 LogLevel::Error => LevelFilter::Error,
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_loglevel_conversion() {
126 let conversions = [
127 (LogLevel::Trace, LevelFilter::Trace),
128 (LogLevel::Debug, LevelFilter::Debug),
129 (LogLevel::Info, LevelFilter::Info),
130 (LogLevel::Warn, LevelFilter::Warn),
131 (LogLevel::Error, LevelFilter::Error),
132 ];
133
134 for (input, expected) in conversions {
135 assert_eq!(LevelFilter::from(input), expected);
136 }
137 }
138}