Populate more `env.*` files under `$CARGO_HOME` regardless of platform
Problem
It looks like $HOME/.cargo/env is not created on Windows.
This breaks shell scripts that depend on it.
Steps
- Download and run rust-init.exe
- Check ~/.cargo/env existence
Possible Solution(s)
Just generate it like you do on Linux. It's useful for people using native bash on Windows.
Notes
No response
Rustup version
rustup 1.26.0 (5af9b9484 2023-04-05)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.75.0 (82e1608df 2023-12-21)`
Installed toolchains
Default host: x86_64-pc-windows-msvc
rustup home: C:\Users\WDAGUtilityAccount\.rustup
stable-x86_64-pc-windows-msvc (default)
rustc 1.75.0 (82e1608df 2023-12-21)
@rbtcollins do you think that'll be useful? I personally don't use Windows for development so I guess I can't decide by myself this time, sorry...
I mostly work from a Git Bash prompt when I have to use Windows. Rustup appears to correctly set the PATH variable for Windows, so $HOME/.cargo/bin ends up in my path, anyway. I can't say this doesn't break other scripts that assume the env file(s) exist, however, just that it doesn't require extra steps to use it from a Git Bash/Mintty CLI.
That said, all the various checks the init scripts and/or rustup appear to go through to determine whether to create the env files makes the existence of the files unpredictable. I ran into similar issues trying to get Rust installed in a Docker container for a GitLab runner and found several other issues that complain about $HOME/.cargo/env not being created. Of course, I can manually add it to the PATH, but the effects of rustup-init and install steps differ more than necessary between environments.
It would be better if the installers had consistent effects, and users can use manual workarounds for special cases. The env files are not large or risky to install. Better to just install them unless explicitly told not to with / as a side-effect of a flag like --no-modify-path, or perhaps if the file already exists (unless it's assume it should never be modified, in which case, that's on the user).
There's even an open issue about the fact that Rustup unconditionally assumes the env file exists. So even the Rust (meta) toolchain assumes it's there.
@bloodgain Thank for your detailed reply! I can see why this is probably causing a bad experience for Windows users now...
@ChrisDenton It looks like the user on Windows might be able to run the installer under pwsh or bash, and that will make it harder to determine what behavior can be considered "consistent". For example, will simply generating the script (without actually sourcing it) be okay, if somehow Rustup knows the user is running bash on Windows?
So just so I understand it, the current state is we only install these scripts on Unix hosts (i.e. not Windows): https://github.com/rust-lang/rustup/blob/b2622d69cd8baf31e8652dfc7e0f720476289202/src/cli/self_update.rs#L826-L827
And on Unix hosts we attempt to detect which shells are installed and only add env files as necessary: https://github.com/rust-lang/rustup/blob/b2622d69cd8baf31e8652dfc7e0f720476289202/src/cli/self_update/shell.rs#L84-L88
The suggestion here is to always install the env files in cargo's directory? Or at least do so by default on all platforms.
The suggestion here is to always install the env files in cargo's directory? Or at least do so by default on all platforms.
@ChrisDenton IMHO, following the spirit of current Unix support, it seems that a "consistent" implementation would be generating env for sh when it has detected signs of the current user actually using, say, bash.
However, it does look like there are many ways to install bash on Windows and it's hard to track them all, that's my primary concern now.
Yeah. We could check the SHELL environment variable to see if /usr/bin/bash is the currently running shell. But detecting if any of msys2/cygwin/etc is installed somewhere on the system is more difficult (or even impossible without scanning every directory).
That said, the Unix code does assume that a POSIX shell always exists (by virtue of being Unix): https://github.com/rust-lang/rustup/blob/b2622d69cd8baf31e8652dfc7e0f720476289202/src/cli/self_update/shell.rs#L117-L119
While the same rationale does not apply to Windows, there also doesn't seem to be much downside to adding env.sh anyway?
While the same rationale does not apply to Windows, there also doesn't seem to be much downside to adding
env.shanyway?
Yes, that's the direction I'm coming from. The shell used to install may not always be the shell used in all execution contexts. For example, I always use bash or zsh, but I have worked with legacy code that assumed csh was the execution env, which I managed by using scripts and aliases without giving up or rewriting my whole config.
Likewise, rustup-init.exe might be used to install, but the user will use a Bourne-derivative shell in practice.
Git Bash/Mintty works surprisingly well even with tools that were installed in the Windows context. In rare cases, I have to switch to Powershell for setup -- e.g. adding a JFrog server to the jf CLI tool -- but otherwise, it just works.
This is why most tools (that I'm familiar with) just go ahead and dump all the setup scripts in their usual directories.
Conda does this, for instance. It requires an extra step (manual or script) to set up the additional execution env, but at least the setup scripts are available if the user needs a different one. Otherwise, users have to go find it and copy the script somewhere before they can use it -- which sometimes means a non-standard location due to lack of write permissions -- or they have to duplicate the setup themselves.
@bloodgain Thanks for your detailed explanation! Your point makes perfect sense.
@ChrisDenton @djc I think there is another place where the old Rustup is trying to be too smart and it's sometimes too hard for the user to instruct it to behave otherwise. The same thing can happen on Unix as well if, say, I suddenly decided to start using nu but that happens after my last rustup self update. In this case I'll definitely end up without any env.nu and have to manually populate that file from the repo (we shouldn't assume that I can find that file that easily in the first place):
https://github.com/rust-lang/rustup/blob/178c502bfab89b68d7e2f2fa681e07ccef295656/src/cli/self_update/env.nu#L1-L3
To conclude, my proposal for the next minor version is the follows:
- Just populate the
env.*files no matter what. As long as we don't inject the installation into the$PATHwithout permission, all should be fine. (Yes, evenenv.fishon Windows, althoughfishwill probably never support Windows...) - The shell detection logic is here to stay, but only for
$PATHmodification purposes. - If something like the one described above happens, the user should be able to simply
sourcethe accordingenv.*file without having to figure out how to replicate its effects in e.g. their*shrc.
I see where you're going and it makes some sense, but at the same time as a user I would be a little annoyed if rustup sprayed a bunch of config files for shells I don't actually use all over the place? Maybe we should have some completion wizard thingy built-in that people can run and find the right points to advertise it (after install but maybe also if you run a shell for which no config is installed, or something)?
I see where you're going and it makes some sense, but at the same time as a user I would be a little annoyed if rustup sprayed a bunch of config files for shells I don't actually use all over the place?
@djc That's what pip and opam are doing with their venv activation script IIRC.
The suggestion of, e.g. rustup env nushell as a counterpart to rustup completions nushell sounds like a reasonable compromise? And it may be more discoverable that way.
We could additionally write all the env files to a rustup subdirectory so people can manually "install" them if they wish. That would avoid the issue of spraying config files all over the place.
write all the env files to a rustup subdirectory
@ChrisDenton @djc To clarify, what I meant is that we already have $CARGO_HOME to populate our env.* files to, my apologies if I wasn't clear enough, and it should do little harm to just populate all these env.* files over there.
In other words, what gets scattered across the filesystem are the scripts that source these env.* files (and of course we will only add them on demand), not these files themselves.
So if the user wants to add another shell to the mix, manually sourcing the corresponding env.* file will do, and it's usually just a single line in their *shrc file.
OTOH, if they want to source the env.* file automatically, rustup env <shell> would be perfect in terms of adding these sourcing scripts on demand.
Ahh, yes, if this is about adding all the env.* files to $CARGO_HOME by default, that makes sense to me.