Skip to main content

mailsis_utils/
exec.rs

1//! Workspace root discovery at runtime.
2//!
3//! The server needs to locate configuration files and TLS certificates
4//! relative to the project root. [`get_crate_root`] resolves this by
5//! walking up from the running executable past the `target/` directory.
6
7use std::{env, error::Error, path::PathBuf};
8
9/// Returns the root directory of the crate, using the current executable path
10/// as reference.
11///
12/// It works by going up the directory tree until it finds a directory that
13/// ends with "target", which is not the case for the root directory.
14pub fn get_crate_root() -> Result<PathBuf, Box<dyn Error>> {
15    let exe_path = env::current_exe().expect("Failed to get executable path");
16    let mut crate_root = exe_path
17        .parent()
18        .ok_or("Failed to get parent directory")?
19        .parent()
20        .ok_or("Failed to get crate root directory")?
21        .to_path_buf();
22
23    loop {
24        let is_final = crate_root.ends_with("target");
25        crate_root = crate_root
26            .parent()
27            .ok_or("Failed to get crate root directory")?
28            .to_path_buf();
29        if is_final {
30            break;
31        }
32    }
33
34    Ok(crate_root)
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn test_get_crate_root_returns_path() {
43        let result = get_crate_root();
44        assert!(result.is_ok());
45        let root = result.unwrap();
46        assert!(root.exists());
47    }
48
49    #[test]
50    fn test_get_crate_root_not_inside_target() {
51        let root = get_crate_root().unwrap();
52        assert!(!root.ends_with("target"));
53    }
54}