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(
11 name = "gitwatch",
12 about = "CLI to watch a git repo and automatically commit changes"
13)]
14pub struct Cli {
15 #[command(subcommand)]
16 pub command: Commands,
17}
18
19#[derive(Parser)]
20pub enum Commands {
21 Watch(CliOptions),
23
24 Completion {
26 #[arg(value_enum)]
28 shell: Shell,
29 },
30}
31
32#[derive(Parser)]
33pub struct CliOptions {
34 #[clap(default_value = ".")]
36 pub repository: PathBuf,
37
38 #[clap(flatten)]
39 pub commit_message: CommitMessageOptions,
40
41 #[clap(long = "commit-on-start", default_value = "true")]
43 pub commit_on_start: std::primitive::bool,
44
45 #[clap(long = "debounce-seconds", default_value = "1", verbatim_doc_comment)]
48 pub debounce_seconds: u64,
49
50 #[clap(long = "dry-run", default_value = "false")]
52 pub dry_run: bool,
53
54 #[clap(short = 'i', long = "ignore-regex", verbatim_doc_comment)]
59 pub ignore_regex: Option<Regex>,
60
61 #[arg(long, value_enum, default_value_t = LogLevel::Info)]
63 pub log_level: LogLevel,
64
65 #[clap(short = 'r', long = "remote", verbatim_doc_comment)]
68 pub remote: Option<String>,
69
70 #[clap(long = "retries", default_value = "3", verbatim_doc_comment)]
73 pub retries: i32,
74
75 #[clap(
78 short = 'w',
79 long = "watch",
80 default_value = "true",
81 verbatim_doc_comment
82 )]
83 pub watch: std::primitive::bool,
84}
85
86#[derive(Clone, Debug, clap::Args)]
87#[group(multiple = false)]
88pub struct CommitMessageOptions {
89 #[clap(short = 'm', long = "commit-message")]
90 pub message: Option<String>,
92
93 #[clap(long = "commit-message-script", verbatim_doc_comment)]
98 pub script: Option<PathBuf>,
99}
100
101#[derive(Copy, Clone, Debug, Default, Deserialize, ValueEnum)]
102pub enum LogLevel {
103 Trace,
104 Debug,
105 #[default]
106 Info,
107 Warn,
108 Error,
109}
110
111impl From<LogLevel> for LevelFilter {
112 fn from(level: LogLevel) -> Self {
113 match level {
114 LogLevel::Trace => LevelFilter::Trace,
115 LogLevel::Debug => LevelFilter::Debug,
116 LogLevel::Info => LevelFilter::Info,
117 LogLevel::Warn => LevelFilter::Warn,
118 LogLevel::Error => LevelFilter::Error,
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_loglevel_conversion() {
129 let conversions = [
130 (LogLevel::Trace, LevelFilter::Trace),
131 (LogLevel::Debug, LevelFilter::Debug),
132 (LogLevel::Info, LevelFilter::Info),
133 (LogLevel::Warn, LevelFilter::Warn),
134 (LogLevel::Error, LevelFilter::Error),
135 ];
136
137 for (input, expected) in conversions {
138 assert_eq!(LevelFilter::from(input), expected);
139 }
140 }
141}