use clap::{Arg, ArgAction, Command};
fn build_version_info() -> String {
let mut s = String::new();
s.push_str("quant1x - Rust edition\n");
s.push_str(
"--------------------------------------------------------------------------------\n",
);
s.push_str(&format!(
" Version : {}\n",
env!("CARGO_PKG_VERSION")
));
s.push_str(&format!(
" Author : {}\n",
env!("CARGO_PKG_AUTHORS")
));
s.push_str(
"--------------------------------------------------------------------------------\n",
);
s
}
fn main() {
quant1x::app::logger_set(false, false);
let program_name = std::env::current_exe()
.ok()
.and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
.unwrap_or_else(|| String::from("quant1x"));
let program_version = build_version_info();
let service_sub = Command::new("service")
.about("Manage the service.")
.arg(
Arg::new("action")
.value_parser(["install", "uninstall", "start", "stop", "status", "run"])
.required(true),
)
.arg(Arg::new("pipe").long("pipe").action(ArgAction::SetTrue))
.arg(Arg::new("elevated-out").long("elevated-out").num_args(1))
.arg(Arg::new("elevated-pipe").long("elevated-pipe").num_args(1));
let update_sub = Command::new("update")
.about("Update cached data (base / features)")
.arg(
Arg::new("calendar")
.long("calendar")
.action(ArgAction::SetTrue)
.help("Only update calendar cache"),
)
.arg(
Arg::new("servers")
.long("servers")
.action(ArgAction::SetTrue)
.help("Only detect and update level1 servers cache"),
)
.arg(
Arg::new("all")
.long("all")
.action(ArgAction::SetTrue)
.help("Update everything (default)"),
)
.arg(
Arg::new("base")
.long("base")
.num_args(1..)
.value_name("KEY")
.help("Update base data keys (e.g. xdxr)")
.value_parser(clap::builder::NonEmptyStringValueParser::new()),
)
.arg(
Arg::new("features")
.long("features")
.num_args(1..)
.value_name("KEY")
.help("Update feature datasets (derived data)")
.value_parser(clap::builder::NonEmptyStringValueParser::new()),
);
let program_name_static: &'static str = Box::leak(program_name.into_boxed_str());
let program_version_static: &'static str = Box::leak(program_version.into_boxed_str());
let mut app = Command::new(program_name_static)
.long_about(program_version_static)
.arg(
Arg::new("version")
.long("version")
.action(ArgAction::SetTrue)
.help("Print build version information and exit"),
)
.arg(
Arg::new("verbose")
.long("verbose")
.action(ArgAction::SetTrue)
.help("显示日志信息到终端"),
)
.arg(
Arg::new("debug")
.long("debug")
.action(ArgAction::SetTrue)
.help("打开日志的调试模式"),
)
.subcommand_required(false)
.subcommand(service_sub)
.subcommand(update_sub);
let matches = app.clone().get_matches();
if matches.get_flag("version") {
println!("{}", program_version_static);
return;
}
let verbose = matches.get_flag("verbose");
let debug = matches.get_flag("debug");
if let Err(e) = call_runtime_global_init() {
log::error!("runtime::global_init failed: {}", e);
}
if let Err(e) = call_datasets_init() {
log::error!("datasets::init failed: {}", e);
}
let _ = call_logger_set(verbose, debug);
let _ = call_engine_init();
if let Some((name, subm)) = matches.subcommand() {
if name == "service" {
let action = subm
.get_one::<String>("action")
.map(|s| s.as_str())
.unwrap_or("");
let pipe = subm.get_flag("pipe");
let elevated_out = subm
.get_one::<String>("elevated-out")
.map(|s| s.to_string());
let elevated_pipe = subm
.get_one::<String>("elevated-pipe")
.map(|s| s.to_string());
let code = call_engine_daemon(
action,
pipe,
elevated_out.as_deref(),
elevated_pipe.as_deref(),
);
std::process::exit(code);
}
}
if let Some((name, subm)) = matches.subcommand() {
if name != "service" {
match lib_bridge::try_run_subcommand(name, subm) {
Ok(true) => {
return;
}
Ok(false) => {
log::error!(
"Error: Command '{}' not implemented in Rust library.\n",
name
);
app.print_help().ok();
std::process::exit(1);
}
Err(err) => {
log::error!("Error running subcommand '{}': {}", name, err);
std::process::exit(1);
}
}
}
}
log::error!("Error: No command provided.");
app.print_help().ok();
std::process::exit(1);
}
fn call_runtime_global_init() -> Result<(), String> {
quant1x::global_init();
Ok(())
}
fn call_datasets_init() -> Result<(), String> {
quant1x::datasets_init();
Ok(())
}
fn call_logger_set(verbose: bool, debug: bool) -> Result<(), String> {
quant1x::logger_set(verbose, debug);
Ok(())
}
fn call_engine_init() -> Result<(), String> {
quant1x::engine_init();
Ok(())
}
fn call_engine_daemon(
action: &str,
pipe: bool,
elevated_out: Option<&str>,
elevated_pipe: Option<&str>,
) -> i32 {
quant1x::engine_daemon(action, pipe, elevated_out, elevated_pipe)
}
mod lib_bridge {
use clap::ArgMatches;
use std::error::Error;
pub fn try_run_subcommand(name: &str, matches: &ArgMatches) -> Result<bool, Box<dyn Error>> {
quant1x::try_run_subcommand(name, matches)
}
}