| 1 | //! Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. | 
| 2 | //! | 
|---|
| 3 | //! The definition of `home_dir` provided by the standard library is | 
|---|
| 4 | //! incorrect because it considers the `HOME` environment variable on | 
|---|
| 5 | //! Windows. This causes surprising situations where a Rust program | 
|---|
| 6 | //! will behave differently depending on whether it is run under a | 
|---|
| 7 | //! Unix emulation environment like Cygwin or MinGW. Neither Cargo nor | 
|---|
| 8 | //! rustup use the standard libraries definition - they use the | 
|---|
| 9 | //! definition here. | 
|---|
| 10 | //! | 
|---|
| 11 | //! This crate provides two additional functions, `cargo_home` and | 
|---|
| 12 | //! `rustup_home`, which are the canonical way to determine the | 
|---|
| 13 | //! location that Cargo and rustup use to store their data. | 
|---|
| 14 | //! The `env` module contains utilities for mocking the process environment | 
|---|
| 15 | //! by Cargo and rustup. | 
|---|
| 16 | //! | 
|---|
| 17 | //! See also this [discussion]. | 
|---|
| 18 | //! | 
|---|
| 19 | //! > This crate is maintained by the Cargo team, primarily for use by Cargo and Rustup | 
|---|
| 20 | //! > and not intended for external use. This | 
|---|
| 21 | //! > crate may make major changes to its APIs or be deprecated without warning. | 
|---|
| 22 | //! | 
|---|
| 23 | //! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935 | 
|---|
| 24 |  | 
|---|
| 25 | #![ allow(clippy::disallowed_methods)] | 
|---|
| 26 |  | 
|---|
| 27 | pub mod env; | 
|---|
| 28 |  | 
|---|
| 29 | #[ cfg(target_os = "windows")] | 
|---|
| 30 | mod windows; | 
|---|
| 31 |  | 
|---|
| 32 | use std::io; | 
|---|
| 33 | use std::path::{Path, PathBuf}; | 
|---|
| 34 |  | 
|---|
| 35 | /// Returns the path of the current user's home directory using environment | 
|---|
| 36 | /// variables or OS-specific APIs. | 
|---|
| 37 | /// | 
|---|
| 38 | /// # Unix | 
|---|
| 39 | /// | 
|---|
| 40 | /// Returns the value of the `HOME` environment variable if it is set | 
|---|
| 41 | /// **even** if it is an empty string. Otherwise, it tries to determine the | 
|---|
| 42 | /// home directory by invoking the [`getpwuid_r`][getpwuid] function with | 
|---|
| 43 | /// the UID of the current user. | 
|---|
| 44 | /// | 
|---|
| 45 | /// [getpwuid]: https://linux.die.net/man/3/getpwuid_r | 
|---|
| 46 | /// | 
|---|
| 47 | /// # Windows | 
|---|
| 48 | /// | 
|---|
| 49 | /// Returns the value of the `USERPROFILE` environment variable if it is set | 
|---|
| 50 | /// **and** it is not an empty string. Otherwise, it tries to determine the | 
|---|
| 51 | /// home directory by invoking the [`SHGetKnownFolderPath`][shgkfp] function with | 
|---|
| 52 | /// [`FOLDERID_Profile`][knownfolderid]. | 
|---|
| 53 | /// | 
|---|
| 54 | /// [shgkfp]: https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath | 
|---|
| 55 | /// [knownfolderid]: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid | 
|---|
| 56 | /// | 
|---|
| 57 | /// # Examples | 
|---|
| 58 | /// | 
|---|
| 59 | /// ``` | 
|---|
| 60 | /// match home::home_dir() { | 
|---|
| 61 | ///     Some(path) if !path.as_os_str().is_empty() => println!( "{}", path.display()), | 
|---|
| 62 | ///     _ => println!( "Unable to get your home dir!"), | 
|---|
| 63 | /// } | 
|---|
| 64 | /// ``` | 
|---|
| 65 | pub fn home_dir() -> Option<PathBuf> { | 
|---|
| 66 | env::home_dir_with_env(&env::OS_ENV) | 
|---|
| 67 | } | 
|---|
| 68 |  | 
|---|
| 69 | #[ cfg(windows)] | 
|---|
| 70 | use windows::home_dir_inner; | 
|---|
| 71 |  | 
|---|
| 72 | #[ cfg(any(unix, target_os = "redox"))] | 
|---|
| 73 | fn home_dir_inner() -> Option<PathBuf> { | 
|---|
| 74 | #[ allow(deprecated)] | 
|---|
| 75 | std::env::home_dir() | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | /// Returns the storage directory used by Cargo, often knowns as | 
|---|
| 79 | /// `.cargo` or `CARGO_HOME`. | 
|---|
| 80 | /// | 
|---|
| 81 | /// It returns one of the following values, in this order of | 
|---|
| 82 | /// preference: | 
|---|
| 83 | /// | 
|---|
| 84 | /// - The value of the `CARGO_HOME` environment variable, if it is | 
|---|
| 85 | ///   an absolute path. | 
|---|
| 86 | /// - The value of the current working directory joined with the value | 
|---|
| 87 | ///   of the `CARGO_HOME` environment variable, if `CARGO_HOME` is a | 
|---|
| 88 | ///   relative directory. | 
|---|
| 89 | /// - The `.cargo` directory in the user's home directory, as reported | 
|---|
| 90 | ///   by the `home_dir` function. | 
|---|
| 91 | /// | 
|---|
| 92 | /// # Errors | 
|---|
| 93 | /// | 
|---|
| 94 | /// This function fails if it fails to retrieve the current directory, | 
|---|
| 95 | /// or if the home directory cannot be determined. | 
|---|
| 96 | /// | 
|---|
| 97 | /// # Examples | 
|---|
| 98 | /// | 
|---|
| 99 | /// ``` | 
|---|
| 100 | /// match home::cargo_home() { | 
|---|
| 101 | ///     Ok(path) => println!( "{}", path.display()), | 
|---|
| 102 | ///     Err(err) => eprintln!( "Cannot get your cargo home dir: {:?}", err), | 
|---|
| 103 | /// } | 
|---|
| 104 | /// ``` | 
|---|
| 105 | pub fn cargo_home() -> io::Result<PathBuf> { | 
|---|
| 106 | env::cargo_home_with_env(&env::OS_ENV) | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | /// Returns the storage directory used by Cargo within `cwd`. | 
|---|
| 110 | /// For more details, see [`cargo_home`](fn.cargo_home.html). | 
|---|
| 111 | pub fn cargo_home_with_cwd(cwd: &Path) -> io::Result<PathBuf> { | 
|---|
| 112 | env::cargo_home_with_cwd_env(&env::OS_ENV, cwd) | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | /// Returns the storage directory used by rustup, often knowns as | 
|---|
| 116 | /// `.rustup` or `RUSTUP_HOME`. | 
|---|
| 117 | /// | 
|---|
| 118 | /// It returns one of the following values, in this order of | 
|---|
| 119 | /// preference: | 
|---|
| 120 | /// | 
|---|
| 121 | /// - The value of the `RUSTUP_HOME` environment variable, if it is | 
|---|
| 122 | ///   an absolute path. | 
|---|
| 123 | /// - The value of the current working directory joined with the value | 
|---|
| 124 | ///   of the `RUSTUP_HOME` environment variable, if `RUSTUP_HOME` is a | 
|---|
| 125 | ///   relative directory. | 
|---|
| 126 | /// - The `.rustup` directory in the user's home directory, as reported | 
|---|
| 127 | ///   by the `home_dir` function. | 
|---|
| 128 | /// | 
|---|
| 129 | /// # Errors | 
|---|
| 130 | /// | 
|---|
| 131 | /// This function fails if it fails to retrieve the current directory, | 
|---|
| 132 | /// or if the home directory cannot be determined. | 
|---|
| 133 | /// | 
|---|
| 134 | /// # Examples | 
|---|
| 135 | /// | 
|---|
| 136 | /// ``` | 
|---|
| 137 | /// match home::rustup_home() { | 
|---|
| 138 | ///     Ok(path) => println!( "{}", path.display()), | 
|---|
| 139 | ///     Err(err) => eprintln!( "Cannot get your rustup home dir: {:?}", err), | 
|---|
| 140 | /// } | 
|---|
| 141 | /// ``` | 
|---|
| 142 | pub fn rustup_home() -> io::Result<PathBuf> { | 
|---|
| 143 | env::rustup_home_with_env(&env::OS_ENV) | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /// Returns the storage directory used by rustup within `cwd`. | 
|---|
| 147 | /// For more details, see [`rustup_home`](fn.rustup_home.html). | 
|---|
| 148 | pub fn rustup_home_with_cwd(cwd: &Path) -> io::Result<PathBuf> { | 
|---|
| 149 | env::rustup_home_with_cwd_env(&env::OS_ENV, cwd) | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|