knife_util/path.rs
1//! # 智能路径管理模块
2//!
3//! 提供智能的工作目录检测和路径处理功能,支持开发和生产环境的自动切换。
4//!
5//! ## 核心功能
6//! - **环境感知**: 自动检测开发/生产环境
7//! - **智能路径**: 根据环境选择合适的工作目录
8//! - **路径构建**: 基于工作目录构建项目路径
9//!
10//! ## 环境检测逻辑
11//! - **开发环境**: 存在 `CARGO_MANIFEST_DIR` 环境变量
12//! - **生产环境**: 基于可执行文件位置推断工作目录
13
14use crate::error::AppError;
15use std::env;
16use std::path::PathBuf;
17
18/// 获取工作目录路径
19///
20/// 根据运行环境自动选择合适的工作目录:
21///
22/// ## 开发环境
23/// - 使用 `CARGO_MANIFEST_DIR/workspace` 目录
24/// - 测试时使用 `CARGO_MANIFEST_DIR/workspace/test` 目录
25///
26/// ## 生产环境
27/// - 基于可执行文件位置推断工作目录
28/// - 如果在 `bin/` 或 `sbin/` 目录中,使用父目录作为工作目录
29/// - 否则使用可执行文件所在目录
30///
31/// # 示例
32/// ```rust
33/// use knife_util::{get_work_dir, AppError};
34///
35/// fn main() -> Result<(), AppError> {
36/// let work_dir = get_work_dir()?;
37/// println!("工作目录: {:?}", work_dir);
38/// Ok(())
39/// }
40/// ```
41pub fn get_work_dir() -> Result<PathBuf, AppError> {
42 // 开发环境:使用 Cargo 项目目录
43 if is_dev_mode()
44 && let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR")
45 {
46 let manifest_path = PathBuf::from(manifest_dir);
47 if manifest_path.exists() && manifest_path.is_dir() {
48 let workspace_path = if cfg!(test) {
49 manifest_path.join("work").join("test")
50 } else {
51 manifest_path.join("work")
52 };
53 return Ok(workspace_path);
54 }
55 }
56
57 // 生产环境:基于可执行文件位置推断
58 if let Ok(exe_path) = env::current_exe()
59 && let Some(parent) = exe_path.parent()
60 {
61 // 检查是否在 bin 或 sbin 目录中
62 if let Some(parent_name) = parent.file_name()
63 && (parent_name == "bin" || parent_name == "sbin")
64 && let Some(grandparent) = parent.parent()
65 {
66 return Ok(grandparent.to_path_buf());
67 }
68 return Ok(parent.to_path_buf());
69 }
70
71 Err(AppError::new("GET_WORK_DIR_ERROR", "无法获取工作目录"))
72}
73
74/// 检查是否为开发模式
75///
76/// 通过检查 `CARGO_MANIFEST_DIR` 环境变量来判断是否在开发环境中运行。
77///
78/// # 返回值
79/// - `true`: 开发环境(存在 Cargo 项目)
80/// - `false`: 生产环境
81pub fn is_dev_mode() -> bool {
82 env::var("CARGO_MANIFEST_DIR").is_ok()
83}
84
85/// 构建工作路径
86///
87/// 基于工作目录构建完整的项目路径。
88///
89/// # 参数
90/// - `path`: 相对于工作目录的路径字符串
91///
92/// # 示例
93/// ```rust
94/// use knife_util::{build_work_path, AppError};
95///
96/// fn main() -> Result<(), AppError> {
97/// let config_path = build_work_path("config/app.toml")?;
98/// println!("配置文件路径: {:?}", config_path);
99/// Ok(())
100/// }
101/// ```
102pub fn build_work_path(path: &str) -> Result<PathBuf, AppError> {
103 let work_dir = get_work_dir()?;
104 Ok(work_dir.join(path))
105}