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
31pub mod env;
32
33#[cfg(target_os = "windows")]
34mod windows;
35
36use std::io;
37use 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/// ```
64pub fn home_dir() -> Option<PathBuf> {
65 env::home_dir_with_env(&env::OS_ENV)
66}
67
68#[cfg(windows)]
69use windows::home_dir_inner;
70
71#[cfg(any(unix, target_os = "redox"))]
72fn 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/// ```
104pub 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).
110pub 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/// ```
141pub 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).
147pub fn rustup_home_with_cwd(cwd: &Path) -> io::Result<PathBuf> {
148 env::rustup_home_with_cwd_env(&env::OS_ENV, cwd)
149}
150