embedded_runner/
path.rs

1use std::path::PathBuf;
2
3#[derive(Debug, thiserror::Error)]
4pub enum PathError {
5    #[error("Could not execute Cargo to find the project root directory.")]
6    ExecutingCargo(std::io::Error),
7    #[error("Cargo could not locate the project root directory.")]
8    LocatingWorkspaceRoot,
9    #[error("Path to the project root directory is not valid UTF8.")]
10    InvalidPath,
11    #[error("Could not get the current directory.")]
12    CurrentDir,
13}
14
15/// Returns the path to the workspace directory of a Cargo workspace.
16/// Reason for this workaround: https://github.com/rust-lang/cargo/issues/3946
17pub fn get_cargo_root() -> Result<PathBuf, PathError> {
18    let locate_project_output = std::process::Command::new(env!("CARGO"))
19        .arg("locate-project")
20        .arg("--workspace")
21        .arg("--quiet")
22        .arg("--message-format=plain")
23        .current_dir(
24            std::env::var("CARGO_MANIFEST_DIR")
25                .map(PathBuf::from)
26                .or(std::env::current_dir())
27                .map_err(|_| PathError::CurrentDir)?,
28        )
29        .output()
30        .map_err(PathError::ExecutingCargo)?;
31
32    if locate_project_output.status.success() {
33        let workspace_root = PathBuf::from(
34            String::from_utf8(locate_project_output.stdout).map_err(|_| PathError::InvalidPath)?,
35        );
36        Ok(workspace_root
37            .parent()
38            .map(|p| p.to_path_buf())
39            .unwrap_or_default())
40    } else {
41        Err(PathError::LocatingWorkspaceRoot)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use std::path::PathBuf;
48
49    use super::get_cargo_root;
50
51    #[test]
52    fn workspace_root_of_mantra() {
53        let workspace_root = get_cargo_root().unwrap().canonicalize().unwrap();
54        let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
55        let expected_root = PathBuf::from(manifest_dir).canonicalize().unwrap();
56
57        assert_eq!(
58            workspace_root, expected_root,
59            "Returned workspace root is wrong."
60        );
61    }
62}