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 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    /// Low-level access to any RomM API endpoint.
86    #[command(visible_alias = "call")]
87    Api(api::ApiCommand),
88    /// Manage gaming platforms.
89    #[command(visible_aliases = ["platform", "p", "plats"])]
90    Platforms(platforms::PlatformsCommand),
91    /// Manage ROM files and metadata.
92    #[command(visible_aliases = ["rom", "r"])]
93    Roms(Box<roms::RomsCommand>),
94    /// Trigger a library scan on the RomM server.
95    Scan(scan::ScanCommand),
96    /// Save-sync workflows (device registration, planning, and execution).
97    Sync(sync::SyncCommand),
98    /// Download a ROM or related extras from the server.
99    #[command(visible_aliases = ["dl", "get"])]
100    Download(download::DownloadCommand),
101    /// Manage the local persistent cache.
102    Cache(cache::CacheCommand),
103    /// Manage authentication credentials.
104    Auth(auth::AuthCommand),
105    /// Check for and install application updates.
106    Update,
107    /// Generate shell completion scripts.
108    Completions(completions::CompletionsCommand),
109}
110
111/// Main entrypoint for running a CLI command.
112///
113/// This function initializes the [`RommClient`] and dispatches the
114/// chosen command to its respective handler.
115pub async fn run(cli: Cli, config: Config) -> Result<(), RommError> {
116    let client = RommClient::new(&config, cli.verbose)?;
117
118    match cli.command {
119        Commands::Completions(_) => Err(RommError::Other(
120            "internal error: completions must be handled in main".into(),
121        )),
122        Commands::Init(_) => Err(RommError::Other(
123            "internal error: init must be handled before load_config".into(),
124        )),
125        command => crate::frontend::cli::run(command, &client, cli.json, cli.verbose).await,
126    }
127}