| //! Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. |
| //! |
| //! This provides the definition of `home_dir` used by Cargo and |
| //! rustup, as well functions to find the correct value of |
| //! `CARGO_HOME` and `RUSTUP_HOME`. |
| //! |
| //! See also the [`dirs`](https://docs.rs/dirs) crate. |
| //! |
| //! _Note that as of 2019/08/06 it appears that cargo uses this crate. And |
| //! rustup has used this crate since 2019/08/21._ |
| //! |
| //! The definition of `home_dir` provided by the standard library is |
| //! incorrect because it considers the `HOME` environment variable on |
| //! Windows. This causes surprising situations where a Rust program |
| //! will behave differently depending on whether it is run under a |
| //! Unix emulation environment like Cygwin or MinGW. Neither Cargo nor |
| //! rustup use the standard libraries definition - they use the |
| //! definition here. |
| //! |
| //! This crate further provides two functions, `cargo_home` and |
| //! `rustup_home`, which are the canonical way to determine the |
| //! location that Cargo and rustup store their data. |
| //! |
| //! See also this [discussion]. |
| //! |
| //! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935 |
| |
| #![doc(html_root_url = "https://docs.rs/home/0.5.3")] |
| #![deny(rust_2018_idioms)] |
| |
| #[cfg(windows)] |
| mod windows; |
| |
| use std::env; |
| use std::io; |
| use std::path::{Path, PathBuf}; |
| |
| /// Returns the path of the current user's home directory if known. |
| /// |
| /// # Unix |
| /// |
| /// Returns the value of the `HOME` environment variable if it is set |
| /// and not equal to the empty string. Otherwise, it tries to determine the |
| /// home directory by invoking the `getpwuid_r` function on the UID of the |
| /// current user. |
| /// |
| /// # Windows |
| /// |
| /// Returns the value of the `USERPROFILE` environment variable if it |
| /// is set and not equal to the empty string. If both do not exist, |
| /// [`GetUserProfileDirectory`][msdn] is used to return the |
| /// appropriate path. |
| /// |
| /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectoryw |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// match home::home_dir() { |
| /// Some(path) => println!("{}", path.display()), |
| /// None => println!("Impossible to get your home dir!"), |
| /// } |
| /// ``` |
| pub fn home_dir() -> Option<PathBuf> { |
| home_dir_inner() |
| } |
| |
| #[cfg(windows)] |
| use windows::home_dir_inner; |
| |
| #[cfg(any(unix, target_os = "redox"))] |
| fn home_dir_inner() -> Option<PathBuf> { |
| #[allow(deprecated)] |
| env::home_dir() |
| } |
| |
| /// Returns the storage directory used by Cargo, often knowns as |
| /// `.cargo` or `CARGO_HOME`. |
| /// |
| /// It returns one of the following values, in this order of |
| /// preference: |
| /// |
| /// - The value of the `CARGO_HOME` environment variable, if it is |
| /// an absolute path. |
| /// - The value of the current working directory joined with the value |
| /// of the `CARGO_HOME` environment variable, if `CARGO_HOME` is a |
| /// relative directory. |
| /// - The `.cargo` directory in the user's home directory, as reported |
| /// by the `home_dir` function. |
| /// |
| /// # Errors |
| /// |
| /// This function fails if it fails to retrieve the current directory, |
| /// or if the home directory cannot be determined. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// match home::cargo_home() { |
| /// Ok(path) => println!("{}", path.display()), |
| /// Err(err) => eprintln!("Cannot get your cargo home dir: {:?}", err), |
| /// } |
| /// ``` |
| pub fn cargo_home() -> io::Result<PathBuf> { |
| let cwd = env::current_dir()?; |
| cargo_home_with_cwd(&cwd) |
| } |
| |
| /// Returns the storage directory used by Cargo within `cwd`. |
| /// For more details, see [`cargo_home`](fn.cargo_home.html). |
| pub fn cargo_home_with_cwd(cwd: &Path) -> io::Result<PathBuf> { |
| match env::var_os("CARGO_HOME").filter(|h| !h.is_empty()) { |
| Some(home) => { |
| let home = PathBuf::from(home); |
| if home.is_absolute() { |
| Ok(home) |
| } else { |
| Ok(cwd.join(&home)) |
| } |
| } |
| _ => home_dir() |
| .map(|p| p.join(".cargo")) |
| .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "could not find cargo home dir")), |
| } |
| } |
| |
| /// Returns the storage directory used by rustup, often knowns as |
| /// `.rustup` or `RUSTUP_HOME`. |
| /// |
| /// It returns one of the following values, in this order of |
| /// preference: |
| /// |
| /// - The value of the `RUSTUP_HOME` environment variable, if it is |
| /// an absolute path. |
| /// - The value of the current working directory joined with the value |
| /// of the `RUSTUP_HOME` environment variable, if `RUSTUP_HOME` is a |
| /// relative directory. |
| /// - The `.rustup` directory in the user's home directory, as reported |
| /// by the `home_dir` function. |
| /// |
| /// # Errors |
| /// |
| /// This function fails if it fails to retrieve the current directory, |
| /// or if the home directory cannot be determined. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// match home::rustup_home() { |
| /// Ok(path) => println!("{}", path.display()), |
| /// Err(err) => eprintln!("Cannot get your rustup home dir: {:?}", err), |
| /// } |
| /// ``` |
| pub fn rustup_home() -> io::Result<PathBuf> { |
| let cwd = env::current_dir()?; |
| rustup_home_with_cwd(&cwd) |
| } |
| |
| /// Returns the storage directory used by rustup within `cwd`. |
| /// For more details, see [`rustup_home`](fn.rustup_home.html). |
| pub fn rustup_home_with_cwd(cwd: &Path) -> io::Result<PathBuf> { |
| match env::var_os("RUSTUP_HOME").filter(|h| !h.is_empty()) { |
| Some(home) => { |
| let home = PathBuf::from(home); |
| if home.is_absolute() { |
| Ok(home) |
| } else { |
| Ok(cwd.join(&home)) |
| } |
| } |
| _ => home_dir() |
| .map(|d| d.join(".rustup")) |
| .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "could not find rustup home dir")), |
| } |
| } |