sdk: macOS dotnet CLI path for global tools is bad - Installer issue
Describe the bug
On macOS when a .Net tool is installed globally, it will not be found in the PATH.
The dotnet installer does attempt to make the directory for globally installed tools part of the PATH, but the mechanism the installer is relying on doesn’t work as the installer apparently expects.
To Reproduce
- Install dotnet on macOS using the Microsoft Installer from https://dotnet.microsoft.com/en-us/download.
- Install a tool globally, e.g.
dotnet tool install -g Microsoft.dotnet-httprepl
- Assuming zsh which is the default shell on macOS (Catalina and newer), run the command
which httprepl
- The output of the which command will be “httprepl not found” indicating that the httprepl tool can’t be found in the PATH.
Further technical details
Why does this happen?
macOS has a mechanism for adding paths to the PATH environment variable. The files in /etc/paths.d are used by the path_helper tool to build up the PATH environment variable.
The installer for dotnet is adding two files for paths:
- /etc/paths.d/dotnet
- /etc/paths.d/dotnet-cli-tools
The dotnet file contains
/usr/local/share/dotnet
The dotnet-cli-tools file contains
~/.dotnet/tools
However, paths in these files should be literal. The tilde (~) is not expanded to be the current user home directory. Environment variable references are also not expanded.
bash
The default standard shell on macOS Catalina (released in 2019) and newer is zsh. Prior to Catalina the default standard shell was bash. The bash shell appears to expand the tilde at a later point for an interactive shell so this issue may not manifest for bash users. However, the files created in /etc/paths.d by the dotnet installer need to support all shells.
Can’t Specify the Current User Home Directory
The tilde can’t be expected to be expanded to be the current user home directory. ${HOME} also can’t be used. There is not a way to specify the current user home directory in a file in /etc/paths.d.
I don’t know if not supporting the current user home directory is by design or is an omission.
Given the current functionality, the dotnet installer should not create the /etc/paths.d/dotnet-cli-tools file at all.
Workaround for Individual Users
In the .profile file, the user can either add the following line to add the needed path:
# dotnet-cli-tools
export PATH=$PATH:~/.dotnet/tools
or, assuming the bad path exists in the PATH, add the following ‘fix-up’ to replace any tildes in the PATH (equivalent to bash):
export PATH=${PATH//\~/$HOME}
The .zprofile may be set to source the .profile file with the following line:
[[ -e ~/.profile ]] && emulate sh -c 'source ~/.profile'
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 15
- Comments: 20 (4 by maintainers)
Commits related to this issue
- dotnet: remove bogus PATH entry containing tilde Ansible(-lint) does not like such entries. https://github.com/dotnet/sdk/issues/23165 — committed to agross/dotfiles by agross 2 years ago
- dotnet: replace bogus PATH entry containing tilde Ansible(-lint) does not like such entries. https://github.com/dotnet/sdk/issues/23165 — committed to agross/dotfiles by agross 2 years ago
Just a bump, I am still experiencing this issue
I agree with @jrdodds - the multi-user aspect is why we haven’t done this very simple change this entire time.
I still maintain that the correct thing to do is to provide a command (like
dotnet tool env <SHELL>
or something along those lines (would probably look at other ecosystems for consistency here)) that would write out the correct syntax for the given shell, and have the users put a call toeval $(dotnet tool env <SHELL>)
in their profile - we would print this in the first-run output.My two cents as a Mac user:
Adding the home expanded path to a system-wide path isn’t going to be an issue.
If multiple users need to install dotnet tools, and they are all added to the global path, nothing bad will happen. The users will be unable to see their peers’ home directories and the path lookup will just skip it.
The only downside here is that one user can accidentally break dotnet tools for all other users if they have root privileges… Which they could do anyway.
There is absolutely no reason not to take the pragmatic approach here. We’re talking about solving a huge pain point for thousands of users, which doesn’t impact other users in any way. That is the very definition of a win-win in this industry.
Maybe we can try to be pragmatic? This issue has existed since the introduction of the dotnet global tools and caused headaches to gazillion of developers. The proposed pull request solves this issue for developers installing the SDK themselves on their account and then using it on their account which I’d wager is more than 99% of the macOS dotnet developers. I’m pretty sure that the multi-user aspect exists only in the absolute but not in the reality of people using the dotnet SDK.
I just submitted #35411 to address this issue by writing the full path (
/Users/username/.dotnet/tools
) into/etc/paths.d/dotnet-cli-tools
.Let’s hope it gets merged and this PATH nightmare will finally be over. 🤞🏻
I believe tilde is not expanded in
PATH
.I am amazed how this ended up being implemented because it is well known that user of tilde (~) is invalid inside PATH environments. While most shells will accept and expand the ~, many tools will break. Tilde should never be part of PATH.
be great to get an update as just had a team of folks run through this on their Macs.
Thanks @jrdodds, this is the definitive summary of the MacOS issues.
I agree that we should not set any paths on /etc/paths.d that are user-specific.
If we want to maintain automatic PATH modification, then I agree that the best path for the installer going forward would be to add a $HOME-based path, but I after reading this post I think modifying the user’s .zshrc is the appropriate place for it. And then there are other concerns we’ll need to tackle as well - what if the user has set another shell? We’ll need to have a fallback that informs the user that the dotnet tools path isn’t in PATH, and that fallback sounds like modifications to the dotnet CLI’s output to me.