mod auth;
mod serve;
use crate::{
commands::{auth::AuthCmd, serve::ServeCmd},
config::RusticServerConfig,
};
use abscissa_core::{
config::Override, tracing::info, Command, Configurable, FrameworkError, Runnable,
};
use clap::builder::{
styling::{AnsiColor, Effects},
Styles,
};
use std::path::PathBuf;
pub const CONFIG_FILE: &str = "rustic_server.toml";
#[derive(clap::Parser, Command, Debug, Runnable)]
pub enum RusticServerCmd {
Auth(AuthCmd),
Serve(ServeCmd),
}
fn styles() -> Styles {
Styles::styled()
.header(AnsiColor::Red.on_default() | Effects::BOLD)
.usage(AnsiColor::Red.on_default() | Effects::BOLD)
.literal(AnsiColor::Blue.on_default() | Effects::BOLD)
.placeholder(AnsiColor::Green.on_default())
}
#[derive(clap::Parser, Command, Debug)]
#[command(author, about, version)]
#[command(author, about, name="rustic-server", styles=styles(), version = env!("CARGO_PKG_VERSION"))]
pub struct EntryPoint {
#[command(subcommand)]
cmd: RusticServerCmd,
#[arg(short, long, global = true, env = "RUSTIC_SERVER_VERBOSE")]
pub verbose: bool,
#[arg(short, long, global = true, env = "RUSTIC_SERVER_CONFIG_PATH")]
pub config: Option<String>,
}
impl Runnable for EntryPoint {
fn run(&self) {
self.cmd.run();
}
}
impl Configurable<RusticServerConfig> for EntryPoint {
fn config_path(&self) -> Option<PathBuf> {
if self.config.is_none() {
info!("No configuration file provided.");
return None;
}
let filename = self
.config
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| CONFIG_FILE.into());
if filename.exists() {
info!("Using configuration file: `{filename:?}`");
Some(filename)
} else {
info!("Provided configuration file not found. Trying default.");
Some(PathBuf::from(CONFIG_FILE))
}
}
fn process_config(
&self,
config: RusticServerConfig,
) -> Result<RusticServerConfig, FrameworkError> {
match &self.cmd {
RusticServerCmd::Serve(cmd) => cmd.override_config(config),
_ => Ok(config),
}
}
}
#[cfg(test)]
mod tests {
use crate::commands::EntryPoint;
use clap::CommandFactory;
#[test]
fn verify_cli() {
EntryPoint::command().debug_assert();
}
}