mod backup;
mod database;
mod export;
mod progress;
mod source;
mod types;
mod util;
mod web;
use crate::util::{DEFAULT_CSV_FILE, DEFAULT_DB_FILE};
use anyhow::Result;
use clap::{Parser, Subcommand};
use env_logger::Env;
use export::export_csv;
use log::{debug, error, info, LevelFilter};
use std::io::Write;
use util::detect_history_files;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
#[clap(short, long, env("OH_DB_FILE"), default_value(&**DEFAULT_DB_FILE))]
db_file: String,
#[clap(short, long)]
verbose: bool,
#[clap(subcommand)]
command: Command,
}
#[derive(Subcommand, Debug)]
enum Command {
Backup(Backup),
Serve(Serve),
Show,
Export(Export),
}
#[derive(Parser, Debug)]
struct Backup {
#[clap(short('f'), long, required(false))]
history_files: Vec<String>,
#[clap(short('d'), long)]
disable_detect: bool,
#[clap(short('D'), long)]
dry_run: bool,
}
#[derive(Parser, Debug)]
struct Serve {
#[clap(short, long, default_value("127.0.0.1:9960"))]
addr: String,
}
#[derive(Parser, Debug)]
struct Export {
#[clap(short, long, env("OH_EXPORT_CSV_FILE"), default_value(&**DEFAULT_CSV_FILE))]
csv_file: String,
}
const PKG_NAME: &str = env!("CARGO_PKG_NAME");
fn main() {
let cli = Cli::parse();
let mut builder =
env_logger::Builder::from_env(Env::default().default_filter_or(format!("{PKG_NAME}=info")));
if cli.verbose {
builder.filter(Some(PKG_NAME), LevelFilter::Debug);
};
builder
.format(|buf, record| {
writeln!(
buf,
"{} {} [{}:{}] {}",
chrono::Local::now().format("%Y-%m-%dT%H:%M:%S.%3f"),
buf.default_styled_level(record.level()),
record.file().unwrap_or("unknown"),
record.line().unwrap_or(0),
record.args()
)
})
.init();
debug!("args:{cli:?}");
if let Err(e) = run(cli) {
error!("Run failed, err:{:?}", e);
}
}
fn show(db_file: String) -> Result<()> {
info!("Local database:{}", db_file);
let mut cnt = 0;
for f in detect_history_files() {
cnt += 1;
info!("found:{}", f);
}
info!("Total:{cnt}");
Ok(())
}
fn run(cli: Cli) -> Result<()> {
match cli.command {
Command::Show => show(cli.db_file),
Command::Export(Export { csv_file }) => export_csv(csv_file, cli.db_file),
Command::Serve(Serve { addr }) => web::serve(addr, cli.db_file),
Command::Backup(Backup {
history_files,
disable_detect,
dry_run,
}) => {
let mut files = if disable_detect {
Vec::new()
} else {
detect_history_files()
};
files.extend(history_files);
backup::backup(files, cli.db_file, dry_run)
}
}
}