Skip to main content

bhtune_server/
cli.rs

1//! `bhtune-server`'s CLI surface (`server-windows-service`): a `--config` flag plus five
2//! subcommands (`install`/`uninstall`/`start`/`stop`/`status`) that manage this binary's
3//! registration as a platform service.
4//!
5//! Kept deliberately tiny -- unlike `bhtune-cli`, this binary is still meant to be run mostly
6//! unconfigured (env vars / `bhtune.toml` cover everything else, see `crate::run`). `--config`
7//! is the one flag worth adding now: it lets `install` bake an explicit, stable config path
8//! into the service's registered launch command (see `crate::service::service_launch_arguments`),
9//! which matters because a Windows service normally runs under a different account than
10//! whoever ran `install` interactively, so it would otherwise resolve `%APPDATA%` to a
11//! different (system) profile and appear to have "lost" any config/database an operator set
12//! up while testing from their own terminal session -- see
13//! `docs/getting-started/installation.md`'s "Run as a background service" section.
14//!
15//! `ServiceCommand` is parsed identically on every platform (so `--help` output and argument
16//! validation are covered by CI's Windows *and* Linux jobs alike), even though only Windows
17//! can actually act on it -- see `crate::service`'s module doc comment for how the two other
18//! platforms respond instead.
19
20use std::path::PathBuf;
21
22use clap::{Parser, Subcommand};
23
24/// Manage `bhtune-server`'s registration as a platform service.
25#[derive(Subcommand, Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ServiceCommand {
27    /// Register bhtune-server as a Windows service (does not start it).
28    Install,
29    /// Stop (if running) and remove the registered service.
30    Uninstall,
31    /// Start the registered service.
32    Start,
33    /// Request the running service to stop.
34    Stop,
35    /// Print the registered service's current state.
36    Status,
37}
38
39/// The `bhtune-server` binary's command line.
40#[derive(Parser, Debug)]
41#[command(
42    name = "bhtune-server",
43    version,
44    about = "BHTune's HTTP API and embedded web GUI"
45)]
46pub struct Cli {
47    #[command(subcommand)]
48    pub command: Option<ServiceCommand>,
49
50    /// Path to a TOML config file (default: platform-specific, see `bhtune_cli::config`).
51    /// Baked into the registered launch command by `install` -- see this module's doc
52    /// comment.
53    #[arg(long, global = true, value_name = "PATH")]
54    pub config: Option<PathBuf>,
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn no_arguments_parses_to_no_subcommand_and_no_config() {
63        let cli = Cli::parse_from(["bhtune-server"]);
64        assert_eq!(cli.command, None);
65        assert_eq!(cli.config, None);
66    }
67
68    #[test]
69    fn config_flag_parses_without_a_subcommand() {
70        let cli = Cli::parse_from(["bhtune-server", "--config", "/etc/bhtune/bhtune.toml"]);
71        assert_eq!(cli.command, None);
72        assert_eq!(cli.config, Some(PathBuf::from("/etc/bhtune/bhtune.toml")));
73    }
74
75    #[test]
76    fn every_service_subcommand_parses() {
77        for (arg, expected) in [
78            ("install", ServiceCommand::Install),
79            ("uninstall", ServiceCommand::Uninstall),
80            ("start", ServiceCommand::Start),
81            ("stop", ServiceCommand::Stop),
82            ("status", ServiceCommand::Status),
83        ] {
84            let cli = Cli::parse_from(["bhtune-server", arg]);
85            assert_eq!(cli.command, Some(expected));
86        }
87    }
88
89    #[test]
90    fn install_carries_a_config_flag_given_after_the_subcommand() {
91        // `--config` is `global = true`, so clap accepts it either before or after the
92        // subcommand -- `install` (the only caller that reads it, via
93        // `crate::service::service_launch_arguments`) needs the latter to work too.
94        let cli = Cli::parse_from([
95            "bhtune-server",
96            "install",
97            "--config",
98            "C:\\ProgramData\\bhtune\\bhtune.toml",
99        ]);
100        assert_eq!(cli.command, Some(ServiceCommand::Install));
101        assert_eq!(
102            cli.config,
103            Some(PathBuf::from("C:\\ProgramData\\bhtune\\bhtune.toml"))
104        );
105    }
106}