cli.rs
⎇
Raw
1use std::path::PathBuf;
2
3use clap::Parser;
4
5#[derive(Parser, Debug)]
6#[command(
7 name = "filebrowser-ng",
8 about = "A simple, noob-friendly web file browser",
9 version
10)]
11pub struct Cli {
12 /// Root folder the server has access to (required).
13 /// All user folders and shares are relative to this.
14 #[arg(long)]
15 pub root: PathBuf,
16
17 /// Display name of the root folder in the UI. Defaults to the folder's
18 /// own name, which in a container is the mount point (e.g. "data").
19 #[arg(long, env = "FILEBROWSER_ROOT_NAME")]
20 pub root_name: Option<String>,
21
22 /// Path to the SQLite database file (required).
23 #[arg(long)]
24 pub db: PathBuf,
25
26 /// Port to listen on.
27 #[arg(long, default_value_t = 8080)]
28 pub port: u16,
29
30 /// Address to bind. Use 0.0.0.0 to expose beyond localhost.
31 #[arg(long, default_value = "127.0.0.1")]
32 pub bind: String,
33
34 /// Assume the server runs behind a TLS-terminating reverse proxy
35 /// (sets the `Secure` attribute on the session cookie).
36 /// The env form takes `true` or `false`.
37 #[arg(long, env = "FILEBROWSER_HTTPS")]
38 pub https: bool,
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use clap::Parser;
45 use std::path::PathBuf;
46
47 /// `defaults_applied` asserts `!https`, which the env var would flip.
48 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
49
50 #[test]
51 fn defaults_applied() {
52 let _guard = ENV_LOCK.lock().unwrap();
53 let c = Cli::try_parse_from(["filebrowser-ng", "--root", "/r", "--db", "/d"]).unwrap();
54 assert_eq!(c.root, PathBuf::from("/r"));
55 assert_eq!(c.db, PathBuf::from("/d"));
56 assert_eq!(c.port, 8080);
57 assert_eq!(c.bind, "127.0.0.1");
58 assert!(!c.https);
59 }
60
61 #[test]
62 fn flags_override_defaults() {
63 let c = Cli::try_parse_from([
64 "filebrowser-ng",
65 "--root",
66 "/r",
67 "--db",
68 "/d",
69 "--port",
70 "9000",
71 "--bind",
72 "0.0.0.0",
73 "--https",
74 ])
75 .unwrap();
76 assert_eq!(c.port, 9000);
77 assert_eq!(c.bind, "0.0.0.0");
78 assert!(c.https);
79 }
80
81 #[test]
82 fn https_from_env() {
83 // Env-driven flags carry the daemon's whole config: the compose file
84 // has no `command:` and must still be able to turn this on.
85 let _guard = ENV_LOCK.lock().unwrap();
86 // clap accepts only these two literals for a flag read from the env.
87 for (val, want) in [("true", true), ("false", false)] {
88 // SAFETY: the process env is shared; ENV_LOCK serialises every test
89 // that reads or writes it.
90 unsafe { std::env::set_var("FILEBROWSER_HTTPS", val) };
91 let c = Cli::try_parse_from(["filebrowser-ng", "--root", "/r", "--db", "/d"]).unwrap();
92 assert_eq!(c.https, want, "FILEBROWSER_HTTPS={val}");
93 }
94 unsafe { std::env::remove_var("FILEBROWSER_HTTPS") };
95 }
96
97 #[test]
98 fn required_args_enforced() {
99 assert!(Cli::try_parse_from(["filebrowser-ng", "--root", "/r"]).is_err());
100 assert!(Cli::try_parse_from(["filebrowser-ng"]).is_err());
101 }
102}
103