rsup_utils/
env.rs

1use std::process::Command;
2
3use serde_derive::{Deserialize, Serialize};
4
5/// 环境变量
6/// 包括名称、版本、安装路径
7#[derive(Deserialize, Serialize, Clone)]
8pub struct Env {
9    /// 命令名称
10    pub name: String,
11    /// 命令版本
12    pub version: String,
13    /// 命令路径
14    pub path: String,
15    /// 命令是否是批处理操作
16    pub is_cmd: bool,
17}
18
19/// 定义了当前需要使用的系统环境变量
20///
21/// 包括node、npm、pnpm、yarn
22///
23#[derive(Deserialize, Serialize)]
24pub struct EnvVec {
25    /// node
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub node: Option<Env>,
28    /// npm
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub npm: Option<Env>,
31    /// pnpm
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub pnpm: Option<Env>,
34    /// yarn
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub yarn: Option<Env>,
37}
38
39impl Env {
40    /// 创建一个环境变量
41    ///
42    /// # Arguments
43    /// * name 命令名称
44    ///
45    /// # Returns
46    /// * `Option<Env>`
47    ///
48    ///     如果命令不存在,返回`None`
49    ///
50    ///     如果命令存在,返回`Some(Env)`
51    ///
52    ///
53    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
77///
78/// 获取命令信息
79///
80/// # Arguments
81/// * command 命令名称
82///
83/// # Returns
84/// * `Env`
85///
86///     返回命令信息
87///
88pub fn get_command_info(mut command: Env) -> Env {
89    let which_cmd = if cfg!(windows) { "where" } else { "which" };
90    // 路径
91    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}