doum_cli/system/
env.rs

1use std::env;
2use std::path::PathBuf;
3use sysinfo::System;
4
5/// Supported operating system
6#[derive(Debug, Clone, PartialEq)]
7pub enum OsType {
8    Windows,
9    Linux,
10    MacOS,
11}
12
13impl OsType {
14    pub fn as_str(&self) -> &str {
15        match self {
16            OsType::Windows => "Windows",
17            OsType::Linux => "Linux",
18            OsType::MacOS => "macOS",
19        }
20    }
21}
22
23/// Supported shell types
24#[derive(Debug, Clone, PartialEq)]
25pub enum ShellType {
26    Cmd,
27    PowerShell,
28    Bash,
29    Zsh,
30    Fish,
31    Unknown,
32}
33
34impl ShellType {
35    pub fn as_str(&self) -> &str {
36        match self {
37            ShellType::Cmd => "cmd.exe",
38            ShellType::PowerShell => "PowerShell",
39            ShellType::Bash => "bash",
40            ShellType::Zsh => "zsh",
41            ShellType::Fish => "fish",
42            ShellType::Unknown => "unknown",
43        }
44    }
45}
46
47/// System information structure
48#[derive(Debug, Clone)]
49pub struct SystemInfo {
50    pub os: OsType,
51    pub shell: ShellType,
52    pub current_dir: PathBuf,
53    pub username: Option<String>,
54    pub hostname: Option<String>,
55}
56
57impl SystemInfo {
58    pub fn display(&self) -> String {
59        format!(
60            "OS: {}\nShell: {}\nCurrent Dir: {}\nUsername: {}\nHostname: {}",
61            self.os.as_str(),
62            self.shell.as_str(),
63            self.current_dir.display(),
64            self.username.as_deref().unwrap_or("(unknown)"),
65            self.hostname.as_deref().unwrap_or("(unknown)")
66        )
67    }
68}
69
70/// Get current system information
71pub fn get_system_info() -> SystemInfo {
72    SystemInfo {
73        os: detect_os(),
74        shell: detect_shell(),
75        current_dir: env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
76        username: env::var("USERNAME").or_else(|_| env::var("USER")).ok(),
77        hostname: env::var("COMPUTERNAME")
78            .or_else(|_| env::var("HOSTNAME"))
79            .ok(),
80    }
81}
82
83/// Detect operating system
84pub fn detect_os() -> OsType {
85    #[cfg(target_os = "windows")]
86    return OsType::Windows;
87
88    #[cfg(target_os = "linux")]
89    return OsType::Linux;
90
91    #[cfg(target_os = "macos")]
92    return OsType::MacOS;
93
94    #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
95    return OsType::Linux; // 기본값
96}
97
98/// Detect shell type
99pub fn detect_shell() -> ShellType {
100    // Try to detect from parent process first
101    if let Some(name) = detect_shell_from_parent() {
102        let name = name.to_lowercase();
103        if name.contains("bash") {
104            return ShellType::Bash;
105        } else if name.contains("zsh") {
106            return ShellType::Zsh;
107        } else if name.contains("fish") {
108            return ShellType::Fish;
109        } else if name.contains("powershell") || name.contains("pwsh") {
110            return ShellType::PowerShell;
111        } else if name.contains("cmd") {
112            return ShellType::Cmd;
113        }
114    }
115
116    // Fallback to environment variable detection
117    if cfg!(target_os = "windows") {
118        // Check COMSPEC on Windows
119        if let Ok(comspec) = env::var("COMSPEC")
120            && comspec.to_lowercase().contains("cmd.exe")
121        {
122            return ShellType::Cmd;
123        }
124
125        // if PSModulePath exists, it's likely PowerShell
126        if env::var("PSModulePath").is_ok() {
127            return ShellType::PowerShell;
128        }
129    } else {
130        // Check SHELL variable on Unix-like systems
131        if let Ok(shell) = env::var("SHELL") {
132            let shell_lower = shell.to_lowercase();
133
134            if shell_lower.contains("bash") {
135                return ShellType::Bash;
136            } else if shell_lower.contains("zsh") {
137                return ShellType::Zsh;
138            } else if shell_lower.contains("fish") {
139                return ShellType::Fish;
140            }
141        }
142    }
143
144    // Default to Unknown if detection fails
145    ShellType::Unknown
146}
147
148/// Detect shell type from parent process
149fn detect_shell_from_parent() -> Option<String> {
150    let mut system = System::new();
151    system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
152
153    let current_pid = sysinfo::Pid::from_u32(std::process::id());
154    let current = system.process(current_pid)?;
155    let parent_pid = current.parent()?;
156
157    let parent = system.process(parent_pid)?;
158    Some(parent.name().to_string_lossy().to_string())
159}