Skip to main content

wowlab/
main.rs

1//! Command-line entry point for workspace data processing and snapshot management.
2
3#[global_allocator]
4static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
5
6use anyhow::Result;
7use clap::{Parser, Subcommand};
8use tracing_subscriber::{EnvFilter, fmt, prelude::*};
9use wowlab_cli::commands;
10use wowlab_common::cli;
11
12#[derive(Parser)]
13#[command(name = "wowlab")]
14#[command(about = "WoW data processing tools")]
15struct Cli {
16    /// Suppress non-essential output.
17    #[arg(long, short, global = true)]
18    quiet: bool,
19
20    #[command(subcommand)]
21    command: Commands,
22}
23
24#[derive(Subcommand)]
25enum Commands {
26    /// Snapshot data processing commands.
27    Snapshot {
28        #[command(subcommand)]
29        command: commands::snapshot::SnapshotCommand,
30    },
31    /// Interactive migration: detect version, prompt for config, sync.
32    Migrate,
33}
34
35#[tokio::main]
36async fn main() -> Result<()> {
37    let _ = dotenvy::dotenv();
38
39    let cli = Cli::parse();
40
41    let _app = cli::boot(
42        "wowlab",
43        env!("CARGO_PKG_VERSION"),
44        cli.quiet,
45        "WOWLAB_ROOT",
46    );
47
48    tracing_subscriber::registry()
49        .with(fmt::layer().without_time().with_target(false))
50        .with(
51            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info,sqlx=error")),
52        )
53        .init();
54
55    match cli.command {
56        Commands::Snapshot { command } => command.run().await,
57        Commands::Migrate => commands::migrate::run_migrate(cli.quiet).await,
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use clap::{CommandFactory, Parser, error::ErrorKind};
64    use googletest::prelude::*;
65
66    use super::Cli;
67
68    #[gtest]
69    fn command_tree_and_help_contract_are_stable() -> Result<()> {
70        let mut command = Cli::command();
71
72        command.clone().debug_assert();
73
74        let help = command.render_help().to_string();
75
76        verify_that!(
77            help,
78            eq("WoW data processing tools\n\n\
79             Usage: wowlab [OPTIONS] <COMMAND>\n\n\
80             Commands:\n  \
81             snapshot  Snapshot data processing commands\n  \
82             migrate   Interactive migration: detect version, prompt for config, sync\n  \
83             help      Print this message or the help of the given subcommand(s)\n\n\
84             Options:\n  \
85             -q, --quiet  Suppress non-essential output\n  \
86             -h, --help   Print help\n")
87        )?;
88
89        let snapshot = command
90            .get_subcommands()
91            .find(|subcommand| subcommand.get_name() == "snapshot")
92            .or_fail()?;
93        let snapshot_commands = snapshot
94            .get_subcommands()
95            .map(clap::Command::get_name)
96            .collect::<Vec<_>>();
97
98        verify_that!(
99            snapshot_commands,
100            eq(&vec![
101                "sync",
102                "dump-spell",
103                "dump-trait",
104                "dump-assisted",
105                "assisted-rotas",
106                "decode-loadout",
107            ])
108        )?;
109
110        let sync = snapshot
111            .get_subcommands()
112            .find(|subcommand| subcommand.get_name() == "sync")
113            .or_fail()?;
114        let long_options = sync
115            .get_arguments()
116            .filter_map(clap::Arg::get_long)
117            .collect::<Vec<_>>();
118
119        verify_that!(
120            long_options,
121            eq(&vec!["patch", "data-dir", "dry-run", "json-only", "table"])
122        )
123    }
124
125    #[gtest]
126    fn invalid_argument_keeps_clap_exit_code_two() -> Result<()> {
127        let error = Cli::try_parse_from(["wowlab", "snapshot", "sync", "--definitely-invalid"])
128            .err()
129            .or_fail()?;
130
131        verify_that!(error.kind(), eq(ErrorKind::UnknownArgument))?;
132
133        verify_that!(error.exit_code(), eq(2))
134    }
135}