- 将核心业务逻辑抽离至 lib.rs,精简 main.rs 为纯粹的 CLI 入口 - 将代码按职责拆分为 config、env、runtime、shim 等子模块 - 提高可测试性与代码复用度
92 lines
3.3 KiB
Rust
92 lines
3.3 KiB
Rust
use std::collections::HashMap;
|
||
use std::path::PathBuf;
|
||
use std::process::Command;
|
||
use mlua::{FromLua, Lua, Table, Value};
|
||
|
||
#[derive(Debug, Clone)]
|
||
pub struct ShimConfig {
|
||
pub target_path: PathBuf,
|
||
pub args: Option<Vec<String>>,
|
||
pub envs: Option<HashMap<String, String>>,
|
||
}
|
||
|
||
impl ShimConfig {
|
||
/// 根据配置快速构建准备执行的 Command 对象
|
||
pub fn to_command(&self) -> Command {
|
||
let mut cmd = Command::new(&self.target_path);
|
||
|
||
if let Some(args) = &self.args {
|
||
cmd.args(args);
|
||
}
|
||
|
||
if let Some(envs) = &self.envs {
|
||
for (key, val) in envs {
|
||
// 直接应用环境变量(Lua 端已经处理好字符串拼接或列表合并)
|
||
cmd.env(key, val);
|
||
}
|
||
}
|
||
|
||
cmd
|
||
}
|
||
}
|
||
|
||
/// 实现 FromLua Trait,由 mlua 自动处理 Table 转换
|
||
impl FromLua for ShimConfig {
|
||
fn from_lua(value: Value, _lua: &Lua) -> mlua::Result<Self> {
|
||
match value {
|
||
Value::Table(table) => {
|
||
let path_str: String = table.get("path")?;
|
||
let args: Option<Vec<String>> = table.get("args")?;
|
||
// 解析 env Table
|
||
let mut envs_map = HashMap::new();
|
||
if let Ok(env_table) = table.get::<Table>("env") {
|
||
// 获取当前系统的路径分隔符(Windows 为 ";",Unix 为 ":")
|
||
#[cfg(windows)]
|
||
let sep = ";";
|
||
#[cfg(not(windows))]
|
||
let sep = ":";
|
||
|
||
for pair in env_table.pairs::<String, Value>() {
|
||
let (k, v) = pair?;
|
||
match v {
|
||
// 情况 1: 普通字符串,如 HOME = "C:/path" -> 直接覆盖
|
||
Value::String(s) => {
|
||
envs_map.insert(k, s.to_str()?.to_string());
|
||
}
|
||
// 情况 2: 数组 Table,如 PATH = { bin_dir, get_env("PATH") }
|
||
Value::Table(arr) => {
|
||
let paths: Vec<String> = arr
|
||
// 将 arr 作为序列(数组)处理,每个元素转为 String
|
||
.sequence_values::<String>()
|
||
.filter_map(|r| r.ok())
|
||
.filter(|s| !s.is_empty()) // 过滤空串,防止生成不必要的连续 ;;
|
||
.collect();
|
||
|
||
let combined = paths.join(sep);
|
||
envs_map.insert(k, combined);
|
||
}
|
||
_ => {}
|
||
}
|
||
}
|
||
}
|
||
|
||
let envs = if envs_map.is_empty() {
|
||
None
|
||
} else {
|
||
Some(envs_map)
|
||
};
|
||
|
||
Ok(ShimConfig {
|
||
target_path: PathBuf::from(path_str),
|
||
args,
|
||
envs,
|
||
})
|
||
}
|
||
_ => Err(mlua::Error::FromLuaConversionError {
|
||
from: value.type_name(),
|
||
to: "ShimConfig".into(),
|
||
message: Some("Expected a Lua table".to_string()),
|
||
}),
|
||
}
|
||
}
|
||
} |