use clap::Parser;
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
mod actions;
mod cache;
mod cli;
mod compare;
mod config;
mod error;
mod hooks;
mod providers;
mod rules;
mod scanner;
mod utils;
use config::get_env_verbosity;
use error::RepoLensError;
use cli::exit_codes;
use cli::{Cli, Commands};
#[tokio::main]
async fn main() -> Result<(), RepoLensError> {
let cli = match Cli::try_parse() {
Ok(cli) => cli,
Err(err) => {
let exit_code = match err.kind() {
clap::error::ErrorKind::DisplayHelp
| clap::error::ErrorKind::DisplayVersion
| clap::error::ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => {
exit_codes::SUCCESS
}
_ => exit_codes::INVALID_ARGS,
};
let _ = err.print();
std::process::exit(exit_code);
}
};
let verbosity = if cli.verbose > 0 {
cli.verbose
} else {
get_env_verbosity().unwrap_or(0)
};
setup_logging(verbosity);
if let Some(ref directory) = cli.directory {
if !directory.exists() {
eprintln!("Error: Directory '{}' does not exist", directory.display());
std::process::exit(exit_codes::ERROR);
}
if let Err(e) = std::env::set_current_dir(directory) {
eprintln!(
"Error: Cannot access directory '{}': {}",
directory.display(),
e
);
std::process::exit(exit_codes::ERROR);
}
}
let result = match cli.command {
Commands::Init(args) => cli::commands::init::execute(args).await,
Commands::Plan(mut args) => {
args.verbose = verbosity;
cli::commands::plan::execute(args).await
}
Commands::Apply(args) => cli::commands::apply::execute(args).await,
Commands::Report(mut args) => {
args.verbose = verbosity;
cli::commands::report::execute(args).await
}
Commands::Schema(args) => cli::commands::schema::execute(args).await,
Commands::Compare(args) => cli::commands::compare::execute(args).await,
Commands::InstallHooks(args) => cli::commands::install_hooks::execute(args).await,
Commands::GenerateMan(args) => cli::commands::generate_man::execute(args).await,
Commands::Completions(args) => {
cli::commands::completions::execute(args.shell, std::io::stdout())
.map(|_| exit_codes::SUCCESS)
.map_err(|e| {
RepoLensError::Config(error::ConfigError::Serialize {
message: format!("Failed to generate shell completions: {}", e),
})
})
}
};
match result {
Ok(exit_code) => std::process::exit(exit_code),
Err(e) => {
eprint!("{}", e.display_formatted());
std::process::exit(exit_codes::ERROR);
}
}
}
fn setup_logging(verbosity: u8) {
let filter = match verbosity {
0 => "warn",
1 => "info",
2 => "debug",
_ => "trace",
};
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(filter)))
.init();
}