Skip to content

ACP: env::home_dir replacement #372

Open
@notpeter

Description

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

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

  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 is nowhere in 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 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

  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:

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!

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions