1use std::env;
2
3use nix::unistd::{geteuid, User};
4
5pub fn platform() -> String {
10 format!("{}-{}", std::env::consts::ARCH, &std::env::consts::OS)
11}
12
13trait UsernameSource {
14 fn env_var(&self, key: &str) -> Option<String>;
15 fn uid_name(&self) -> Option<String>;
16}
17
18struct SystemSource;
19
20impl UsernameSource for SystemSource {
21 fn env_var(&self, key: &str) -> Option<String> {
22 env::var(key).ok()
23 }
24
25 fn uid_name(&self) -> Option<String> {
26 User::from_uid(geteuid())
27 .ok()
28 .and_then(|u| u.map(|u| u.name))
29 }
30}
31
32fn get_username_with<S: UsernameSource>(src: &S) -> String {
33 src.env_var("USER")
34 .or_else(|| src.env_var("LOGNAME"))
35 .or_else(|| src.uid_name())
36 .expect("Couldn't determine username.")
37}
38
39pub fn get_username() -> String {
48 get_username_with(&SystemSource)
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 struct AlwaysNone;
56 impl UsernameSource for AlwaysNone {
57 fn env_var(&self, _: &str) -> Option<String> {
58 None
59 }
60
61 fn uid_name(&self) -> Option<String> {
62 None
63 }
64 }
65
66 #[test]
67 fn test_platform() {
68 #[cfg(target_arch = "x86_64")]
69 #[cfg(target_os = "linux")]
70 assert_eq!(platform(), "x86_64-linux");
71
72 #[cfg(target_arch = "aarch64")]
73 #[cfg(target_os = "linux")]
74 assert_eq!(platform(), "aarch64-linux");
75 }
76
77 #[test]
78 #[should_panic(expected = "Couldn't determine username.")]
79 fn test_fails_when_all_sources_missing() {
80 get_username_with(&AlwaysNone);
81 }
82
83 #[test]
84 fn test_get_username() {
85 let username = get_username();
86 assert!(!username.is_empty());
87 }
88
89 #[test]
90 fn test_get_username_missing_env_vars() {
91 env::remove_var("USER");
92 env::remove_var("LOGNAME");
93
94 let username = get_username();
95 assert!(!username.is_empty());
96 }
97}