ha_utils/
cmd.rs

1use std::{
2    io::{Error, ErrorKind},
3    path::{Path, PathBuf},
4    process::{Command, Output},
5};
6
7use which::which;
8
9/// Returns output to give command
10///
11/// It takes in the command/binary to execute, optional flags and the path
12/// to execute it in.
13///
14/// It will only execute if the provided `cmd` is found on host and `cwd` exists
15/// as a directory.
16///
17/// # Arguments
18///
19/// * `cmd` - The binary to execute.
20/// * `cwd` - The directory to execute in.
21///
22/// # Examples
23/// ```rust
24/// exec("hyprctl workspaces", Path::new("/home/user/repo"));
25/// ```
26/// You can use it with `get_pwd()` to avoid passing a path.
27///
28/// ```rust
29/// exec("hyprctl workspaces", None);
30/// ```
31///
32pub fn exec(cmd: &str, cwd: &Path) -> Result<Output, Error> {
33    // Check if binary for command exists
34    match which(cmd.split(' ').next().unwrap()) {
35        Ok(_) => (),
36        Err(_) => {
37            return Err(Error::new(
38                ErrorKind::NotFound,
39                format!("Could not find specified command: {}", cmd),
40            ))
41        }
42    }
43    // Check if path exists
44    if !cwd.exists() {
45        return Err(Error::new(ErrorKind::Other, "Specified path is invalid!"));
46    }
47    // path is not a directory
48    if !cwd.is_dir() {
49        return Err(Error::new(
50            ErrorKind::Other,
51            "Specified path is not a directory",
52        ));
53    }
54    // Now execute the command
55    if cfg!(target_os = "windows") {
56        return Command::new("cmd")
57            .current_dir(&cwd.as_os_str())
58            .args(["/C", cmd])
59            .output();
60    } else {
61        return Command::new("sh")
62            .current_dir(&cwd.as_os_str())
63            .arg("-c")
64            .arg(cmd)
65            .output();
66    };
67}
68
69/// Returns a Pathbuf of current working dir or the dir if provided.
70///
71/// It's to be used with `exec()`
72///
73/// ## Example
74///
75/// ```rust
76/// get_pwd(None);
77/// ```
78pub fn get_pwd(dir: Option<&Path>) -> PathBuf {
79    let pwd = match std::env::current_dir() {
80        Ok(v) => PathBuf::from(v),
81        Err(err) => panic!("Couldn't find current dir: {}", err),
82    };
83
84    return match dir {
85        Some(v) => v.to_path_buf(),
86        None => pwd,
87    };
88}
89
90#[cfg(test)]
91mod tests {
92    use std::path::Path;
93
94    use super::exec;
95
96    #[test]
97    fn test_exec_valid() {
98        let cmd = "echo";
99        let cwd = Path::new("/tmp");
100        let result = exec(cmd, cwd);
101        assert!(result.is_ok());
102        let output = result.unwrap();
103        assert!(output.status.success());
104    }
105
106    #[test]
107    #[should_panic]
108    fn test_exec_cmd_invalid() {
109        let cmd = "invalid_command";
110        let cwd = Path::new("/tmp");
111        exec(cmd, cwd).unwrap();
112    }
113
114    #[test]
115    #[should_panic]
116    fn test_exec_cwd_invalid() {
117        let cmd = "ls";
118        let cwd = Path::new("/dir/that/does/not/exist");
119        exec(cmd, cwd).unwrap();
120    }
121}