use anyhow::{Context, Result, bail}; use std::env; use std::path::{Path, PathBuf}; use tracing::debug; pub struct Layout { pub base_dir: PathBuf, pub bin_dir: PathBuf, pub tools_dir: PathBuf, pub lua_file: PathBuf, } 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 安装目录布局 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(); debug!("bin_dir目录 {}", bin_dir.display()); let base_dir = bin_dir .parent() .with_context(|| format!("无法获取 bin 目录 [{}] 的父级 root 目录", bin_dir.display()))? .to_path_buf(); debug!("base_dir 目录 {}", base_dir.display()); Self::from_base_dir(base_dir) } }