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

Don't error out when activating a binstub unless necessary #4351

Merged

Conversation

deivid-rodriguez
Copy link
Member

@deivid-rodriguez deivid-rodriguez commented Feb 4, 2021

What was the end-user or developer problem that led to this PR?

When activating an executable from a gem, rubygems will find the spec corresponding to the rubygems binstub, it will then activate it, and they it will finish resolving all of its dependencies, and properly setting up the load path and activate them.

However, if during this process "orphaned gems" are detected (installed gems without valid dependencies installed), rubygems will crash with a very strange error, even if the orphan gem will not end up being activated and used in the end.

The error will look like this:

$ rails s
[138376, #<Thread:0x000055e5400bad58 run>, #<Gem::MissingSpecVersionError: Gem::MissingSpecVersionError>, ["/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/dependency.rb:309:in `to_specs'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2553:in `block in traverse'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `each'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `traverse'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1031:in `block in find_in_unresolved_tree'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `each'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `find_in_unresolved_tree'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:114:in `require'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'", "/home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'"]]
Traceback (most recent call last):
	12: from /home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'
	11: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'
	10: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'
	 9: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'
	 8: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'
	 7: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:114:in `require'
	 6: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `find_in_unresolved_tree'
	 5: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `each'
	 4: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1031:in `block in find_in_unresolved_tree'
	 3: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `traverse'
	 2: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `each'
	 1: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2553:in `block in traverse'
/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/dependency.rb:309:in `to_specs': Could not find 'mini_portile2' (~> 2.4.0) - did find: [mini_portile2-2.5.0] (Gem::MissingSpecVersionError)
Checked in 'GEM_PATH=/home/deivid/.gem/ruby/2.7.0:/home/deivid/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0' , execute `gem env` for more information
	6: from /home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'
	5: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'
	4: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'
	3: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'
	2: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'
	1: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:167:in `require'
/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:167:in `ensure in require': CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before false -> after true (RuntimeError)

What is your fix for the problem, implemented in this PR?

This is a really unhelpful error and in many cases, it's not necesary to raise it.

For example, in my case, the underlying problem was that I had this list of versions of nokogiri on my system:

$ gem list nokogiri

*** LOCAL GEMS ***

nokogiri (1.11.1 x86_64-linux, 1.11.0 x86_64-linux, 1.10.8, 1.10.1)

And one of them, 1.10.8, had orphaned dependencies:

$ gem specification nokogiri -v 1.10.8 --ruby|grep runtime_dependency.*mini_portile
    s.add_runtime_dependency(%q<mini_portile2>.freeze, ["~> 2.4.0"])

$ gem list mini_portile2

*** LOCAL GEMS ***

mini_portile2 (2.5.0)

This gem version is irrelevant to this case, since a higher version will be activated, so there's no need to crash with such a weird error.

Make sure the following tasks are checked

@deivid-rodriguez deivid-rodriguez force-pushed the avoid_unnecessary_activate_bin_path_crashes branch from 62f98c4 to 5c31c41 Compare February 4, 2021 18:31
When activating an executable from a gem, rubygems will find the spec
corresponding to the rubygems binstub, it will then activate it, and
they it will finish resolving all of its dependencies, and properly
setting up the load path and activate them.

However, if during this process "orphaned gems" are detected (installed
gems without valid dependencies installed), rubygems will crash with a
very strange error, even if the orphan gem will not end up being
activated and used in the end.

The error will look like this:

```
$ rails s
[138376, #<Thread:0x000055e5400bad58 run>, #<Gem::MissingSpecVersionError: Gem::MissingSpecVersionError>, ["/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/dependency.rb:309:in `to_specs'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2553:in `block in traverse'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `each'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `traverse'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1031:in `block in find_in_unresolved_tree'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `each'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `find_in_unresolved_tree'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:114:in `require'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'", "/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'", "/home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'"]]
Traceback (most recent call last):
	12: from /home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'
	11: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'
	10: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'
	 9: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'
	 8: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'
	 7: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:114:in `require'
	 6: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `find_in_unresolved_tree'
	 5: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1030:in `each'
	 4: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1031:in `block in find_in_unresolved_tree'
	 3: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `traverse'
	 2: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2551:in `each'
	 1: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:2553:in `block in traverse'
/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/dependency.rb:309:in `to_specs': Could not find 'mini_portile2' (~> 2.4.0) - did find: [mini_portile2-2.5.0] (Gem::MissingSpecVersionError)
Checked in 'GEM_PATH=/home/deivid/.gem/ruby/2.7.0:/home/deivid/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0' , execute `gem env` for more information
	6: from /home/deivid/.rbenv/versions/2.7.2/bin/rails:23:in `<main>'
	5: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `activate_bin_path'
	4: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:301:in `synchronize'
	3: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:303:in `block in activate_bin_path'
	2: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems.rb:236:in `finish_resolve'
	1: from /home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:167:in `require'
/home/deivid/.rbenv/versions/2.7.2/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:167:in `ensure in require': CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before false -> after true (RuntimeError)
```

In this case, the underlying problem is that I have this list of
versions of nokogiri on my system:

```
$ gem list nokogiri

*** LOCAL GEMS ***

nokogiri (1.11.1 x86_64-linux, 1.11.0 x86_64-linux, 1.10.8, 1.10.1)
```

And one of them, 1.10.8, has orphaned dependencies:

```
$ gem specification nokogiri -v 1.10.8 --ruby|grep runtime_dependency.*mini_portile
    s.add_runtime_dependency(%q<mini_portile2>.freeze, ["~> 2.4.0"])

$ gem list mini_portile2

*** LOCAL GEMS ***

mini_portile2 (2.5.0)
```

This gem version is irrelevant to this case, since a higher version will
be activated, so there's no need to crash with such a weird error.
@deivid-rodriguez deivid-rodriguez force-pushed the avoid_unnecessary_activate_bin_path_crashes branch from 5c31c41 to b5fcd71 Compare February 4, 2021 18:46
@deivid-rodriguez deivid-rodriguez merged commit be08d83 into master Feb 4, 2021
@deivid-rodriguez deivid-rodriguez deleted the avoid_unnecessary_activate_bin_path_crashes branch February 4, 2021 19:54
deivid-rodriguez added a commit that referenced this pull request Feb 8, 2021
…_path_crashes

Don't error out when activating a binstub unless necessary

(cherry picked from commit be08d83)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants