arachnid_cli/cli/
cli.rs

1/*
2    Appellation: cli <module>
3    Created At: 2026.01.10:15:58:56
4    Contrib: @FL03
5*/
6use super::cmd::Command;
7use crate::Context;
8
9/// The root command line interface structure
10#[derive(
11    Clone,
12    Debug,
13    Default,
14    Eq,
15    Hash,
16    Ord,
17    PartialEq,
18    PartialOrd,
19    clap::Parser,
20    serde::Deserialize,
21    serde::Serialize,
22)]
23#[clap(about, author, long_about = None, version)]
24#[command(arg_required_else_help(true), allow_missing_positional(true))]
25pub struct Cli {
26    #[clap(subcommand)]
27    pub command: Option<Command>,
28    #[clap(long, short = 'C', default_value_t = String::from("Puzzled.toml"))]
29    pub config: String,
30    #[clap(action = clap::ArgAction::Count, long, short)]
31    pub release: u8,
32    #[arg(action = clap::ArgAction::Count, long, short)]
33    pub update: u8,
34    #[arg(action = clap::ArgAction::Count, long, short)]
35    pub verbose: u8,
36}
37
38impl Cli {
39    #[tracing::instrument(target = "cli")]
40    /// parse a new instance of the command line arguments
41    pub fn parse() -> Self {
42        tracing::debug! { "Parsing command line arguments..." }
43        <Self as clap::Parser>::parse()
44    }
45    /// returns a reference to the optional command
46    pub fn command(&self) -> &Option<Command> {
47        &self.command
48    }
49    /// returns the `release` flag
50    pub const fn release(&self) -> u8 {
51        self.release
52    }
53    /// returns the `verbose` flag
54    pub const fn verbose(&self) -> u8 {
55        self.verbose
56    }
57    /// returns a copy of the `update` flag
58    pub const fn update(&self) -> u8 {
59        self.update
60    }
61    /// returns true if the release flag has been toggled at least once
62    pub const fn is_release(&self) -> bool {
63        self.release > 0
64    }
65    /// returns true if the verbose flag has been toggled at least once
66    pub const fn is_verbose(&self) -> bool {
67        self.verbose > 0
68    }
69    /// returns true if the update flag has been toggled at least once
70    pub const fn is_update(&self) -> bool {
71        self.update > 0
72    }
73    /// handle the parsed arguments w.r.t. the given context
74    #[tracing::instrument(skip_all, target = "cli")]
75    pub async fn handle(&self, ctx: &mut Context) -> anyhow::Result<()> {
76        // handle any commands
77        if let Some(cmd) = &self.command {
78            tracing::info! { "Executing command: {:?}", cmd.name() }
79            cmd.handle(ctx).await?;
80        }
81        // handle the flags
82        if self.is_release() {
83            tracing::info!(
84                "Release flag has been toggled {n} times",
85                n = self.release()
86            );
87        }
88        if self.is_verbose() {
89            tracing::info! { "Verbose flag has been toggled {n} times", n = self.verbose() }
90        }
91
92        if self.is_update() {
93            tracing::info! { "Update flag has been toggled {n} times", n = self.update() }
94        }
95        Ok(())
96    }
97}