Skip to content

Instantly share code, notes, and snippets.

@notpeter
Last active April 23, 2024 15:37
Show Gist options
  • Save notpeter/3e4e83b59d09b325ae77158caa1b0267 to your computer and use it in GitHub Desktop.
Save notpeter/3e4e83b59d09b325ae77158caa1b0267 to your computer and use it in GitHub Desktop.
Rust API Change Proposal: std::env::user_home_dir

Proposal (DRAFT) std::env::user_home_dir

Add new std::env::user_home_dir API returning Option<PathBuf>.

This API is a replacement for the deprecated std::env::home_dir which provides a platform agnostic method for identifying the user's home directory via environment variables ('HOME' on Unix, 'USERPROFILE' on Windows).

This implementation will be much simpler than std::env::home_dir as it will only search the environment and not fallback to calling platform APIs (e.g. getpwuid_r, GetUserProfileDirectoryW) when the environment variables are unset.

std::env::home_dir remains unchanged.

Problem statement

  1. The std::env::home_dir API is deprecated and fixing it would be a breaking API change.

    Deprecated since 1.29.0: This function’s behavior may be unexpected on Windows. Consider using a crate from crates.io instead. (See: rust-lang/rust#51656)

  2. 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 differs from the process environment.

  3. 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."

  4. 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 Cargo team 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 (libc, windows-sys, etc) which are entirely unused in the common case (environment has HOME set).

Motivating examples or use cases

Programmer wishes determine the current user home directory via inspecting environment variables in a platform agnostic way.

Basically the same use case as std::env::home_dir but without the bugs or fallback behavior when the environment variables are unset.

Ideally without instroducing platform specific dependencies (e.g. dirs crate depends on libc and windows-sys).

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

  1. 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):

  2. 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.

  3. 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:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment