Author:
Hash:
Timestamp:
+72 -38 +/-3 browse
Kevin Schoon [me@kevinschoon.com]
8634ef5b3eafe0a9c2cdf27ed03e960e4a5ba7e2
Sun, 31 Dec 2023 17:22:03 +0000 (1.5 years ago)
1 | diff --git a/Cargo.lock b/Cargo.lock |
2 | index 41e95f4..68b08a3 100644 |
3 | --- a/Cargo.lock |
4 | +++ b/Cargo.lock |
5 | @@ -591,6 +591,7 @@ dependencies = [ |
6 | "capnp", |
7 | "capnp-rpc", |
8 | "clap 4.4.8", |
9 | + "clap_complete", |
10 | "futures", |
11 | "mailpot", |
12 | "melib 0.8.4", |
13 | @@ -978,6 +979,15 @@ dependencies = [ |
14 | ] |
15 | |
16 | [[package]] |
17 | + name = "clap_complete" |
18 | + version = "4.4.5" |
19 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
20 | + checksum = "a51919c5608a32e34ea1d6be321ad070065e17613e168c5b6977024290f2630b" |
21 | + dependencies = [ |
22 | + "clap 4.4.8", |
23 | + ] |
24 | + |
25 | + [[package]] |
26 | name = "clap_derive" |
27 | version = "4.4.7" |
28 | source = "registry+https://github.com/rust-lang/crates.io-index" |
29 | diff --git a/ayllu-mail/Cargo.toml b/ayllu-mail/Cargo.toml |
30 | index 4f727d2..5fb51f0 100644 |
31 | --- a/ayllu-mail/Cargo.toml |
32 | +++ b/ayllu-mail/Cargo.toml |
33 | @@ -8,7 +8,7 @@ ayllu_api = {workspace = true} |
34 | ayllu_config = {workspace = true} |
35 | ayllu_rpc = {workspace = true} |
36 | serde = { version = "1.0.188", features = ["derive"] } |
37 | - clap = "4.4.6" |
38 | + clap = { version = "4.4.6", features = ["derive"] } |
39 | tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } |
40 | tracing = "0.1.37" |
41 | tokio = { version = "1.33.0", features = ["full"] } |
42 | @@ -17,3 +17,4 @@ futures = "0.3.28" |
43 | capnp = "0.18.1" |
44 | melib = "0.8.2" |
45 | mailpot = { git = "https://ayllu-forge.org/forks/mailpot", branch = "ayllu-dev"} |
46 | + clap_complete = "4.4.5" |
47 | diff --git a/ayllu-mail/src/main.rs b/ayllu-mail/src/main.rs |
48 | index d0a90bc..e09101b 100644 |
49 | --- a/ayllu-mail/src/main.rs |
50 | +++ b/ayllu-mail/src/main.rs |
51 | @@ -1,54 +1,77 @@ |
52 | - use std::path::Path; |
53 | + use std::io::stdout; |
54 | + use std::path::PathBuf; |
55 | + use std::str::FromStr; |
56 | |
57 | - use clap::{arg, value_parser, Command}; |
58 | + use clap::{arg, Command, CommandFactory, Parser, Subcommand}; |
59 | + use clap_complete::{generate, Generator, Shell}; |
60 | use tokio::{runtime::Builder as TokioBuilder, task::LocalSet}; |
61 | + use tracing::Level; |
62 | |
63 | mod config; |
64 | mod declarative; |
65 | mod server; |
66 | |
67 | + #[derive(Parser)] |
68 | + #[command(author, version, about, long_about = None)] |
69 | + #[command(name = "ayllu-mail")] |
70 | + #[command(about = "Mailing List Management plugin for Ayllu")] |
71 | + struct Cli { |
72 | + /// Path to your configuration file |
73 | + #[arg(short, long, value_name = "FILE")] |
74 | + config: Option<PathBuf>, |
75 | + |
76 | + /// Sets the logging level |
77 | + #[arg(short, long, value_name = "LEVEL")] |
78 | + level: Option<Level>, |
79 | + |
80 | + #[command(subcommand)] |
81 | + command: Commands, |
82 | + } |
83 | + |
84 | + #[derive(Subcommand, Debug, PartialEq)] |
85 | + enum Commands { |
86 | + /// generate autocomplete commands for common shells |
87 | + Complete { |
88 | + #[arg(long)] |
89 | + shell: Shell, |
90 | + }, |
91 | + /// run the rpc server and mailing list manager |
92 | + Serve {}, |
93 | + } |
94 | + |
95 | + fn print_completions<G: Generator>(gen: G, cmd: &mut Command) { |
96 | + generate(gen, cmd, cmd.get_name().to_string(), &mut stdout()); |
97 | + } |
98 | + |
99 | fn main() -> Result<(), Box<dyn std::error::Error>> { |
100 | - let command = Command::new("ayllu-mail") |
101 | - .about("ayllu email service") |
102 | - .arg( |
103 | - arg!(-c --config <FILE> "optional path to a configuration file") |
104 | - .id("config") |
105 | - .required(false) |
106 | - .value_parser(value_parser!(String)), |
107 | - ) |
108 | - .arg( |
109 | - arg!(-l --level <LEVEL> "logging level [ERROR,WARN,INFO,DEBUG,TRACE]") |
110 | - .id("level") |
111 | - .required(false) |
112 | - .value_parser(value_parser!(String)), |
113 | - ); |
114 | - let matches = command.get_matches(); |
115 | - let config_path = matches.get_one::<String>("config").map(Path::new); |
116 | - let ayllu_config = config::load(config_path)?; |
117 | - let log_level = matches |
118 | - .get_one::<String>("level") |
119 | - .cloned() |
120 | - .unwrap_or(ayllu_config.log_level.clone()); |
121 | + let cli = Cli::parse(); |
122 | + let ayllu_config = config::load(cli.config.as_ref().map(|cfg| cfg.as_path()))?; |
123 | + let config_level = Level::from_str(&ayllu_config.log_level)?; |
124 | tracing_subscriber::fmt() |
125 | .compact() |
126 | .with_line_number(true) |
127 | .with_level(true) |
128 | - // tokei will spam the console unless this is set |
129 | - .with_env_filter(format!( |
130 | - "{},tokei::language::language_type=error", |
131 | - log_level |
132 | - )) |
133 | + .with_max_level(cli.level.unwrap_or(config_level)) |
134 | .init(); |
135 | tracing::info!("logger initialized"); |
136 | declarative::initialize(&ayllu_config)?; |
137 | - TokioBuilder::new_current_thread() |
138 | - .enable_all() |
139 | - .build() |
140 | - .unwrap() |
141 | - .block_on(async move { |
142 | - LocalSet::new() |
143 | - .run_until(server::serve(&ayllu_config)) |
144 | - .await |
145 | - })?; |
146 | + match cli.command { |
147 | + Commands::Complete { shell } => { |
148 | + let mut cmd = Cli::command(); |
149 | + print_completions(shell, &mut cmd); |
150 | + } |
151 | + Commands::Serve {} => { |
152 | + TokioBuilder::new_current_thread() |
153 | + .enable_all() |
154 | + .build() |
155 | + .unwrap() |
156 | + .block_on(async move { |
157 | + LocalSet::new() |
158 | + .run_until(server::serve(&ayllu_config)) |
159 | + .await |
160 | + })?; |
161 | + } |
162 | + } |
163 | + |
164 | Ok(()) |
165 | } |