eureka_manager_cli/
lib.rs

1pub mod commands;
2
3use duration_string::DurationString;
4use fern::colors::ColoredLevelConfig;
5use log::{LevelFilter, Log};
6use std::{path::PathBuf, time::SystemTime};
7
8use clap::{Args, Parser};
9use commands::Commands;
10use eureka_mmanager::prelude::DirsOptionsCore;
11
12#[derive(Debug, Args, Clone)]
13pub struct DirsOptionsArgs {
14    /// data directory path
15    ///
16    /// Default: "output"
17    #[arg(long)]
18    pub data_dir: Option<PathBuf>,
19    /// chapter directory relative to `data_dir` (you can put an absolute path if you wanted to)
20    #[arg(long)]
21    pub chapters: Option<PathBuf>,
22    /// manga directory relative to `data_dir` (you can put an absolute path if you wanted to)
23    #[arg(long)]
24    pub mangas: Option<PathBuf>,
25    /// covers directory relative to `data_dir` (you can put an absolute path if you wanted to)
26    #[arg(long)]
27    pub covers: Option<PathBuf>,
28}
29
30impl From<DirsOptionsArgs> for DirsOptionsCore {
31    fn from(value: DirsOptionsArgs) -> Self {
32        let mut options =
33            DirsOptionsCore::new_from_data_dir(value.data_dir.unwrap_or(From::from("output")));
34        if let Some(chapters) = value.chapters {
35            options.chapters = options.data_dir_add(chapters);
36        }
37        if let Some(mangas) = value.mangas {
38            options.mangas = options.data_dir_add(mangas);
39        }
40        if let Some(covers) = value.covers {
41            options.covers = options.data_dir_add(covers);
42        }
43        options
44    }
45}
46
47#[derive(Debug, Parser)]
48#[command(version, about, long_about = None, propagate_version = true)]
49pub struct Cli {
50    /// Verbose
51    #[arg(short, long)]
52    verbose: bool,
53    #[arg(long)]
54    pub request_timeout: Option<DurationString>,
55    #[command(flatten)]
56    pub options: DirsOptionsArgs,
57    #[command(subcommand)]
58    pub commands: Commands,
59}
60
61impl Cli {
62    pub fn setup_logger(&self) -> (LevelFilter, Box<dyn Log>) {
63        let colors = ColoredLevelConfig::new();
64        let (level, log) = fern::Dispatch::new()
65            .format(move |out, message, record| {
66                out.finish(format_args!(
67                    "[{} {} {}] {}",
68                    humantime::format_rfc3339_seconds(SystemTime::now()),
69                    colors.color(record.level()),
70                    record.target(),
71                    message
72                ));
73            })
74            .level(if self.verbose {
75                LevelFilter::max()
76            } else {
77                LevelFilter::Error
78            })
79            .chain(std::io::stdout())
80            .into_log();
81        (level, log)
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use clap::CommandFactory;
88
89    use crate::Cli;
90    #[test]
91    fn verify_app() {
92        Cli::command().debug_assert();
93    }
94}