hop_cli/
lib.rs

1pub(crate) mod commands;
2pub(crate) mod config;
3pub(crate) mod state;
4pub(crate) mod store;
5pub(crate) mod utils;
6
7use anyhow::Result;
8use clap::Parser;
9use commands::update::version_notice;
10use commands::{handle_command, Commands};
11use config::{ARCH, PLATFORM, VERSION};
12use state::{State, StateOptions};
13
14#[derive(Debug, Parser)]
15#[clap(
16    name = "hop",
17    about = "🐇 Interact with Hop via command line",
18    version,
19    author
20)]
21pub struct CLI {
22    #[clap(subcommand)]
23    pub commands: Commands,
24
25    #[clap(
26        short,
27        long,
28        help = "Namespace or ID of the project to use",
29        global = true
30    )]
31    pub project: Option<String>,
32
33    #[clap(short = 'D', long, help = "Enable debug mode", global = true)]
34    pub debug: bool,
35}
36
37pub async fn run() -> Result<()> {
38    // create a new CLI instance
39    let cli = CLI::parse();
40
41    // setup panic hook
42    utils::set_hook();
43
44    utils::logs(cli.debug);
45
46    // in the debug mode, print the version and arch for easier debugging
47    log::debug!("Hop-CLI v{VERSION} build for {ARCH}-{PLATFORM}");
48
49    utils::sudo::fix().await?;
50
51    let state = State::new(StateOptions {
52        override_project: std::env::var("PROJECT_ID").ok().or(cli.project),
53        override_token: std::env::var("TOKEN").ok(),
54        debug: cli.debug,
55    })
56    .await?;
57
58    match cli.commands {
59        #[cfg(feature = "update")]
60        Commands::Update(_) => {}
61
62        // do not show the notice if we are in completions mode
63        // since it could break the shell
64        Commands::Completions(_) => {}
65
66        // only show the notice if we are not in debug mode or in CI
67        _ if cfg!(debug_assertions) || state.is_ci => {}
68
69        // async block to spawn the update check in the background :)
70        _ => {
71            let ctx = state.ctx.clone();
72
73            tokio::spawn(async move {
74                if let Err(e) = version_notice(ctx).await {
75                    log::debug!("Failed to check for updates: {e}");
76                }
77            });
78        }
79    };
80
81    if let Err(error) = handle_command(cli.commands, state).await {
82        log::error!("{error}");
83        log::debug!("{error:#?}");
84        std::process::exit(1);
85    }
86
87    utils::clean_term();
88
89    Ok(())
90}
91
92#[cfg(test)]
93mod test {
94    #[test]
95    fn test_cli() {
96        use clap::CommandFactory;
97
98        use super::*;
99
100        CLI::command().debug_assert();
101    }
102}