1use std::process::Command;
2
3use serde_derive::{Deserialize, Serialize};
4
5#[derive(Deserialize, Serialize, Clone)]
8pub struct Env {
9 pub name: String,
11 pub version: String,
13 pub path: String,
15 pub is_cmd: bool,
17}
18
19#[derive(Deserialize, Serialize)]
24pub struct EnvVec {
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub node: Option<Env>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub npm: Option<Env>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub pnpm: Option<Env>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub yarn: Option<Env>,
37}
38
39impl Env {
40 pub fn new(name: &str) -> Option<Self> {
54 let mut env = Env {
55 name: String::from(""),
56 version: String::from(""),
57 path: String::from(""),
58 is_cmd: false,
59 };
60
61 match name {
62 "node" => env.is_cmd = false,
63 _ => env.is_cmd = true,
64 }
65 env.name = name.to_string();
66
67 let env = get_command_info(env);
68
69 if env.path.is_empty() {
70 None
71 } else {
72 Some(env)
73 }
74 }
75}
76
77pub fn get_command_info(mut command: Env) -> Env {
89 let which_cmd = if cfg!(windows) { "where" } else { "which" };
90 let path = Command::new(which_cmd)
92 .arg(&command.name)
93 .output()
94 .ok()
95 .and_then(|output| {
96 if output.status.success() {
97 Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
98 } else {
99 None
100 }
101 });
102
103 let command_sys_cmd = if cfg!(windows) && command.is_cmd {
104 format!("{}.cmd", &command.name)
105 } else {
106 command.name.clone()
107 };
108 command.path = path.unwrap_or_default();
109 let version = Command::new(command_sys_cmd)
110 .arg("-v")
111 .output()
112 .ok()
113 .and_then(|output| {
114 if output.status.success() {
115 Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
116 } else {
117 None
118 }
119 });
120 command.version = version.unwrap_or_default();
121 command
122}