#[cfg(feature = "admin")]
mod admin;
mod cart_io;
pub(crate) mod config;
mod run;
mod service;
#[cfg(feature = "vt")]
mod vt;
#[cfg(feature = "admin-gui")]
use crate::gui;
use service::{Install, Installer};
use std::process::ExitCode;
use std::str::FromStr;
use anyhow::{bail, Result};
use clap::{Command, CommandFactory, Parser, Subcommand};
use clap_complete::{generate, Shell};
pub const VERSION: &str = concat!(env!("MDB_VERSION"), " ", env!("MDB_BUILD_DATE"));
#[derive(Parser, Debug)]
#[command(author, about, version = VERSION)]
pub struct Options {
#[clap(subcommand)]
cmd: Option<Subcommands>,
#[clap(flatten)]
pub logger: LogOptions,
}
#[derive(Parser, Clone, Debug, PartialEq)]
pub struct LogOptions {
#[clap(long = "log-filter", env = "MDB_LOG")]
pub log_filter: Option<String>,
#[clap(long, default_value = "stderr")]
pub log_target: LogTarget,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogTarget {
Stdout,
Stderr,
}
impl FromStr for LogTarget {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"stdout" => Ok(Self::Stdout),
"stderr" => Ok(Self::Stderr),
_ => bail!("unknown log target {s:?}"),
}
}
}
impl Options {
pub async fn execute(self) -> Result<ExitCode> {
match self.cmd {
Some(Subcommands::Run(cmd)) => cmd.execute().await,
#[cfg(feature = "admin")]
Some(Subcommands::Admin(cmd)) => cmd.execute().await,
#[cfg(feature = "admin-gui")]
Some(Subcommands::AdminGui(cmd)) => cmd.execute().await,
Some(Subcommands::InstallService(install)) => install.do_install(),
#[cfg(feature = "vt")]
Some(Subcommands::Vt(cmd)) => cmd.execute().await,
Some(Subcommands::Cart(cmd)) => cmd.execute(),
Some(Subcommands::Generate(cmd)) => Ok(cmd.execute()),
None => {
eprintln!("Please run with `--help` for options.");
Ok(ExitCode::FAILURE)
}
}
}
}
#[derive(Subcommand, Debug)]
enum Subcommands {
#[command(visible_alias = "hint")]
Run(run::Run),
#[cfg(feature = "admin")]
Admin(admin::Admin),
#[cfg(feature = "admin-gui")]
AdminGui(gui::AdminGui),
InstallService(Install),
#[cfg(feature = "vt")]
Vt(vt::VtOption),
Cart(cart_io::CartIO),
Generate(Generator),
}
#[derive(Parser, Debug, Clone, PartialEq)]
pub struct Generator {
#[arg(value_enum)]
pub(crate) generator: Shell,
}
impl Generator {
pub fn execute(&self) -> ExitCode {
let mut cmd = Options::command();
eprintln!("Generating completion file for {:?}...", self.generator);
print_completions(self.generator, &mut cmd);
ExitCode::SUCCESS
}
}
pub fn print_completions<G: clap_complete::Generator>(gen: G, cmd: &mut Command) {
generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
}
#[cfg(test)]
mod tests {
use super::Options;
use clap::CommandFactory;
#[test]
fn verify_cli() {
Options::command().debug_assert();
}
}