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