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