use std::path::PathBuf;
use clap::{Parser, ValueEnum};
use lloggs::{LoggingArgs, PreArgs, WorkerGuard};
use miette::{IntoDiagnostic, Result, miette};
use tracing::debug;
#[derive(Debug, Clone, Parser)]
pub struct Args {
#[command(flatten)]
logging: LoggingArgs,
#[arg(long, hide = true)]
pub docs: bool,
pub connstring: Option<String>,
#[arg(long, value_enum, default_value_t = TlsMode::default())]
pub ssl: TlsMode,
#[arg(short = 'W', long)]
pub write: bool,
#[arg(long, default_value = "auto")]
pub theme: bestool_psql::Theme,
#[arg(long, value_name = "PATH", help = help_audit_path())]
pub audit_path: Option<PathBuf>,
}
#[derive(Debug, Default, Clone, Copy, ValueEnum)]
pub enum TlsMode {
Disable,
#[default]
Prefer,
Require,
}
impl TlsMode {
fn as_str(self) -> &'static str {
match self {
TlsMode::Disable => "disable",
TlsMode::Prefer => "prefer",
TlsMode::Require => "require",
}
}
}
fn help_audit_path() -> String {
format!(
"Path to audit database directory (default: {})",
bestool_psql::default_audit_dir()
)
}
fn get_args() -> Result<(Args, WorkerGuard)> {
let log_guard = PreArgs::parse().setup().map_err(|err| miette!("{err}"))?;
debug!("parsing arguments");
let args = Args::parse();
let log_guard = match log_guard {
Some(g) => g,
None => args
.logging
.setup(|v| match v {
0 => "bestool_psql=info",
1 => "info,bestool_psql=debug",
2 => "debug",
3 => "debug,bestool_psql=trace",
_ => "trace",
})
.map_err(|err| miette!("{err}"))?,
};
debug!(?args, "got arguments");
Ok((args, log_guard))
}
#[tokio::main]
async fn main() -> Result<()> {
let (args, _guard) = get_args()?;
if args.docs || args.connstring.as_ref().is_some_and(|c| c == "_docs") {
let markdown = clap_markdown::help_markdown::<Args>();
println!("{}", markdown);
return Ok(());
}
let connstring = args
.connstring
.ok_or_else(|| miette!("database name or connection URL is required"))?;
let theme = args.theme.resolve();
debug!(?theme, "using syntax highlighting theme");
let url = if connstring.contains("://") {
let mut url = url::Url::parse(&connstring).into_diagnostic()?;
if !url.query_pairs().any(|(key, _)| key == "sslmode") {
url.query_pairs_mut()
.append_pair("sslmode", args.ssl.as_str());
}
url.to_string()
} else {
format!(
"postgresql://localhost/{}?sslmode={}",
connstring,
args.ssl.as_str()
)
};
debug!(url, "using connection url");
debug!("creating connection pool");
let pool = bestool_psql::create_pool(&url).await?;
bestool_psql::register_sigint_handler()?;
bestool_psql::run(
pool,
bestool_psql::Config {
theme,
audit_path: args.audit_path,
write: args.write,
use_colours: args.logging.color.enabled(),
..Default::default()
},
)
.await
}