-
-
Notifications
You must be signed in to change notification settings - Fork 8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Fix] install
: detect user shell and try shellrc file first
#2260
base: master
Are you sure you want to change the base?
Conversation
…nto install-script-fix-zsh Rebasing on remote
Hey @ljharb, I accepted a few of your suggestions and added some context for the sh-bash change. What more do we need to move this forward? |
@steelcowboy sorry for the delay; replied to your comment. |
Hey @ljharb, I just made a few changes:
Let me know what you think! |
What is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to make "testing" variables only determine whether a command runs or not, kind of like a "dry run" - this one actually follows a different code path which seems less than ideal.
|
||
# If we're not testing, try to get shell from passwd | ||
# Otherwise, try the SHELL variable | ||
if [ "$NVM_TESTING" != 'yes' ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if [ "$NVM_TESTING" != 'yes' ]; then | |
if [ "${NVM_TESTING-}" != 'yes' ]; then |
# Otherwise, try the SHELL variable | ||
if [ "$NVM_TESTING" != 'yes' ]; then | ||
USER_SHELL=$(getent passwd $(whoami) | cut -d: -f7) | ||
elif [ -n "$SHELL" ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elif [ -n "$SHELL" ]; then | |
elif [ -n "${SHELL-}" ]; then |
# If we're not testing, try to get shell from passwd | ||
# Otherwise, try the SHELL variable | ||
if [ "$NVM_TESTING" != 'yes' ]; then | ||
USER_SHELL=$(getent passwd $(whoami) | cut -d: -f7) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I run $(getent passwd $(whoami) | cut -d: -f7)
on my Mac, I get -bash: getent: command not found
on stderr, which doesn't seem like something we want. What is getent
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shoot yeah I meant to see if getent exists on Mac, apparently it doesn't :/ Back to the drawing board!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So looking at it, there doesn't seem to be a standard POSIX way to do this -- and the current behavior of checking various shell versions certainly isn't POSIX, as there is no $DASH_VERSION for example.
As such, I propose we do this: getent is the most reliable way on Linux machines, and it's quite standard. We could go one step further and just grep $(whoami)
on /etc/passwd
if we want to avoid getent.
On MacOS, I think the best we can do is hope the $SHELL variable is accurate because Apple. MacOS apparently does its own thing for storing user info, so we could either write in logic to use getent
on Linux and whatever MacOS-equivalent on MacOS, or we can see if getent
exists, use it if possible, fall back to $SHELL
, and finally fall back to brute forcing. Either way, I'm confident that doing that will:
- Make all supported shells work on Linux
- Support at LEAST bash and zsh on MacOS, except there's still the remaining issue of MacOS not creating zshrc :) But again, that's a hurdle for a different PR
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with trying a bunch of different things in the install script, as long as they fail gracefully on systems where they don't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it! So getent
obviously works reliably on Linux, but I'm exploring a more cross-platform solution of simply seeing what the parent process of the script is :) I think it's quite reasonable, because it's most likely that people would be installing nvm
from their default shell.
Furthermore, if you decide to start a new bash
session when your default shell is zsh
simply to install nvm
, I think it's fair to say it's the user's responsibility at that point since my impression is that opening a different type of shell just to install something is pretty non-standard. We can document it to say that running the script will "install nvm for the currently running shell" too so the behavior doesn't surprise anyone.
That makes sense on testing variables! The issue here we need to resolve is that we're trying to learn about system state in a testing environment, which makes sense if we can just pass a variable (e,.g. SHELL) but it's a lot harder if we want to mock, for example, Do you see a better way forward? |
I'd focus on what makes the production code correct, and I'm happy to help figure out how to mock it properly, rather than thinking about tests when writing the real code :-) |
Can't you just look at the
This is on MacOS, but I expect it would work the same on Linux Edit: Didn't see how old this PR was. Guess this is abandoned and I should make a new PR. |
c6cfc3a
to
c20db2a
Compare
Situation
Currently, the nvm install script has a specific order in which it looks for files:
.bashrc
.bash_profile
.zshrc
However, this doesn't take into account any kind of user preference. I suggest we first try and see if we can find the user's shell and determine a good RC file to use based on that. If not, we fall back to the current behavior.
Tests
I had to change the shell on
nvm_install_with_aliased_dot
to bash in order to useshopt
, open to a different approach though!Current Behavior
New Behavior
Docker Testing
bash
https://gist.github.com/steelcowboy/451d45ae6a1728dba7678ce2e68dbcc4
zsh
https://gist.github.com/steelcowboy/1d7ac8aed8e7b6a275aa1d35ac43cd1a
dash
https://gist.github.com/steelcowboy/1af21c23cac3208b9dc77676475e65d3
ksh
https://gist.github.com/steelcowboy/5b62b7ac44c7e425c504a86ba511d1dc
Note: It doesn't like the
local
in nvm.sh, but this is a known issue: #574mksh
https://gist.github.com/steelcowboy/5b62b7ac44c7e425c504a86ba511d1dc
Interestingly unlike AT&T ksh, mksh is perfectly happy with the local variables :)
MacOS Issue
Resolves #592, but #2148 still remains because Catalina doesn't create any default .zshrc it would seem. If we wanted to take the spirit of this change further, we could simply
touch $SHELLRC
because if your shell is set I'd imagine there's a high likelihood you want an rc file for it :)I think if we do want to go that direction, the best approach is to do it in another PR to keep the changes well-scoped.