From 428da76a816dc78ddb142d87b5fd884dd2479046 Mon Sep 17 00:00:00 2001 From: CNWei Date: Thu, 20 Aug 2026 14:30:14 +0800 Subject: [PATCH] =?UTF-8?q?fix(config):=20=E4=BC=98=E5=8C=96=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 从环境变量解析目录结构 --- Cargo.lock | 331 ----------------------------------------- build.rs | 8 +- shims.lua => mimic.lua | 2 +- src/config.rs | 194 ++++++++++++------------ src/layout.rs | 65 +++++--- src/lib.rs | 3 +- src/runtime.rs | 25 ++-- src/shim.rs | 27 ++-- 8 files changed, 184 insertions(+), 471 deletions(-) delete mode 100644 Cargo.lock rename shims.lua => mimic.lua (98%) diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index baf95a7..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,331 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "autocfg" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" - -[[package]] -name = "bitflags" -version = "2.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" - -[[package]] -name = "bstr" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" -dependencies = [ - "memchr", - "serde_core", -] - -[[package]] -name = "cc" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "either" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" - -[[package]] -name = "find-msvc-tools" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" - -[[package]] -name = "fs-err" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "libc" -version = "0.2.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "lua-src" -version = "550.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c110c2fa33f34e0de05448e1f3eb2e0631e7a69e2d8ae1586cffc9fc9f9949" -dependencies = [ - "cc", -] - -[[package]] -name = "luajit-src" -version = "210.7.2+b925b3e" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920cf654b23d217c550ceea57c32cd2a413ea27b6d47ed77b5ee0cf655adefa6" -dependencies = [ - "cc", - "which", -] - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "mlua" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad72ffa037cf5970c9860674f32f703fda25d86cf217475fe7a79c5f9961bcaa" -dependencies = [ - "bstr", - "either", - "libc", - "mlua-sys", - "num-traits", - "parking_lot", - "rustc-hash", -] - -[[package]] -name = "mlua-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92136787b906d4e55cfe96cd6c62e010bb1a56889d0d6cf83eb016dbad07576b" -dependencies = [ - "cc", - "cfg-if", - "libc", - "lua-src", - "luajit-src", - "pkg-config", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "pkg-config" -version = "0.3.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - -[[package]] -name = "proc-macro2" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rshim" -version = "0.1.0" -dependencies = [ - "fs-err", - "mlua", - "thiserror", - "unicode-bom", - "winapi", -] - -[[package]] -name = "rustc-hash" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde_core" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - -[[package]] -name = "smallvec" -version = "1.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-bom" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "which" -version = "8.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" -dependencies = [ - "libc", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" diff --git a/build.rs b/build.rs index 1905fc7..93f68b0 100644 --- a/build.rs +++ b/build.rs @@ -34,13 +34,13 @@ fn main() { } // 复制文件 - let source = PathBuf::from(&manifest_dir).join("shims.lua"); + let source = PathBuf::from(&manifest_dir).join("mimic.lua"); let destination = output_dir.join("rshim.lua"); if source.exists() { - fs::copy(&source, &destination).expect("Failed to copy shims.lua"); - println!("Copied shims.lua to: {:?}", destination); + fs::copy(&source, &destination).expect("Failed to copy mimic.lua"); + println!("Copied mimic.lua to: {:?}", destination); } else { - panic!("shims.lua not found at: {:?}", source); + panic!("mimic.lua not found at: {:?}", source); } } diff --git a/shims.lua b/mimic.lua similarity index 98% rename from shims.lua rename to mimic.lua index be57aae..64a4b9a 100644 --- a/shims.lua +++ b/mimic.lua @@ -1,4 +1,4 @@ --- shims.lua (总控制台) +-- mimic.lua (总控制台) -- __SHIM_DIR__ 已经在 Rust 中注入完毕,并且是正斜杠格式 (例如 C:/Tools) local base_dir = __SHIM_DIR__ diff --git a/src/config.rs b/src/config.rs index a809083..22444f4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use mlua::{FromLua, Lua, LuaString, Table, Value}; +use mlua::{FromLua, Lua, LuaString, ObjectLike, Table, Value}; use std::collections::HashMap; use std::ffi::OsString; use std::fmt; @@ -35,7 +35,7 @@ fn lua_string_2_os_string(s: LuaString) -> mlua::Result { let (cow, _, had_errors) = encoding_rs::GBK.decode(raw_bytes); if had_errors { return Err(mlua::Error::RuntimeError( - "Path contains invalid/unsupported byte encoding".into(), + "路径包含无效/不支持的字节编码".into(), )); } Ok(OsString::from(cow.as_ref())) @@ -43,58 +43,71 @@ fn lua_string_2_os_string(s: LuaString) -> mlua::Result { } /// 按连续整数下标遍历表的序列部分;存在空洞或非序列键时返回错误,避免静默截断 -fn validate_each_sequence_item( - tbl: &Table, - mut f: impl FnMut(Value) -> mlua::Result<()>, -) -> mlua::Result<()> { - let mut index = 1i64; - loop { - let item: Value = tbl.raw_get(index)?; - if matches!(item, Value::Nil) { - break; - } - f(item)?; - index += 1; - } - // 校验剩余键:只允许已经被遍历的连续整数键 - for pair in tbl.pairs::() { - let (key, _) = pair?; - match key { - Value::Integer(i) if i >= 1 && i < index => {} - _ => { - return Err(conversion_error(format!( - "数组只能包含连续的整数下标 [1..{}],发现非序列键或空洞", - index - 1 - ))); - } - } - } - Ok(()) -} + /// 值分流与上下文分发枚举 #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ValueShunt { +pub enum ValueShunt<'a> { /// 命令行参数元素:仅支持一维基础标量,禁止嵌套 Table Args, /// 环境变量值:支持基础标量及多维嵌套 Table(递归展平) - Env, + Env(&'a str), } -impl Display for ValueShunt { +impl<'a> Display for ValueShunt<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Args => write!(f, "命令行参数 (args)"), - Self::Env => write!(f, "环境变量 (env)"), + Self::Env(name) => write!(f, "环境变量 ({name})"), } } } -impl ValueShunt { - fn expected_types_desc(&self) -> &str { - match self { - Self::Args => "string/number/boolean(不支持嵌套数组)", - Self::Env => "string/number/boolean 或包含这些类型的数组/嵌套数组", - } +impl<'a> ValueShunt<'a> { + fn parse_sequence(&self, tbl: &Table, out: &mut Vec) -> mlua::Result<()> { + self.validate_each_sequence_item(tbl, |item| self.collect_into(item, out)) } + + fn validate_each_sequence_item( + &self, + tbl: &Table, + mut f: impl FnMut(Value) -> mlua::Result<()>, + ) -> mlua::Result<()> { + let mut index = 1i64; + loop { + let item: Value = tbl.raw_get(index)?; + if matches!(item, Value::Nil) { + break; + } + f(item)?; + index += 1; + } + // 校验剩余键:只允许已经被遍历的连续整数键 + for pair in tbl.pairs::() { + let (key, _) = pair?; + match key { + Value::Integer(i) if i >= 1 && i < index => {} + Value::Integer(_) => { + return Err(conversion_error(format!( + "{} 第 {} 个元素为 nil 或不存在(请检查是否漏写引号或变量未定义)", + self, index + ))); + } + _ => { + // let label = match self { + // ValueShunt::Args => "命令行参数 (args)".to_string(), + // ValueShunt::Env(n) => format!("环境变量 [{n}]"), + // }; + return Err(conversion_error(format!( + "{} 必须是纯列表,不能包含键值对/字典结构", + self + ))); + } + } + } + Ok(()) + } +} + +impl<'a> ValueShunt<'a> { /// 递归/标量收集实现 pub fn collect_into(&self, value: Value, out: &mut Vec) -> mlua::Result<()> { match value { @@ -110,15 +123,32 @@ impl ValueShunt { out.push(OsString::from(b.to_string())); } // 嵌套 Table 仅在 EnvValue 下允许递归展开(支持 get_env("PATH") 等返回的子表) - Value::Table(tbl) if *self == Self::Env => { - validate_each_sequence_item(&tbl, |item| self.collect_into(item, out))?; + // Value::Table(tbl) if *self == Self::Env(_) => { + // self.validate_each_sequence_item(&tbl, |item| self.collect_into(item, out))?; + // } + Value::Table(tbl) => { + match self { + Self::Args => { + return Err(conversion_error(format!( + "{} 不支持 {} 类型, 仅支持 string/number/boolean", + self, + tbl.to_string()? + ))); + } + Self::Env(_) => { + self.validate_each_sequence_item(&tbl, |item| { + self.collect_into(item, out) + })?; + } + } + // self.validate_each_sequence_item(&tbl, |item| self.collect_into(item, out))?; } + other => { return Err(conversion_error(format!( - "{} 不支持类型 {}(仅支持 {})", + "{} 不支持 {} 类型, 仅支持 string/number/boolean 或包含这些类型的数组/嵌套数组", self, other.type_name(), - self.expected_types_desc() ))); } } @@ -127,7 +157,19 @@ impl ValueShunt { } /// 校验环境变量名的合法性(Windows 约束:非空、不含 '='、不含 NUL) -fn validate_env_var_name(key: &str) -> mlua::Result<()> { +fn validate_env_var_name(key_val: &Value, val: &Value) -> mlua::Result { + let key = match key_val { + Value::String(s) => s.to_str()?.to_string(), + + _ => { + return Err(conversion_error(format!( + r#"env 配置解析失败:值: {} (类型: {}) 无效的键值! + 示例 HOME="/home" 或 PATH = {{ "C:/tools/", "D:/Windows"}})"#, + val.to_string()?, + val.type_name() + ))); + } + }; if key.is_empty() { return Err(conversion_error("环境变量名不能为空")); } @@ -143,42 +185,11 @@ fn validate_env_var_name(key: &str) -> mlua::Result<()> { key ))); } - Ok(()) + Ok(key) } /// 递归将任意 Lua Value 展开为扁平的字符串片段列表 -fn collect_env_segments(value: Value, out: &mut Vec) -> mlua::Result<()> { - match value { - // 1. 字符串 - Value::String(s) => out.push(lua_string_2_os_string(s)?), - // 2. 整数与浮点数 - Value::Integer(i) => out.push(OsString::from(i.to_string())), - Value::Number(n) => { - tracing::warn!(value = %n, "环境变量中的浮点数将按十进制格式转换为字符串"); - out.push(OsString::from(n.to_string())); - } - // 3. 布尔值 - Value::Boolean(b) => { - tracing::warn!(value = %b, "环境变量中的布尔值将转换为字符串"); - out.push(OsString::from(b.to_string())); - } - // 4. 表/数组:必须是连续整数下标的纯序列,递归解包(支持任意深度的嵌套数组) - Value::Table(tbl) => { - validate_each_sequence_item(&tbl, |item| collect_env_segments(item, out))? - } - // 5. 安全忽 - // 略 nil - Value::Nil => {} - // 6. 无法转为环境变量的非法类型(函数、协程、UserData 等):报错而非静默忽略 - other => { - return Err(conversion_error(format!( - "环境变量值不支持类型 {}(仅支持 string/number/boolean/数组)", - other.type_name() - ))); - } - } - Ok(()) -} +// fn collect_env_segments(value: Value, out: &mut Vec) -> mlua::Result<()>{OK(())} #[derive(Debug, Clone, Default)] pub struct ShimConfig { @@ -243,11 +254,7 @@ impl FromLua for ShimConfig { // 可选字段: args(缺失或 nil 时默认空列表;保留空字符串参数,与提权路径的 "" 语义一致) match table.get::>("args")? { None | Some(Value::Nil) => {} - Some(Value::Table(tbl)) => { - validate_each_sequence_item(&tbl, |item| { - ValueShunt::Args.collect_into(item, &mut args) - })?; - } + Some(Value::Table(tbl)) => ValueShunt::Args.parse_sequence(&tbl, &mut args)?, Some(other) => { return Err(conversion_error(format!( "args 必须是数组列表,实际类型是 {}", @@ -262,12 +269,13 @@ impl FromLua for ShimConfig { match env_table { None | Some(Value::Nil) => {} Some(Value::Table(tbl)) => { - for pair in tbl.pairs::() { + for pair in tbl.pairs::() { let (name, value) = pair?; - validate_env_var_name(&name)?; + let name = validate_env_var_name(&name, &value)?; + println!("==========={name}:{:?}", value); let mut parts = Vec::new(); - ValueShunt::Env.collect_into(value, &mut parts)?; + ValueShunt::Env(&name).collect_into(value, &mut parts)?; // 空数组/空串也显式设置(空值表示清空该变量), // 与“未配置该变量(继承宿主环境)”相区分 @@ -277,7 +285,7 @@ impl FromLua for ShimConfig { name, e )) })?; - println!("环境变量拼接结果:{:?}", joined_os_str); + // println!("环境变量拼接结果:{:?}", joined_os_str); // 检查是否包含非法 NUL 字符 #[cfg(unix)] { @@ -355,14 +363,10 @@ mod tests { target = "C:/tools/git.exe", args = { "--no-pager" }, env = { - PATH = { "C:/tools/git/bin", "C:/Windows",get_env("PATH") }, + PATH = { "C:/tools/git/bin", "C:/Windows", get_env("PATH") }, HOME = "C:/tools/home", CONST = 3, - BOOL = true, - MUT ={ - A=3, - B=true - } + BOOL = true } } "#, @@ -470,7 +474,9 @@ mod tests { #[test] fn rejects_non_string_args_element() { - assert!(parse(r#"return { target = "t.exe", args = { 1 } }"#).is_err()); + // ValueShunt::Args 允许基础标量(数字/布尔)转字符串,仅禁止嵌套表 + let cfg = parse(r#"return { target = "t.exe", args = { 1, true } }"#).unwrap(); + assert_eq!(cfg.args, vec!["1", "true"]); } #[test] diff --git a/src/layout.rs b/src/layout.rs index a54cfeb..c3350f4 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,36 +1,67 @@ use anyhow::{Context, Result, bail}; +use std::env; use std::path::{Path, PathBuf}; - -pub struct ShimLayout { - pub root_dir: PathBuf, +use tracing::debug; +pub struct Layout { + pub base_dir: PathBuf, pub bin_dir: PathBuf, pub tools_dir: PathBuf, + pub lua_file: PathBuf, } -impl ShimLayout { +impl Layout { + /// 自动解析目录布局: + /// 1. 优先使用环境变量 RSHIM_HOME + /// 2. 兜底回退到当前垫片可执行文件所在目录推断 (exe -> bin -> root) + pub fn discover(current_exe: &Path) -> Result { + // 策略 1: 环境变量优先 + if let Ok(home_val) = env::var("MIMIC_HOME") { + let trimmed = home_val.trim(); + if !trimmed.is_empty() { + debug!(home = %trimmed, "检测到 MIMIC_HOME,采用环境变量配置"); + return Self::from_base_dir(PathBuf::from(trimmed)); + } + } + + // 策略 2: 相对路径自动推断兜底 + debug!("未配置 MIMIC_HOME,尝试从当前可执行文件路径推断根目录"); + Self::from_executable(current_exe) + } + + /// 基于确定的根目录构建完整布局 + fn from_base_dir(base_dir: PathBuf) -> Result { + if !base_dir.is_dir() { + bail!("指定的根目录不存在或不是有效目录: [{}]", base_dir.display()); + } + + let bin_dir = base_dir.join("bin"); + let tools_dir = base_dir.join("tools"); + let lua_file = base_dir.join("mimic.lua"); + + Ok(Self { + base_dir, + bin_dir, + tools_dir, + lua_file, + }) + } + /// 从当前可执行文件解析 shim 安装目录布局 - pub fn from_executable(exe_path: impl AsRef) -> Result { - let exe_path = exe_path.as_ref(); + fn from_executable(exe_path: &Path) -> Result { + // let exe_path = exe_path.as_ref(); let bin_dir = exe_path .parent() .with_context(|| format!("无法获取程序 [{}] 的父级 bin 目录", exe_path.display()))? .to_path_buf(); - eprintln!("bin_dir目录 {}", bin_dir.display()); + debug!("bin_dir目录 {}", bin_dir.display()); - let root_dir = bin_dir + let base_dir = bin_dir .parent() .with_context(|| format!("无法获取 bin 目录 [{}] 的父级 root 目录", bin_dir.display()))? .to_path_buf(); - eprintln!("root_dir 目录 {}", root_dir.display()); + debug!("base_dir 目录 {}", base_dir.display()); - let tools_dir = root_dir.join("tools"); - eprintln!("tools_dir 目录 {}", tools_dir.display()); - - Ok(Self { - root_dir, - bin_dir, - tools_dir, - }) + Self::from_base_dir(base_dir) } } diff --git a/src/lib.rs b/src/lib.rs index 2f24eac..75a46fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,9 @@ mod layout; mod logger; mod runtime; mod shim; +mod loader; pub use config::ShimConfig; -pub use layout::ShimLayout; +pub use layout::Layout; pub use runtime::LuaRuntime; pub use shim::Shim; diff --git a/src/runtime.rs b/src/runtime.rs index ac2f52d..398b6c9 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,4 +1,4 @@ -use crate::{ShimConfig, ShimLayout}; +use crate::{ShimConfig, Layout}; use anyhow::{Context, Result, anyhow, bail}; use mlua::{FromLua, Lua, StdLib, Table, Value}; use std::ffi::OsStr; @@ -17,7 +17,7 @@ pub struct LuaRuntime { impl LuaRuntime { /// 初始化限定权限的 Lua 沙箱环境 - pub fn new(layout: &ShimLayout) -> Result { + pub fn new(layout: &Layout) -> Result { // 只加载安全的标准库,剥离 os / io 等风险模块 let lua = Lua::new_with( StdLib::TABLE | StdLib::STRING | StdLib::MATH | StdLib::PACKAGE, @@ -28,12 +28,12 @@ impl LuaRuntime { let globals = lua.globals(); // 统一使用 POSIX 风格路径规范化路径字符串 - let root_dir = normalize_path_for_lua(&layout.root_dir); + let base_dir = normalize_path_for_lua(&layout.base_dir); let tools_dir = normalize_path_for_lua(&layout.tools_dir); // 1. 注入锚点变量 __SHIM_DIR__(shim 安装根目录) globals - .set("__SHIM_DIR__", root_dir.clone()) + .set("__SHIM_DIR__", base_dir.clone()) .context("设置 __SHIM_DIR__ 环境变量失败")?; // 2. 安全暴露 get_env 供配置读取环境变量 @@ -82,14 +82,14 @@ impl LuaRuntime { if let Ok(path) = package.get::("path") { let new_path = format!( "{};{}/?.lua;{}/?/init.lua;{}/?.lua;{}/?/init.lua", - path, root_dir, root_dir, tools_dir, tools_dir + path, base_dir, base_dir, tools_dir, tools_dir ); let _ = package.set("path", new_path); } } // 4. 包装 require:配置模块缺失/加载失败时记录日志并跳过该条目, - // 而不是让整个 shims.lua 解析失败(排查问题时日志可见) + // 而不是让整个 mimic.lua 解析失败(排查问题时日志可见) let original_require: mlua::Function = globals .get("require") .context("获取内置 require 函数失败")?; @@ -145,23 +145,20 @@ impl LuaRuntime { .with_context(|| format!("执行 Lua 配置文件失败: {}", path.display())) } - // /// 将 Lua Value 解析转化为 ShimConfig 数据对象 - // pub fn parse_config(&self, value: Value) -> Result { - // ShimConfig::from_lua(value, &self.lua).map_err(|e| Error::InvalidConfig(e.to_string())) - // } } #[cfg(test)] mod tests { use super::*; - use crate::ShimLayout; + use crate::Layout; - fn test_layout() -> ShimLayout { + fn test_layout() -> Layout { let root = std::env::temp_dir().join("rshim-test-layout"); - ShimLayout { - root_dir: root.clone(), + Layout { + base_dir: root.clone(), bin_dir: root.join("bin"), tools_dir: root.join("tools"), + lua_file: Default::default(), } } diff --git a/src/shim.rs b/src/shim.rs index bf2fbd2..30961d1 100644 --- a/src/shim.rs +++ b/src/shim.rs @@ -1,4 +1,4 @@ -use crate::{LuaRuntime, ShimConfig, ShimLayout}; +use crate::{LuaRuntime, ShimConfig, Layout}; use anyhow::{Context, Result, bail}; use mlua::{Table, Value}; use std::env; @@ -20,10 +20,10 @@ impl Shim { current_exe = %current_exe.display(), "开始加载 Shim 配置" ); + let layout = Layout::discover(¤t_exe)?; - let layout = ShimLayout::from_executable(current_exe)?; debug!( - root_dir = %layout.root_dir.display(), + root_dir = %layout.base_dir.display(), bin_dir = %layout.bin_dir.display(), tools_dir = %layout.tools_dir.display(), "Shim 目录布局解析完成" @@ -36,16 +36,25 @@ impl Shim { fn resolve_config( runtime: &LuaRuntime, - paths: &ShimLayout, + paths: &Layout, target_name: &str, ) -> Result { - // 策略 1: 尝试加载全局配置文件 shims.lua - let global_config = paths.root_dir.join("rshim.lua"); + // 策略 1: 尝试加载全局配置文件 mimic.lua + let global_config = paths.base_dir.join("rshim.lua"); + + // if !global_config.is_file() { + // bail!( + // "未找到主配置文件: [{}],请确保在安装根目录创建 rshim.lua", + // global_config.display() + // ); + // } + + if global_config.is_file() { trace!(path = %global_config.display(), "发现全局配置文件,尝试解析"); let root_table: Table = runtime.eval_script(&global_config)?; - // 检查 shims.lua 中是否存在以 target_name 命名的 Table 节点 + // 检查 mimic.lua 中是否存在以 target_name 命名的 Table 节点 if root_table .contains_key(target_name) .context("检查全局配置失败")? @@ -69,7 +78,7 @@ impl Shim { let target_filename = format!("{}.lua", target_name); let candidates = [ paths.tools_dir.join(&target_filename), - paths.root_dir.join(&target_filename), + paths.base_dir.join(&target_filename), ]; for config_path in &candidates { @@ -84,7 +93,7 @@ impl Shim { // 策略 3: 所有查找失败,抛出错误 warn!(target = %target_name, "未找到任何匹配的配置文件"); bail!( - "未找到关于 '{}' 的配置。请检查 shims.lua 或特定的 {}.lua 文件", + "未找到关于 '{}' 的配置。请检查 mimic.lua 或特定的 {}.lua 文件", target_name, target_name );