Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Gems defined with extensions dirs conflict with diff versions #5594

Closed
jules2689 opened this issue Apr 18, 2017 · 6 comments · Fixed by #5595
Closed

Gems defined with extensions dirs conflict with diff versions #5594

jules2689 opened this issue Apr 18, 2017 · 6 comments · Fixed by #5595
Milestone

Comments

@jules2689
Copy link
Contributor

Problem:

  • Using ruby version X, two projects define some gem at differing versions.
  • Stub Specification does not pass extension dir, which causes issues.

We saw this as

** Notice: CityHash was not loaded. **

For optimal performance, use of the cityhash gem is recommended.

Run the following command, or add it to your Gemfile:

gem install cityhash

Environment

Bundler   1.15.0.pre.1
Rubygems  2.6.11
Ruby      2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]
GEM_HOME  /Users/ryanmcilmoyl/.gem/ruby/2.3.3
GEM_PATH  /Users/ryanmcilmoyl/.gem/ruby/2.3.3:/opt/rubies/2.3.3/lib/ruby/gems/2.3.0
Git       2.11.0 (Apple Git-81)
Platform  x86_64-darwin-16

Bundler settings

jobs
  Set for your local app (/Users/ryanmcilmoyl/src/github.com/Shopify/shopify/.bundle/config): "4"

Relevant Gemfile

Shopify Project:

gem 'cityhash', git: 'csfrancis/cityhash', sha: 'XYZ'

Another Project

gem 'cityhash'

@segiddins
Copy link
Member

see lib/bundler/rubygems_ext.rb, we need that impl of extension_dir for the stub spec, just replacing rg_extension_dir with stub.extension_dir

@jules2689
Copy link
Contributor Author

To replicate:

Gemfile

source 'https://rubygems.org'
gem 'cityhash', git: 'https://github.com/csfrancis/cityhash.git', ref: '3cfc7d01f333c01811d5e834f1495eaa29f87c36'

test.rb

require 'bundler/setup'
puts $:.grep(/cityhash/)

Which outputs

/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/cityhash-3cfc7d01f333/lib
/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/extensions/x86_64-darwin-16/2.3.0-static/cityhash-0.6.0

That cityhash-0.6.0 should be a hash

@jules2689
Copy link
Contributor Author

Ok, so looking into this more, stub_specification doesn't know what full_name should be because we don't have a record of the source, so it resolves to cityhash-0.6.0 rather than cityhash-3cfc7d01f333

@jules2689
Copy link
Contributor Author

This seems to work:

diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index d89abd9..0f2ec9c 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -12,7 +12,7 @@ module Bundler

     attr_reader :name, :version, :platform
     attr_writer :dependencies
-    attr_accessor :source, :remote
+    attr_accessor :remote

     def initialize(name, version, platform, spec_fetcher)
       @name         = name
@@ -76,11 +76,6 @@ module Bundler
       @dependencies || method_missing(:dependencies)
     end

-    def git_version
-      return unless loaded_from && source.is_a?(Bundler::Source::Git)
-      " #{source.revision[0..6]}"
-    end
-
   private

     def to_ary
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index a0f8fa8..bc32d2e 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -23,6 +23,27 @@ require "bundler/match_platform"
 module Gem
   @loaded_stacks = Hash.new {|h, k| h[k] = [] }

+  class StubSpecification
+    attr_accessor :source
+
+    def git_version
+      return unless loaded_from && source.is_a?(Bundler::Source::Git)
+      " #{source.revision[0..6]}"
+    end
+
+    if method_defined?(:extension_dir)
+      alias_method :rg_extension_dir, :extension_dir
+      def extension_dir
+        @bundler_extension_dir ||= if git_version
+          ext_name = [name, git_version.strip].join('-')
+          File.expand_path(File.join(extensions_dir, ext_name))
+        else
+          rg_extension_dir
+        end
+      end
+    end
+  end
+
   class Specification
     attr_accessor :remote, :location, :relative_loaded_from

diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index bc1b18f..c0b6232 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -9,7 +9,12 @@ module Bundler
       spec
     end

-    attr_accessor :stub, :ignored
+    attr_accessor :stub, :ignored, :source
+
+    def source=(source)
+      stub.source = source
+      @source = source
+    end

@segiddins
Copy link
Member

We have a spec for extensions being usable, and I can't reproduce this issue...

@jules2689
Copy link
Contributor Author

jules2689 commented Apr 18, 2017

I think the specs don't cover all cases. Using #5594 (comment) between 1.14.6 and 1.15.0.pre.1, I get this:

~/src/github.com/Shopify/bund ➜ bundle exec ruby test.rb
1.14.6
/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/cityhash-3cfc7d01f333/lib
/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/extensions/x86_64-darwin-16/2.3.0-static/cityhash-3cfc7d01f333
~/src/github.com/Shopify/bund ➜ bundle exec ruby test.rb
1.15.0.pre.1
/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/cityhash-3cfc7d01f333/lib
/Users/juliannadeau/.gem/ruby/2.3.3/bundler/gems/extensions/x86_64-darwin-16/2.3.0-static/cityhash-0.6.0

bundlerbot added a commit that referenced this issue Apr 20, 2017
…giddins

Apply source and git_version to stub spec extension

Fixes #5594

`stub_specification` doesn't know what `full_name` should be because we don't have a record of the source, so it resolves to `cityhash-0.6.0` rather than `cityhash-3cfc7d01f333`

This makes `StubSpecification` aware of the source to we can still avoid loading the full spec when needed. This is done by bringing remote_specs `attr_accessor :source` to `stub_spec`, and assigning source to the `stub`.

I am probably missing some edge cases to check for though 🙈  Need to write specs.

cc @segiddins
segiddins pushed a commit that referenced this issue Apr 23, 2017
…giddins

Apply source and git_version to stub spec extension

Fixes #5594

`stub_specification` doesn't know what `full_name` should be because we don't have a record of the source, so it resolves to `cityhash-0.6.0` rather than `cityhash-3cfc7d01f333`

This makes `StubSpecification` aware of the source to we can still avoid loading the full spec when needed. This is done by bringing remote_specs `attr_accessor :source` to `stub_spec`, and assigning source to the `stub`.

I am probably missing some edge cases to check for though 🙈  Need to write specs.

cc @segiddins

(cherry picked from commit dcddaf9)
philipefarias added a commit to dleemoo/rc-images that referenced this issue Jun 12, 2017
Changes since last version used (1.14.6):

== 1.15.1 (2017-06-02)

Bugfixes:

  - `bundle lock --update GEM` will fail gracefully when the gem is not in the lockfile (rubygems/bundler#5693, @segiddins)
  - `bundle init --gemspec` will fail gracefully when the gemspec is invalid (@colby-swandale)
  - `bundle install --force` works when the gemfile contains git gems (rubygems/bundler#5678, @segiddins)
  - `bundle env` will print well-formed markdown when there are no settings (rubygems/bundler#5677, @segiddins)

== 1.15.0 (2017-05-19)

This space intentionally left blank.

== 1.15.0.pre.4 (2017-05-10)

Bugfixes:

  - avoid conflicts when `Gem.finish_resolve` is called after the bundle has been set up (@segiddins)
  - ensure that `Gem::Specification.find_by_name` always returns an object that can have `#to_spec` called on it (rubygems/bundler#5592, @jules2689)

== 1.15.0.pre.3 (2017-04-30)

Bugfixes:

  - avoid redundant blank lines in the readme generated by `bundle gem` (@koic)
  - ensure that `open-uri` is not loaded after `bundle exec` (@segiddins)
  - print a helpful error message when an activated default gem conflicts with
    a gem in the gemfile (@segiddins)
  - only shorten `ref` option for git gems when it is a SHA (rubygems/bundler#5620, @segiddins)

== 1.15.0.pre.2 (2017-04-23)

Bugfixes:

  - ensure pre-existing fit caches are updated from remote sources (rubygems/bundler#5423, @alextaylor000)
  - avoid duplicating specs in the lockfile after updating with the gem uninstalled (rubygems/bundler#5599, @segiddins)
  - ensure git gems have their extensions available at runtime (rubygems/bundler#5594, @jules2689, @segiddins)

== 1.15.0.pre.1 (2017-04-16)

Features:

  - print a notification when a newer version of bundler is available (rubygems/bundler#4683, @segiddins)
  - add man pages for all bundler commands (rubygems/bundler#4988, @feministy)
  - add the `bundle info` command (@fredrb, @colby-swandale)
  - all files created with `bundle gem` comply with the bundler style guide (@zachahn)
  - if installing a gem fails, print out the reason the gem needed to be installed (rubygems/bundler#5078, @segiddins)
  - allow setting `gem.push_key` to set the key used when running `rake release` (@DTrierweiler)
  - print gem versions that are regressing during `bundle update` in yellow (rubygems/bundler#5506, @brchristian)
  - avoid printing extraneous dependencies when the resolver encounters a conflict (@segiddins)
  - add the `bundle issue` command that prints instructions for reporting issues (rubygems/bundler#4871, @jonathanpike)
  - add `--source` and `--group` options to the `bundle inject` command (rubygems/bundler#5452, @Shekharrajak)
  - add the `bundle add` command to add a gem to the gemfile (@denniss)
  - add the `bundle pristine` command to re-install gems from cached `.gem` files (rubygems/bundler#4509, @denniss)
  - add a `--parseable` option for `bundle config` (@JuanitoFatas, @colby-swandale)

Performance:

  - speed up gemfile initialization by storing locked dependencies as a hash (@jules2689)
  - speed up gemfile initialization by making locked dependency comparison lazy, avoiding object allocation (@jules2689)
  - only validate git gems when they are downloaded, instead of every time `Bundler.setup` is run (@segiddins)
  - avoid regenerating the lockfile when nothing has changed (@segiddins)
  - avoid diffing large arrays when no sources in the gemfile have changed (@segiddins)
  - avoid evaluating full gemspecs when running with RubyGems 2.5+ (@segiddins)

Bugfixes:

  - fix cases where `bundle update` would print a resolver conflict instead of updating the selected gems (rubygems/bundler#5031, rubygems/bundler#5095, @segiddins)
  - print out a stack trace after an interrupt when running in debug mode (@segiddins)
  - print out when bundler starts fetching a gem from a remote server (@segiddins)
  - fix `bundle gem` failing when `git` is unavailable (rubygems/bundler#5458, @Shekharrajak, @colby-swandale)
  - suggest the appropriate command to unfreeze a bundle (rubygems/bundler#5009, @denniss)
  - ensure nested calls to `bundle exec` resolve default gems correctly (rubygems/bundler#5500, @segiddins)
  - ensure that a plugin failing to install doesn't uninstall other plugins (@kerrizor, @roseaboveit)
  - ensure `socket` is required before being referenced (rubygems/bundler#5533, @rafaelfranca)
  - allow running `bundle outdated` when gems aren't installed locally (rubygems/bundler#5553, @segiddins)
  - print a helpful error when `bundle exec`ing to a gem that isn't included in the bundle (rubygems/bundler#5487, @segiddins)
  - print an error message when a non-git gem is given a `branch` option (rubygems/bundler#5530, @colby-swandale)
  - allow interrupts to exit the process after gems have been installed (@segiddins)
  - print the underlying error when downloading gem metadata fails (rubygems/bundler#5579, @segiddins)
  - avoid deadlocking when installing with a lockfile that is missing dependencies (rubygems/bundler#5378, rubygems/bundler#5480, rubygems/bundler#5519, rubygems/bundler#5526, rubygems/bundler#5529, rubygems/bundler#5549, rubygems/bundler#5572, @segiddins)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants