Skip to main content

romm_cli/commands/
mod.rs

1//! Top-level CLI command handling.
2//!
3//! The `Cli` type (derived from `clap`) describes the public command-line
4//! interface. Each subcommand lives in its own module and is free to use
5//! `RommClient` directly. The TUI is just another subcommand.
6
7use clap::{Parser, Subcommand};
8
9use crate::client::RommClient;
10use crate::config::Config;
11use crate::error::RommError;
12
13pub mod api;
14pub mod auth;
15pub mod cache;
16pub mod completions;
17pub mod download;
18pub mod init;
19pub mod library_scan;
20pub mod platforms;
21pub mod print;
22pub mod roms;
23pub mod scan;
24pub mod sync;
25pub mod update;
26
27/// Defines how a command should format its output for the user.
28#[derive(Clone, Copy, Debug)]
29pub enum OutputFormat {
30    /// Human-readable text format, often with tables and aligned columns.
31    Text,
32    /// Machine-friendly JSON format, useful for scripting and integration.
33    Json,
34}
35
36impl OutputFormat {
37    /// Resolves the effective output format based on global and command-specific flags.
38    ///
39    /// If either the global `--json` flag or a local `--json` flag is set,
40    /// this returns [`OutputFormat::Json`].
41    pub fn from_flags(global_json: bool, local_json: bool) -> Self {
42        if global_json || local_json {
43            OutputFormat::Json
44        } else {
45            OutputFormat::Text
46        }
47    }
48}
49
50/// Top-level CLI entrypoint for `romm-cli`.
51///
52/// This structure defines the global flags and available subcommands
53/// for the `romm-cli` binary.
54#[derive(Parser, Debug)]
55#[command(
56    name = "romm-cli",
57    version,
58    about = "Rust CLI and TUI for the ROMM API",
59    infer_subcommands = true,
60    arg_required_else_help = true
61)]
62pub struct Cli {
63    /// Increase output verbosity (logs requests to stderr).
64    #[arg(short, long, global = true)]
65    pub verbose: bool,
66
67    /// Output JSON instead of human-readable text where supported.
68    #[arg(long, global = true)]
69    pub json: bool,
70
71    /// The subcommand to execute.
72    #[command(subcommand)]
73    pub command: Commands,
74}
75
76/// All top-level commands supported by the CLI.
77#[derive(Subcommand, Debug)]
78pub enum Commands {
79    /// Create or update user configuration.
80    #[command(visible_alias = "setup")]
81    Init(init::InitCommand),
82    /// Launch the interactive Terminal User Interface (TUI).
83    #[cfg(feature = "tui")]
84    Tui {
85        /// Force show a fake update prompt for UI testing.
86        #[arg(long)]
87        mock_update: bool,
88    },
89    /// Launch the interactive TUI (stub for disabled feature).
90    #[cfg(not(feature = "tui"))]
91    Tui {
92        #[arg(long)]
93        mock_update: bool,
94    },
95    /// Low-level access to any RomM API endpoint.
96    #[command(visible_alias = "call")]
97    Api(api::ApiCommand),
98    /// Manage gaming platforms.
99    #[command(visible_aliases = ["platform", "p", "plats"])]
100    Platforms(platforms::PlatformsCommand),
101    /// Manage ROM files and metadata.
102    #[command(visible_aliases = ["rom", "r"])]
103    Roms(Box<roms::RomsCommand>),
104    /// Trigger a library scan on the RomM server.
105    Scan(scan::ScanCommand),
106    /// Save-sync workflows (device registration, planning, and execution).
107    Sync(sync::SyncCommand),
108    /// Download a ROM or related extras from the server.
109    #[command(visible_aliases = ["dl", "get"])]
110    Download(download::DownloadCommand),
111    /// Manage the local persistent cache.
112    Cache(cache::CacheCommand),
113    /// Manage authentication credentials.
114    Auth(auth::AuthCommand),
115    /// Check for and install application updates.
116    Update,
117    /// Generate shell completion scripts.
118    Completions(completions::CompletionsCommand),
119}
120
121/// Main entrypoint for running a CLI command.
122///
123/// This function initializes the [`RommClient`] and dispatches the
124/// chosen command to its respective handler.
125pub async fn run(cli: Cli, config: Config) -> Result<(), RommError> {
126    let client = RommClient::new(&config, cli.verbose)?;
127
128    match cli.command {
129        Commands::Completions(_) => Err(RommError::Other(
130            "internal error: completions must be handled in main".into(),
131        )),
132        Commands::Init(_) => Err(RommError::Other(
133            "internal error: init must be handled before load_config".into(),
134        )),
135        #[cfg(feature = "tui")]
136        Commands::Tui { .. } => Err(RommError::Other(
137            "internal error: TUI must be started via run_interactive from main".into(),
138        )),
139        #[cfg(not(feature = "tui"))]
140        Commands::Tui { .. } => Err(RommError::Other("this feature requires the tui".into())),
141        command => crate::frontend::cli::run(command, &client, cli.json).await,
142    }
143}