Proposal
Add new API: std::env::user_home_dir returning Option<PathBuf>.
This is a replacement for the deprecated std::env::home_dir, providing a platform agnostic method for identifying the user's home directory checking platform-specific environment variables ('HOME' on Unix, 'USERPROFILE' on Windows) as required.
The proposed implementation is simpler than std::env::home_dir as only searches the environment and does not attempt call one/multiple platform APIs (e.g. getpwuid_r, GetUserProfileDirectoryW, etc) as fallback when the appropriate environment variables are unset.
The existing env::home_dir remains unchanged.
Problem statement
-
The std::env::home_dir API is deprecated. Fixing it would be a breaking API change. (See: rust-lang/rust#51656)
Deprecated since 1.29.0: This function’s behavior may be unexpected on Windows.
Consider using a crate from crates.io instead.
-
In most home_dir implementations, (including std::env::home_dir) if the 'HOME' / 'USERPROFILE' environment variables are unset, there is fallback implementation that calls one/multiple platform APIs in order to guess the user's home directory. This is potentially surprising behavior, as it is not call an env::* function may magically get you a value which is nowhere in the process environment.
-
The std::env::home_dir API may return a value which is not usable as a Path (""). This occurs when HOME set to an empty string, which is not uncommon in restricted shell environments (sudo, cron jobs, etc). Callers thus must check for None and for an empty string before using the returned value. Earlier documentation for std::env::home_dir suggests this may have been the original intended behavior:
"Returns the value of the 'HOME' environment variable if it is set and not equal to the empty string."
-
Users looking for a replacement for std::env::home_dir are forced to evaluate and choose amongst a number of 3rd party crates:
- The 'home' crate, maintained by the Cargo team, is the very popular and used by (nearly 500 crates but the Cargoteam has stated they do not wish to maintain it as a general purpose 'home_dir' replacement and they consider it only an internal Cargo and Rustup dependency.
- The 'home' crate generates a compile time error on wasm and other non-Unix/Windows platforms. The Cargo team has signaled they do not intend to fix this. See: rust-lang/cargo#12297
- Many crates do not just provide a
std::env::home_dir replacement but also provide additional abstractions over other platform-specific APIs (XDG, Windows Known Folders API, etc)
- Many crates have platform specific dependencies. For example dirs crate depends on libc and windows-sys which are entirely unused in the common case where the environment has
HOME or USERPROFILE set.
Motivating examples or use cases
Developer wishes determine the current user home directory via inspecting environment variables in a platform agnostic way.
The same use case as std::env::home_dir but without the bugs or fallback behavior when environment variables are unset.
Solution sketch
Create the API which covers the most common use of std::env::user_home_dir
getting a PathBuf with of user's home directory, if available,
by inspecting environment variables:
- New
user_home_dir function that returns Option<PathBuf>.
- Checks for
USERPROFILE environment variable on Windows.
- Checks for
HOME environment variable variable on Unix.
- Return None if variable is unset.
- Return None if variable set to an empty string.
- Return None if platform does not have a concept of a home directory (wasi, etc)
- Do not attempt to guess the user's home directory when environment variables are unset (principle of least surprise)
See: env_home lib.rs for a potential implementation.
Naming is hard, especially when a deprecated API has good name. I prefer std::env::user_home_dir as it does not collide with std::env::home_dir or home_dir provided by other crates.
Alternatives
-
Do nothing. Require users to evaluate and choose a 3rd party crate which provides a home_dir API with better behavior on Windows (usually including extra APIs):
-
Extract the current cargo implementation of home_dir from the home and trivial fixes so it compiles as a no-op on unsupported platforms. Publish as a stand-alone crate and recommend it as a replacement for std::env::home_dir.
-
Create an implementation of home_dir that only relies on the platform specific APIs and does not inspect environment variables. This would make it trivial to implement the platform API fallback behavior of std::env::home_dir when environment variables are unset.
Links and related work
Discussions:
Languages whose standard library provides a platform independent home_dir abstraction:
Languages which do not have a home_dir abstraction in the standard library:
Notes
I am particularly interested to hear of real-world use cases or systems where $HOME is unset and the directory provided via platform-specific APIs is available/appropriate for use. In my experience $HOME being unset is a signal that there there is nothing like a unix home directory available to my process and my app should behave accordingly.
This is my first attempt at drafting an API Change Proposal, so please be kind.
Thanks!
Proposal
Add new API:
std::env::user_home_dirreturningOption<PathBuf>.This is a replacement for the deprecated
std::env::home_dir, providing a platform agnostic method for identifying the user's home directory checking platform-specific environment variables ('HOME' on Unix, 'USERPROFILE' on Windows) as required.The proposed implementation is simpler than
std::env::home_diras only searches the environment and does not attempt call one/multiple platform APIs (e.g.getpwuid_r,GetUserProfileDirectoryW, etc) as fallback when the appropriate environment variables are unset.The existing
env::home_dirremains unchanged.Problem statement
The
std::env::home_dirAPI is deprecated. Fixing it would be a breaking API change. (See: rust-lang/rust#51656)In most
home_dirimplementations, (includingstd::env::home_dir) if the 'HOME' / 'USERPROFILE' environment variables are unset, there is fallback implementation that calls one/multiple platform APIs in order to guess the user's home directory. This is potentially surprising behavior, as it is not call anenv::*function may magically get you a value which is nowhere in the process environment.The
std::env::home_dirAPI may return a value which is not usable as a Path (""). This occurs when HOME set to an empty string, which is not uncommon in restricted shell environments (sudo, cron jobs, etc). Callers thus must check for None and for an empty string before using the returned value. Earlier documentation forstd::env::home_dirsuggests this may have been the original intended behavior:Users looking for a replacement for
std::env::home_dirare forced to evaluate and choose amongst a number of 3rd party crates:std::env::home_dirreplacement but also provide additional abstractions over other platform-specific APIs (XDG, Windows Known Folders API, etc)HOMEorUSERPROFILEset.Motivating examples or use cases
Developer wishes determine the current user home directory via inspecting environment variables in a platform agnostic way.
The same use case as
std::env::home_dirbut without the bugs or fallback behavior when environment variables are unset.Solution sketch
Create the API which covers the most common use of
std::env::user_home_dirgetting a
PathBufwith of user's home directory, if available,by inspecting environment variables:
user_home_dirfunction that returnsOption<PathBuf>.USERPROFILEenvironment variable on Windows.HOMEenvironment variable variable on Unix.See: env_home lib.rs for a potential implementation.
Naming is hard, especially when a deprecated API has good name. I prefer
std::env::user_home_diras it does not collide withstd::env::home_dirorhome_dirprovided by other crates.Alternatives
Do nothing. Require users to evaluate and choose a 3rd party crate which provides a
home_dirAPI with better behavior on Windows (usually including extra APIs):Extract the current cargo implementation of
home_dirfrom thehomeand trivial fixes so it compiles as a no-op on unsupported platforms. Publish as a stand-alone crate and recommend it as a replacement forstd::env::home_dir.Create an implementation of
home_dirthat only relies on the platform specific APIs and does not inspect environment variables. This would make it trivial to implement the platform API fallback behavior ofstd::env::home_dirwhen environment variables are unset.Links and related work
Discussions:
std::env::home_dirand fix incorrect documentation rust#51656Languages whose standard library provides a platform independent home_dir abstraction:
Languages which do not have a home_dir abstraction in the standard library:
Notes
I am particularly interested to hear of real-world use cases or systems where $HOME is unset and the directory provided via platform-specific APIs is available/appropriate for use. In my experience
$HOMEbeing unset is a signal that there there is nothing like a unix home directory available to my process and my app should behave accordingly.This is my first attempt at drafting an API Change Proposal, so please be kind.
Thanks!