-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Check installation dir permissions before uninstalling #847
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
Conversation
This LGTM at first glance - I'll want to play with it a bit first. Can you also add an automated test? |
Yeah I'll add a test in. This is the new output btw:
|
Looks great. You could even simplify it a bit by using |
I'll leave it simply because I've already got Builds are failing, but I have a hunch it may be the existing fast uninstall test that's wrong, not the new uninstall code. Meaning technically the permissions are wrong on the failing test. Would it be ok to remove the fast uninstall test and add a slow one that actually tests installing and then uninstalling node rather than faking it with empty folders? |
Let's start by adding the slow one; if that passes and the fast one fails, I'd love to look at both and see if we can save the fast test. |
I'm cloning into a random folder and working in there but when I run tests it's messing with my main |
Yes, that's the sad state of dev/testing - ideally it doesn't clobber existing installs when possible. |
I don't understand why sourcing the dev |
Think I've just implemented a fix that will make tests use the local nvm dir rather than the globally sourced one. I'll do some more testing and create a seperate pr for it tomorrow. If I can get that merged in and rebase this from it, it'll make writing these tests a hell of a lot easier |
Do you still want this PR? Got some time to have a look into that failing test this weekend if you do. |
@lukechilds yes! sorry if it's fallen through the cracks. What do you think about adding a test that verifies that it fails when permissions are wrong? |
No probs, I've been super busy. Got the fast test that was previously failing working. It was globbing doing weird stuff when files didn't exist (because the fast test creates an empty dir), using Yeah adding a test to check the fail message gets triggered would be good, I'll get on it. |
|
Ok, added a test to check for the error message. I'm also checking file permission with I still can't find anything saying how portable If you're happy this should be all sorted. |
# Check version dir permissions | ||
local INVALID_FILES="$(find "$VERSION_PATH" -exec [ ! -w "{}" ] \; -exec echo "{}" \;)" | ||
if [ "$INVALID_FILES" ]; then | ||
echo "Cannot uninstall, incorrect permissions on installation folder." |
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.
these should probably all echo to stderr - >&2 echo blah
@lukechilds thanks! Some minor comments, and it'd be nice to rebase these down to fewer conceptually atomic commits, but otherwise, good to go! |
Made those tweaks and squished everything down to three commits :) |
I tried this out locally, installed a version, and |
Hmmn, I'll take a look when I get in from work. |
Works fine for me, just tested on a fresh ubuntu vm:
I can't see any way it could cause an infinite loop, it's just running Did you have many global modules installed on the version you were uninstalling? Can you try on a freshly installed version? |
I was testing this on a fresh install with no additional global modules, on Mac OS. |
|
||
# Check version dir permissions | ||
local INVALID_FILES="$(find "$VERSION_PATH" -exec [ ! -w "{}" ] \; -exec echo "{}" \;)" | ||
if [ "$INVALID_FILES" ]; 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.
what are you intending to test here? perhaps you need -z
or -n
?
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.
$INVALID_FILES
contains a list of any files that we don't have write permissions for, so it's just a truthy test. If everything's good it should be an empty variable (falsey).
Works fine as is with sh, bash, zsh and dash but if you think it would help readability I could add in -z
.
Maybe, if it's readability you're concerned about, it would be better to rename the var to $FILES_WITHOUT_WRITE_PERMISIONS
. Then we could have:
if [ "$FILES_WITHOUT_WRITE_PERMISIONS" ]; then
# Error message
fi
which I think makes it obvious what's going on. Or is that too verbose?
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.
does it also work with ksh
?
I'm just surprised to see a truthiness test in shell scripting :-) won't -z
test the same thing, more explicitly?
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.
Yeah it works in ksh:
% ksh
$ var=""
$ [ $var ] && echo yep || echo nope
nope
I also just checked and -z
won't actually work, it returns true on an empty string which isn't what I want.
bash-3.2$ var=""
bash-3.2$ [ $var ] && echo yep || echo nope
nope
bash-3.2$ [ -z $var ] && echo yep || echo nope
yep
Personally I reckon this is ok but open to suggestions if there's a better way.
>&2 echo 'Cannot uninstall, incorrect permissions on installation folder.' | ||
>&2 echo 'This is usually caused by running `npm install -g` as root. Run the following command as root to fix the permissions and then try again.' | ||
>&2 echo | ||
>&2 echo " chown -R $(whoami) $VERSION_PATH" |
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.
nit: the VERSION_PATH should probably be in quotes, and the command surrounded by backticks, in case it has spaces.
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.
Good point
Just tested it on OS X 10.11.1 and it worked for me.
It did hang for maybe a second or two while it did the It's working on travis with all the different shells so it seems it's an anomaly on your system. Any ideas what it could be? What node version did you test with? |
Ok, I've wrapped the file path in the command output in quotes and I've renamed the file permissions var to make it super clear what's going on. Also managed to get a proper slow test working that installs a package globally as root and checks for the error message on uninstall. It's working correctly on all shells on Travis. |
ok, got it working locally - it hung there for awhile, but worked. $ time nvm uninstall 4.2.1
Uninstalled node v4.2.1
real 0m0.255s
user 0m0.051s
sys 0m0.207s
$ time nvm uninstall 4.2.0
Uninstalled node v4.2.0
real 0m0.156s
user 0m0.056s
sys 0m0.103s (note the silent fast failure on the latter case) on your branch: $ time nvm uninstall 4.2.1
Uninstalled node v4.2.1
real 0m3.838s
user 0m1.453s
sys 0m2.255s
$ time nvm uninstall 4.2.0
Cannot uninstall, incorrect permissions on installation folder.
This is usually caused by running `npm install -g` as root. Run the following command as root to fix the permissions and then try again.
chown -R `whoami` "$NVM_DIR/versions/node/v4.2.0"
real 0m6.965s
user 0m2.801s
sys 0m3.936s This is a significant slowdown. I'm wondering if it would be better to just try removing, and grep |
I see your point, the lag is less than ideal. Checking after is an option, the only issue is if the user ignores it, or misses it because it's in a script or whatever, I think the reason it's so slow is because It would involve replacing: local FILES_WITHOUT_WRITE_PERMISIONS="$(find "$VERSION_PATH" -exec [ ! -w "{}" ] \; -exec echo "{}" \;)" with something like: local PERMISSIONS_OK=true
check_file_permissions() {
for FILE in $1/* $1/.[!.]* $1/..?* ; do
if [ -d "$FILE" ]; then
check_file_permissions "$FILE"
elif [ -e "$FILE" ]; then
[ ! -w "$FILE" ] && PERMISSIONS_OK=false
fi
done
}
check_file_permissions "$VERSION_PATH" Worth a shot I suppose, what do you reckon? Might even be slower 😭🔫 |
I'd say it's worth doing it in a separate commit, and then we can |
$ time nvm uninstall 4.2.1
Uninstalled node v4.2.1
real 0m0.514s
user 0m0.275s
sys 0m0.244s
$ time nvm uninstall 4.2.0
Cannot uninstall, incorrect permissions on installation folder.
This is usually caused by running `npm install -g` as root. Run the following command as root to fix the permissions and then try again.
chown -R `whoami` "$NVM_DIR/versions/node/v4.2.0"
real 0m0.413s
user 0m0.279s
sys 0m0.135s i think we have a winner. (Let's keep the commit separate, so both this discussion and the relevant code remain in the history) |
Woah, it actually works! It wasn't quite as slow for me but it's gone from 1.4s to 0.15s: $ node_dir=/home/vagrant/.nvm/versions/node/v5.10.0/
$ time find "$node_dir" -exec [ ! -w "{}" ] \; -exec echo "{}" \;
real 0m1.420s
user 0m0.090s
sys 0m1.306s
$ time check_file_permissions "$node_dir"
real 0m0.148s
user 0m0.131s
sys 0m0.014s What do you get? |
Oops, just seen your reply. Glad this is sorted, only took 7 months! |
:-D thanks for the work! |
…n a closure. Also, make it return early, to be a bit more efficient. (from #847)
v0.31.1 Changelog New Stuff: - `nvm uninstall`: Check installation dir permissions before uninstalling; display "fix" commands (nvm-sh#847) - `nvm alias`: colorize output to match `nvm ls` - `nvm alias`: colorize output when creating aliases - `nvm ls`/`nvm alias`/`nvm ls-remote`: only colorize when colors are supported Fixes: - don’t use bash `==` in conditionals - `nvm run`: pass through `--silent` on bare `nvm run` - `nvm exec`: show “io.js” for io.js versions - `set -e`: ensure `nvm_version` returning 3, and `nvm_alias` returning 2, doesn’t terminate the process - `nvm alias`: explicitly forbid user aliases in subdirs - `read` exits 1 when `.nvmrc` lacks a trailing newline; avoid that - `set -x`: avoid an unbound variable - `deactivate`: unset `$NVM_BIN` and `$NVM_PATH` (nvm-sh#1033) Performance: - `nvm alias`: slightly speed up alias resolution - Use `awk` to improve version comparison performance Robustness: - add a missing `command` to a `sed` call Misc: - Various README tweaks - Various testing improvements - Prefer `nvm --help` over `nvm help`
Fixes #840