1use super::*;
2use commands::Command;
3
4pub mod commands;
5
6pub static CONFIG: OnceLock<Config> = OnceLock::new();
7
8#[derive(Parser, Debug)]
9#[command(name = "CI manager")]
10#[command(bin_name = "ci-manager", version, propagate_version = true, author, styles = config_styles())]
11#[command(about = "Manage CI")]
12pub struct Config {
13 #[command(subcommand)]
14 command: Option<Command>,
15 #[arg(long, global = true, value_hint = ValueHint::Other, name = "SHELL")]
17 completions: Option<clap_complete::Shell>,
18 #[arg(short, long, global = true, default_value_t = 2)]
20 verbosity: u8,
21 #[arg(long, default_value_t = false, global = true)]
23 dry_run: bool,
24 #[arg(value_enum, long, global = true)]
26 ci: Option<CIProvider>,
27 #[arg(long, global = true, default_value_t = false)]
29 trim_timestamp: bool,
30 #[arg(long, global = true, default_value_t = false)]
32 trim_ansi_codes: bool,
33}
34
35impl Config {
36 pub fn global() -> &'static Config {
38 CONFIG.get().expect("Config is not initialized")
39 }
40
41 pub fn subcmd(&self) -> &Command {
43 if let Some(subcmd) = &self.command {
44 subcmd
45 } else {
46 log::error!("Subcommand required! use `--help` for more information");
47 std::process::exit(1);
48 }
49 }
50
51 pub fn generate_completion_script(&self) -> bool {
54 match self.completions {
55 Some(shell) => {
56 generate_completion_script(shell);
57 true
58 }
59 None => false,
60 }
61 }
62
63 pub fn verbosity(&self) -> u8 {
65 self.verbosity
66 }
67
68 pub fn dry_run(&self) -> bool {
70 self.dry_run
71 }
72
73 pub fn no_ci(&self) -> Option<CIProvider> {
75 self.ci
76 }
77
78 pub fn trim_timestamp(&self) -> bool {
80 self.trim_timestamp
81 }
82
83 pub fn trim_ansi_codes(&self) -> bool {
85 self.trim_ansi_codes
86 }
87}
88
89pub fn init() -> Result<()> {
91 let config = Config::parse();
92 CONFIG.set(config).expect("Config is already initialized");
93
94 use stderrlog::LogLevelNum;
95 let log_level = match Config::global().verbosity() {
96 0 => LogLevelNum::Error,
97 1 => LogLevelNum::Warn,
98 2 => LogLevelNum::Info,
99 3 => LogLevelNum::Debug,
100 4 => LogLevelNum::Trace,
101 _ => {
102 eprintln!("Invalid verbosity level: {}", Config::global().verbosity());
103 eprintln!("Using highest verbosity level: Trace");
104 LogLevelNum::Trace
105 }
106 };
107 stderrlog::new().verbosity(log_level).quiet(false).init()?;
108
109 log::debug!("Config: {:#?}", Config::global());
110
111 if Config::global().dry_run() {
112 log::warn!("Running in dry-run mode. No writes/changes will be made");
113 }
114
115 Ok(())
116}
117
118fn config_styles() -> Styles {
120 Styles::styled()
121 .header(AnsiColor::Red.on_default() | Effects::BOLD)
122 .usage(AnsiColor::Yellow.on_default() | Effects::BOLD)
123 .literal(AnsiColor::Green.on_default() | Effects::BOLD)
124 .placeholder(AnsiColor::Blue.on_default())
125}
126
127fn generate_completion_script(shell: clap_complete::Shell) {
129 log::info!("Generating completion script for {shell:?}");
130 clap_complete::generate(
131 shell,
132 &mut <Config as clap::CommandFactory>::command(),
133 "ci-manager",
134 &mut std::io::stdout(),
135 );
136}