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