doum_cli/system/
env.rs

1use std::env;
2use std::path::PathBuf;
3
4/// OS 타입
5#[derive(Debug, Clone, PartialEq)]
6pub enum OsType {
7    Windows,
8    Linux,
9    MacOS,
10}
11
12/// 쉘 타입
13#[derive(Debug, Clone, PartialEq)]
14pub enum ShellType {
15    Cmd,
16    PowerShell,
17    Bash,
18    Zsh,
19    Fish,
20    Unknown,
21}
22
23/// 시스템 정보
24#[derive(Debug, Clone)]
25pub struct SystemInfo {
26    pub os: OsType,
27    pub shell: ShellType,
28    pub current_dir: PathBuf,
29    pub username: Option<String>,
30    pub hostname: Option<String>,
31}
32
33/// 현재 시스템 정보 수집
34pub fn get_system_info() -> SystemInfo {
35    SystemInfo {
36        os: detect_os(),
37        shell: detect_shell(),
38        current_dir: env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
39        username: env::var("USERNAME")
40            .or_else(|_| env::var("USER"))
41            .ok(),
42        hostname: env::var("COMPUTERNAME")
43            .or_else(|_| env::var("HOSTNAME"))
44            .ok(),
45    }
46}
47
48/// OS 타입 감지
49pub fn detect_os() -> OsType {
50    #[cfg(target_os = "windows")]
51    return OsType::Windows;
52    
53    #[cfg(target_os = "linux")]
54    return OsType::Linux;
55    
56    #[cfg(target_os = "macos")]
57    return OsType::MacOS;
58    
59    #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
60    return OsType::Linux; // 기본값
61}
62
63/// 현재 쉘 감지
64pub fn detect_shell() -> ShellType {
65    // Windows에서는 ComSpec 환경 변수 확인
66    if cfg!(target_os = "windows") {
67        if let Ok(comspec) = env::var("COMSPEC")
68            && comspec.to_lowercase().contains("cmd.exe") {
69                return ShellType::Cmd;
70            }
71        
72        // PSModulePath가 있으면 PowerShell
73        if env::var("PSModulePath").is_ok() {
74            return ShellType::PowerShell;
75        }
76        
77        return ShellType::Cmd; // Windows 기본값
78    }
79    
80    // Unix 계열에서는 SHELL 환경 변수 확인
81    if let Ok(shell) = env::var("SHELL") {
82        let shell_lower = shell.to_lowercase();
83        
84        if shell_lower.contains("bash") {
85            return ShellType::Bash;
86        } else if shell_lower.contains("zsh") {
87            return ShellType::Zsh;
88        } else if shell_lower.contains("fish") {
89            return ShellType::Fish;
90        }
91    }
92    
93    // 부모 프로세스 이름으로 추가 확인 시도 (간단한 방법)
94    // 실제로는 더 정교한 감지가 필요할 수 있음
95    
96    ShellType::Unknown
97}
98
99impl OsType {
100    /// OS 이름 문자열 반환
101    pub fn as_str(&self) -> &str {
102        match self {
103            OsType::Windows => "Windows",
104            OsType::Linux => "Linux",
105            OsType::MacOS => "macOS",
106        }
107    }
108}
109
110impl ShellType {
111    /// 쉘 이름 문자열 반환
112    pub fn as_str(&self) -> &str {
113        match self {
114            ShellType::Cmd => "cmd.exe",
115            ShellType::PowerShell => "PowerShell",
116            ShellType::Bash => "bash",
117            ShellType::Zsh => "zsh",
118            ShellType::Fish => "fish",
119            ShellType::Unknown => "unknown",
120        }
121    }
122}
123
124impl SystemInfo {
125    /// 시스템 정보를 사람이 읽기 쉬운 형태로 출력
126    pub fn display(&self) -> String {
127        format!(
128            "OS: {}\nShell: {}\nCurrent Dir: {}\nUsername: {}\nHostname: {}",
129            self.os.as_str(),
130            self.shell.as_str(),
131            self.current_dir.display(),
132            self.username.as_deref().unwrap_or("(unknown)"),
133            self.hostname.as_deref().unwrap_or("(unknown)")
134        )
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn test_detect_os() {
144        let os = detect_os();
145        #[cfg(target_os = "windows")]
146        assert_eq!(os, OsType::Windows);
147        #[cfg(target_os = "linux")]
148        assert_eq!(os, OsType::Linux);
149        #[cfg(target_os = "macos")]
150        assert_eq!(os, OsType::MacOS);
151    }
152
153    #[test]
154    fn test_get_system_info() {
155        let info = get_system_info();
156        assert_eq!(info.os, detect_os());
157        assert_eq!(info.shell, detect_shell());
158        assert!(info.current_dir.as_os_str().len() > 0);
159    }
160
161    #[test]
162    fn test_system_info_display() {
163        let info = SystemInfo {
164            os: OsType::Linux,
165            shell: ShellType::Bash,
166            current_dir: PathBuf::from("/home/user"),
167            username: Some("testuser".to_string()),
168            hostname: None,
169        };
170        
171        let display = info.display();
172        assert!(display.contains("OS: Linux"));
173        assert!(display.contains("Username: testuser"));
174        assert!(display.contains("Hostname: (unknown)"));
175    }
176}