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 /// Folder for the thumbnail cache. Without it thumbnails are off and
35 /// the grid shows icons only. Entries not used for a day are swept.
36 #[arg(long, env = "FILEBROWSER_CACHE")]
37 pub cache: Option<PathBuf>,
38
39 /// Assume the server runs behind a TLS-terminating reverse proxy
40 /// (sets the `Secure` attribute on the session cookie).
41 /// The env form takes `true` or `false`.
42 #[arg(long, env = "FILEBROWSER_HTTPS")]
43 pub https: bool,
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use clap::Parser;
50 use std::path::PathBuf;
51
52 /// `defaults_applied` asserts `!https`, which the env var would flip.
53 static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
54
55 #[test]
56 fn defaults_applied() {
57 let _guard = ENV_LOCK.lock().unwrap();
58 let c = Cli::try_parse_from(["filebrowser-ng", "--root", "/r", "--db", "/d"]).unwrap();
59 assert_eq!(c.root, PathBuf::from("/r"));
60 assert_eq!(c.db, PathBuf::from("/d"));
61 assert_eq!(c.port, 8080);
62 assert_eq!(c.bind, "127.0.0.1");
63 assert_eq!(c.cache, None);
64 assert!(!c.https);
65 }
66
67 #[test]
68 fn flags_override_defaults() {
69 let c = Cli::try_parse_from([
70 "filebrowser-ng",
71 "--root",
72 "/r",
73 "--db",
74 "/d",
75 "--port",
76 "9000",
77 "--bind",
78 "0.0.0.0",
79 "--https",
80 ])
81 .unwrap();
82 assert_eq!(c.port, 9000);
83 assert_eq!(c.bind, "0.0.0.0");
84 assert!(c.https);
85 }
86
87 #[test]
88 fn https_from_env() {
89 // Env-driven flags carry the daemon's whole config: the compose file
90 // has no `command:` and must still be able to turn this on.
91 let _guard = ENV_LOCK.lock().unwrap();
92 // clap accepts only these two literals for a flag read from the env.
93 for (val, want) in [("true", true), ("false", false)] {
94 // SAFETY: the process env is shared; ENV_LOCK serialises every test
95 // that reads or writes it.
96 unsafe { std::env::set_var("FILEBROWSER_HTTPS", val) };
97 let c = Cli::try_parse_from(["filebrowser-ng", "--root", "/r", "--db", "/d"]).unwrap();
98 assert_eq!(c.https, want, "FILEBROWSER_HTTPS={val}");
99 }
100 unsafe { std::env::remove_var("FILEBROWSER_HTTPS") };
101 }
102
103 #[test]
104 fn required_args_enforced() {
105 assert!(Cli::try_parse_from(["filebrowser-ng", "--root", "/r"]).is_err());
106 assert!(Cli::try_parse_from(["filebrowser-ng"]).is_err());
107 }
108}
109