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    after_help = "Exit codes: 0 success, 1 general failure, 2 usage, 3 config/auth, 4 API/network.\n\
62                  See README \"Exit codes\" for scripting examples.\n\
63                  JSON output shapes: docs/json-output.md"
64)]
65pub struct Cli {
66    /// Increase output verbosity (logs requests to stderr).
67    #[arg(short, long, global = true)]
68    pub verbose: bool,
69
70    /// Output JSON instead of human-readable text where supported.
71    #[arg(long, global = true)]
72    pub json: bool,
73
74    /// The subcommand to execute.
75    #[command(subcommand)]
76    pub command: Commands,
77}
78
79/// All top-level commands supported by the CLI.
80#[derive(Subcommand, Debug)]
81pub enum Commands {
82    /// Create or update user configuration.
83    #[command(visible_alias = "setup")]
84    Init(init::InitCommand),
85    /// Launch the interactive Terminal User Interface (TUI).
86    #[cfg(feature = "tui")]
87    Tui {
88        /// Force show a fake update prompt for UI testing.
89        #[arg(long)]
90        mock_update: bool,
91    },
92    /// Launch the interactive TUI (stub for disabled feature).
93    #[cfg(not(feature = "tui"))]
94    Tui {
95        #[arg(long)]
96        mock_update: bool,
97    },
98    /// Low-level access to any RomM API endpoint.
99    #[command(visible_alias = "call")]
100    Api(api::ApiCommand),
101    /// Manage gaming platforms.
102    #[command(visible_aliases = ["platform", "p", "plats"])]
103    Platforms(platforms::PlatformsCommand),
104    /// Manage ROM files and metadata.
105    #[command(visible_aliases = ["rom", "r"])]
106    Roms(Box<roms::RomsCommand>),
107    /// Trigger a library scan on the RomM server.
108    Scan(scan::ScanCommand),
109    /// Save-sync workflows (device registration, planning, and execution).
110    Sync(sync::SyncCommand),
111    /// Download a ROM or related extras from the server.
112    #[command(visible_aliases = ["dl", "get"])]
113    Download(download::DownloadCommand),
114    /// Manage the local persistent cache.
115    Cache(cache::CacheCommand),
116    /// Manage authentication credentials.
117    Auth(auth::AuthCommand),
118    /// Check for and install application updates.
119    Update,
120    /// Generate shell completion scripts.
121    Completions(completions::CompletionsCommand),
122}
123
124/// Main entrypoint for running a CLI command.
125///
126/// This function initializes the [`RommClient`] and dispatches the
127/// chosen command to its respective handler.
128pub async fn run(cli: Cli, config: Config) -> Result<(), RommError> {
129    let client = RommClient::new(&config, cli.verbose)?;
130
131    match cli.command {
132        Commands::Completions(_) => Err(RommError::Other(
133            "internal error: completions must be handled in main".into(),
134        )),
135        Commands::Init(_) => Err(RommError::Other(
136            "internal error: init must be handled before load_config".into(),
137        )),
138        #[cfg(feature = "tui")]
139        Commands::Tui { .. } => Err(RommError::Other(
140            "internal error: TUI must be started via run_interactive from main".into(),
141        )),
142        #[cfg(not(feature = "tui"))]
143        Commands::Tui { .. } => Err(RommError::Other("this feature requires the tui".into())),
144        command => crate::frontend::cli::run(command, &client, cli.json, cli.verbose).await,
145    }
146}