1use crate::error::ScriptResult;
6use crate::sync::CommandBuilder;
7
8pub fn which(name: &str) -> ScriptResult<Option<std::path::PathBuf>> {
14 #[cfg(windows)]
15 {
16 let result = CommandBuilder::new("where")
17 .arg(name)
18 .capture_output()
19 .execute()?;
20
21 if result.success() {
22 let path = result
23 .stdout_str()
24 .lines()
25 .next()
26 .map(std::path::PathBuf::from);
27 Ok(path)
28 } else {
29 Ok(None)
30 }
31 }
32
33 #[cfg(not(windows))]
34 {
35 let result = CommandBuilder::new("which")
36 .arg(name)
37 .capture_output()
38 .execute()?;
39
40 if result.success() {
41 let path = result
42 .stdout_str()
43 .trim()
44 .lines()
45 .next()
46 .map(std::path::PathBuf::from);
47 Ok(path)
48 } else {
49 Ok(None)
50 }
51 }
52}
53
54pub fn command_exists(name: &str) -> ScriptResult<bool> {
64 Ok(which(name)?.is_some())
65}
66
67pub fn default_shell() -> &'static str {
71 #[cfg(windows)]
72 {
73 "cmd"
74 }
75
76 #[cfg(not(windows))]
77 {
78 "sh"
79 }
80}
81
82pub fn shell_exec_flag() -> &'static str {
86 #[cfg(windows)]
87 {
88 "/C"
89 }
90
91 #[cfg(not(windows))]
92 {
93 "-c"
94 }
95}
96
97pub fn eval(command: &str) -> ScriptResult<crate::output::Output> {
103 CommandBuilder::new(default_shell())
104 .arg(shell_exec_flag())
105 .arg(command)
106 .capture_output()
107 .execute()
108}
109
110pub fn get_env(var: &str) -> Option<std::ffi::OsString> {
114 std::env::var(var).ok().map(std::ffi::OsString::from)
115}
116
117pub fn is_windows() -> bool {
119 cfg!(windows)
120}
121
122pub fn is_unix() -> bool {
124 cfg!(unix)
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_default_shell() {
133 let shell = default_shell();
134 assert!(!shell.is_empty());
135 }
136
137 #[test]
138 fn test_shell_exec_flag() {
139 let flag = shell_exec_flag();
140 assert!(!flag.is_empty());
141 }
142
143 #[test]
144 fn test_platform_checks() {
145 let is_win = is_windows();
146 let is_nix = is_unix();
147 assert!(is_win || is_nix);
148 assert!(!(is_win && is_nix));
149 }
150}