1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//! Provides the directory of the executable.

use std::{env, io, path};

/// Returns the cargo manifest directory when running the executable with cargo or the directory in
/// which the executable resides otherwise, traversing symlinks if necessary.
///
/// The algorithm used is:
///
/// * If the `CARGO_MANIFEST_DIR` environment variable is defined it is used as application root.
///   This simplifies running development projects through `cargo run`.
///   See the [cargo reference documentation][cargo-ref] for more details.
/// * If the executable name can be found using [`std::env::current_exe`], resolve all symlinks and
///   use the directory it resides in as application root.
///
/// If none of the above works, an error is returned.
///
/// [cargo-ref]: https://doc.rust-lang.org/cargo/reference/environment-variables.html
/// [`std::env::current_exe`]: https://doc.rust-lang.org/std/env/fn.current_exe.html
pub fn application_root_dir() -> Result<path::PathBuf, io::Error> {
    if let Some(manifest_dir) = env::var_os("CARGO_MANIFEST_DIR") {
        return Ok(path::PathBuf::from(manifest_dir));
    }

    let mut exe = env::current_exe()?.canonicalize()?;

    // Modify in-place to avoid an extra copy.
    if exe.pop() {
        return Ok(exe);
    }

    Err(io::Error::new(
        io::ErrorKind::Other,
        "Failed to find an application root",
    ))
}

/// Same as `application_root_dir`, but extends the root directory with the given path.
pub fn application_dir<P>(path: P) -> Result<path::PathBuf, io::Error>
where
    P: AsRef<path::Path>,
{
    Ok(application_root_dir()?.join(path))
}