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