Skip to content
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

gem uninstall --user-install GEM_NAME throws InstallError, even if the gem is installed #6457

Closed
duckinator opened this issue Mar 9, 2023 · 16 comments · Fixed by #7645
Closed
Labels

Comments

@duckinator
Copy link
Member

Describe the problem as clearly as you can

If you run gem install --user-install SOME_GEM, then run gem uninstall --user-install SOME_GEM, RubyGems throws an error because the gem is not in GEM_HOME and tells you to use --install-dir instead.

There is a test which seems relevant, and passes. It does not catch this problem, however.

def test_uninstall_user_install
@user_spec = Gem::Specification.find_by_name "b"
uninstaller = Gem::Uninstaller.new(@user_spec.name,
:executables => true,
:user_install => true)
gem_dir = File.join @user_spec.gem_dir
Gem.pre_uninstall do
assert_path_exist gem_dir
end
Gem.post_uninstall do
assert_path_not_exist gem_dir
end
uninstaller.uninstall
assert_path_not_exist gem_dir
assert_same uninstaller, @pre_uninstall_hook_arg
assert_same uninstaller, @post_uninstall_hook_arg
end

I suspect we need something closer to an integration test, possibly in test/rubygems/test_gem_commands_uninstall_command.rb.

Did you try upgrading RubyGems?

Yes. This occurs both on RubyGems 3.4.8 and master (as of 6256829)

Post steps to reproduce the problem

Using Ruby 3.0.5p211, via the FreeBSD lang/ruby30 package.

$ gem --version
3.4.8
$ gem install --user-install boop
Fetching boop-0.5.0.gem
WARNING:  You don't have /home/puppy/.gem/ruby/3.0/bin in your PATH,
          gem executables will not run.
Successfully installed boop-0.5.0
1 gem installed
$ gem uninstall --user-install boop
ERROR:  While executing gem ... (Gem::InstallError)
    boop is not installed in GEM_HOME, try:
        gem uninstall -i /usr/home/puppy/.gem/ruby/3.0 boop
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/uninstaller.rb:124:in `uninstall'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:195:in `uninstall'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:181:in `uninstall_gem'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:175:in `block in uninstall_specific'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:167:in `each'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:167:in `uninstall_specific'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/commands/uninstall_command.rb:133:in `execute'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/command.rb:327:in `invoke_with_build_args'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/command_manager.rb:252:in `invoke_command'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/command_manager.rb:192:in `process_args'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/command_manager.rb:150:in `run'
        /usr/local/lib/ruby/site_ruby/3.0/rubygems/gem_runner.rb:51:in `run'
        /usr/local/bin/gem:10:in `<main>'
puppy@orthrus.fox:~/test$

Which command did you run?

gem uninstall --user-install boop (exact gem does not matter).

What were you expecting to happen?

I was expecting it to uninstall the specified gem.

What actually happened?

It said it is not installed in GEM_HOME, and recommends using -i (--install-dir) with the user-install directory (the value of Gem.user_dir).

Run gem env and paste the output below

RubyGems Environment:
  - RUBYGEMS VERSION: 3.4.8
  - RUBY VERSION: 3.0.5 (2022-11-24 patchlevel 211) [amd64-freebsd13]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/3.0
  - USER INSTALLATION DIRECTORY: /home/puppy/.gem/ruby/3.0
  - RUBY EXECUTABLE: /usr/local/bin/ruby30
  - GIT EXECUTABLE: /usr/local/bin/git
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/puppy/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - amd64-freebsd-13
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/3.0
     - /usr/home/puppy/.gem/ruby/3.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
     - "gem" => "--suggestions --no-document"
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /usr/home/puppy/.rubies/ruby-3.2.1/lib/ruby/gems/3.2.0/bin
     - /home/puppy/.cargo/bin
     - /home/puppy/bin
     - /home/puppy/.local/bin
     - /home/puppy/.gem/ruby/bin
     - /home/puppy/.npm-global/bin
     - /home/puppy/go/bin
     - /bin
     - /usr/bin
     - /sbin
     - /usr/sbin
     - /usr/local/bin
     - /usr/local/sbin
@duckinator
Copy link
Member Author

This issue blocks #5327 (If GEM_HOME is not writable, use --user-install).

The error is obviously deliberate, but I suspect it was not intended to affect --user-install:

def uninstall_gem(gem_name)
uninstall(gem_name)
rescue Gem::GemNotInHomeException => e
spec = e.spec
alert("In order to remove #{spec.name}, please execute:\n" +
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
rescue Gem::UninstallError => e
spec = e.spec
alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " +
"located at '#{spec.full_gem_path}'. This is most likely because" +
"the current user does not have the appropriate permissions")
terminate_interaction 1
end

@voxik
Copy link
Contributor

voxik commented Mar 9, 2023

Just FTR, the gem uninstall --user-install boop command is questionable IMHO. Should the --user-install influence anything?

  • RubyGems already knows where the gem is
  • if there are more possibilities, it allows to pick
  • If the location is RW, then is should be able to remove such gem.

@duckinator
Copy link
Member Author

duckinator commented Mar 9, 2023

Yeah, I'm not entirely sure what the appropriate behavior is. I just know that "throw an error" feels like it is definitely wrong.

@rubyFeedback
Copy link

Should the --user-install influence anything?

That is a good question, but as far as I know, if you use gem --user-install, it will install into the home dir, right? And there may be situations where you have /usr/lib/ as target (say a campus university computer system) and you need to override some things via custom gems so --user-install is used. You are probably correct that this may not make a difference because of gem's default behaviour targeting the user's home dir first - that may be. But I can understand why users can come up with using --user-install at gem uninstall too, even though that seems a misnomer. 🗡️

if there are more possibilities, it allows to pick

Well, while I agree with you in general, IF the user passes a flag that says "ruby, target user-installed gems first", then there should not be any picking. It should default to uninstall the first gem it can find AT the user-install directory.

@rubyFeedback
Copy link

I guess an additional source of confusion may be for users to wonder what GEM_HOME is used for and how it relates to --user-install, if at all.

@deivid-rodriguez
Copy link
Member

Interesting. This works as documented for me:

$ gem --version
3.4.8

$ gem install --user-install boop  
WARNING:  You don't have /Users/deivid/.gem/ruby/3.2.0/bin in your PATH,
	  gem executables will not run.
Successfully installed boop-0.5.0
1 gem installed

$ gem uninstall --user-install boop
Remove executables:
	boop

in addition to the gem? [Yn]  Y
Removing boop
Successfully uninstalled boop-0.5.0

So this is probably specific to @duckinator's setup. Have you investigated anything yet, @duckinator?

For what it's worth, the option is documented like this:

add_option("--[no-]user-install",
"Uninstall from user's home directory",
"in addition to GEM_HOME.") do |value, options|
options[:user_install] = value
end

@duckinator
Copy link
Member Author

I haven't dug into this yet. Planning to get to it this week.

@duckinator
Copy link
Member Author

duckinator commented Mar 31, 2023

This is reproducible on a fresh FreeBSD 13.1 VM.

Installed FreeBSD 13.1, added a non-root user, and installed the ruby and ruby30-gems packages.

`gem env` after installing `ruby` and `ruby30-gems` packages
RubyGems Environment:
  - RUBYGEMS VERSION: 3.3.26
  - RUBY VERSION: 3.0.5 (2022-11-24 patchlevel 211) [amd64-freebsd13]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/3.0
  - USER INSTALLATION DIRECTORY: /home/freebsd/.local/share/gem/ruby/3.0
  - RUBY EXECUTABLE: /usr/local/bin/ruby30
  - GIT EXECUTABLE: 
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/freebsd/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - amd64-freebsd-13
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/3.0
     - /usr/home/freebsd/.local/share/gem/ruby/3.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /sbin
     - /bin
     - /usr/sbin
     - /usr/bin
     - /usr/local/sbin
     - /usr/local/bin
     - /home/freebsd/bin

This also happens with the latest RubyGems (installed via gem update --system as root).

`gem env` after `gem update --system`
RubyGems Environment:
  - RUBYGEMS VERSION: 3.4.10
  - RUBY VERSION: 3.0.5 (2022-11-24 patchlevel 211) [amd64-freebsd13]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/3.0
  - USER INSTALLATION DIRECTORY: /home/freebsd/.local/share/gem/ruby/3.0
  - RUBY EXECUTABLE: /usr/local/bin/ruby30
  - GIT EXECUTABLE: 
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/freebsd/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - amd64-freebsd-13
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/3.0
     - /usr/home/freebsd/.local/share/gem/ruby/3.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /sbin
     - /bin
     - /usr/sbin
     - /usr/bin
     - /usr/local/sbin
     - /usr/local/bin
     - /home/freebsd/bin

I could not reproduce it on Ubuntu 22.04. I'm attempting to narrow it down farther.

@duckinator
Copy link
Member Author

It took a little more effort (I had to manually install RubyGems from a TGZ file), but almost-latest Ruby (3.2.0) and latest RubyGems (3.4.10) still had the problem.

`gem env` on fresh FreeBSD 13.1 VM, after installing `ruby32` and installing RubyGems manually
  - RUBYGEMS VERSION: 3.4.10
  - RUBY VERSION: 3.2.0 (2022-12-25 patchlevel 0) [amd64-freebsd13]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/3.2
  - USER INSTALLATION DIRECTORY: /home/freebsd/.local/share/gem/ruby/3.2
  - RUBY EXECUTABLE: /usr/local/bin/ruby32
  - GIT EXECUTABLE: 
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/freebsd/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - amd64-freebsd-13
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/3.2
     - /usr/home/freebsd/.local/share/gem/ruby/3.2
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /sbin
     - /bin
     - /usr/sbin
     - /usr/bin
     - /usr/local/sbin
     - /usr/local/bin
     - /home/freebsd/bin

@duckinator
Copy link
Member Author

Some info from the working system, for comparison.

`gem env` on Ubuntu 22.04 LTS
RubyGems Environment:
  - RUBYGEMS VERSION: 3.3.5
  - RUBY VERSION: 3.0.2 (2021-07-07 patchlevel 107) [x86_64-linux-gnu]
  - INSTALLATION DIRECTORY: /var/lib/gems/3.0.0
  - USER INSTALLATION DIRECTORY: /home/ubuntu/.local/share/gem/ruby/3.0.0
  - RUBY EXECUTABLE: /usr/bin/ruby3.0
  - GIT EXECUTABLE: /usr/bin/git
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/ubuntu/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - x86_64-linux
  - GEM PATHS:
     - /var/lib/gems/3.0.0
     - /home/ubuntu/.local/share/gem/ruby/3.0.0
     - /usr/local/lib/ruby/gems/3.0.0
     - /usr/lib/ruby/gems/3.0.0
     - /usr/lib/x86_64-linux-gnu/ruby/gems/3.0.0
     - /usr/share/rubygems-integration/3.0.0
     - /usr/share/rubygems-integration/all
     - /usr/lib/x86_64-linux-gnu/rubygems-integration/3.0.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
     - /usr/bin
     - /sbin
     - /bin
     - /usr/games
     - /usr/local/games
     - /snap/bin

@indirect
Copy link
Member

indirect commented Apr 1, 2023

Hmm. Off the top of my head, that sounds like an issue with the FreeBSD ruby package, rather than an issue with Ruby itself. If you install ruby on FreeBSD using a version manager like rvm or ruby-install, does it still have the same problem?

@duckinator
Copy link
Member Author

duckinator commented Apr 5, 2023

I used Ruby 3.0.5 installed via ruby-install and switched to it with chruby (this is the closest version I had without waiting ages for Ruby to compile). I deleted ~/.gem/ before each attempt, in case something else I was doing was causing problems.

By default I get a different failure: it just doesn't think the gem is installed.

puppy@orthrus.fox:~$ chruby 3.0
puppy@orthrus.fox:~$ gem install --user-install boop
Fetching boop-0.5.0.gem
WARNING:  You don't have /home/puppy/.gem/ruby/3.0.0/bin in your PATH,
          gem executables will not run.
Successfully installed boop-0.5.0
1 gem installed
puppy@orthrus.fox:~$ gem uninstall --user-install boop
Gem 'boop' is not installed
puppy@orthrus.fox:~$ 

After deleting ~/.gem to reset, I unset the GEM_* variables that chruby sets by default and tried again. This time I got the behavior with it telling me to use gem uninstall -i [...] boop:

attempting with `GEM_*` unset
puppy@orthrus.fox:~$ chruby 3.0
puppy@orthrus.fox:~$ env | grep GEM_
GEM_ROOT=/usr/home/puppy/.rubies/ruby-3.0.5/lib/ruby/gems/3.0.0
GEM_PATH=/home/puppy/.gem/ruby/3.0.5:/usr/home/puppy/.rubies/ruby-3.0.5/lib/ruby/gems/3.0.0
GEM_HOME=/home/puppy/.gem/ruby/3.0.5
puppy@orthrus.fox:~$ unset GEM_ROOT GEM_PATH GEM_HOME
puppy@orthrus.fox:~$ rm -rf ~/.local/share/gem/ ~/.gem/
puppy@orthrus.fox:~$ gem install --user-install boop
Fetching boop-0.5.0.gem
WARNING:  You don't have /home/puppy/.local/share/gem/ruby/3.0.0/bin in your PATH,
          gem executables will not run.
Successfully installed boop-0.5.0
1 gem installed
puppy@orthrus.fox:~$ gem uninstall --user-install boop
ERROR:  While executing gem ... (Gem::InstallError)
    boop is not installed in GEM_HOME, try:
        gem uninstall -i /usr/home/puppy/.local/share/gem/ruby/3.0.0 boop
puppy@orthrus.fox:~$ 

I also realized that the code I linked to before was not the area the error happens. This is the correct one:

if list.empty?
return unless other_repo_specs.any?
other_repos = other_repo_specs.map(&:base_dir).uniq
message = ["#{@gem} is not installed in GEM_HOME, try:"]
message.concat other_repos.map {|repo|
"\tgem uninstall -i #{repo} #{@gem}"
}
raise Gem::InstallError, message.join("\n")

It looks like that error has been there for 12 years: 7096384.

I'm not sure what's happening that's making install and uninstall behave so differently here.

@fd00
Copy link

fd00 commented Apr 28, 2023

Is ENV['HOME'] a symbolic link?

It seems to compare ENV['HOME']/.gem/ruby/x.y.z with File.realpath(ENV['HOME']/.gem/ruby/x.y.z) and cannot find the installation location correctly.

@duckinator
Copy link
Member Author

duckinator commented Apr 29, 2023

@fd00 ENV['HOME'] is /home/puppy, and /home is a symlink to /usr/home. (This is the default setup on FreeBSD.)

@fd00
Copy link

fd00 commented Apr 29, 2023

I am using a cygwin environment where ENV['HOME'] is a symbolic link.
I had the same problem.

After checking the contents of the variable, this comparison failed.

list, other_repo_specs = list.partition do |spec|
@gem_home == spec.base_dir ||
(@user_install && spec.base_dir == Gem.user_dir)
end

  • Gem.user_dir -> /home/puppy/.gem/ruby/x.y.z
  • spec.base_dir -> /usr/home/puppy/.gem/ruby/x.y.z

spec.base_dir is expanded with Gem::PathSupport.

The proper fix is still unknown to me.

@deivid-rodriguez
Copy link
Member

@duckinator I'm having a pass over related RubyGems issues and I found a repro for your problem and a potential fix at #7645. Ruby core specs are failing, I should look into that, but other than that seems fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants