为什么bundler使用多个gem位置?

时间:2020-12-14 16:47:06

This is happening in Puppet's bundle.

这发生在Puppet的捆绑中。

The Gemfile specifies

Gemfile指定

gem "puppet", :path => File.dirname(__FILE__), :require => false

But one of the gems I installed in $GEM_HOME appears in $: after all.

但是我在$ GEM_HOME中安装的其中一个宝石出现在$:中。

$ bundle exec ruby -e 'puts $:'
...
/home/puppy/puppet-git-clone/lib
...
/usr/lib/ruby/vendor_ruby
...
/home/puppy/gems/gems/puppet-3.7.5/lib
...

This is not a problem in and of itself, but apparently Ruby will load Puppet 3.7.5 instead of the 3.7.3 I checked out of the git repo.

这本身并不是问题,但显然Ruby会加载Puppet 3.7.5而不是3.7.3我检出git repo。

$ bundle exec irb
irb(main):001:0> require 'puppet'
=> true
irb(main):002:0> Facter.value(:puppetversion)
=> "3.7.5"

Why is Puppet not loaded from the git tree and how can I debug this further?

为什么Puppet没有从git树加载,我该如何进一步调试呢?

Update

Puppets .gemspec might be involved. It's clever about specifying the version. I now worry that Rubygems does in fact load the installed 3.7.5 gem so that Puppet.version would truthfully report a wrong value, throwing off bundler. Could that be what's happening?

Puppets .gemspec可能会参与其中。它在指定版本方面很聪明。我现在担心Rubygems实际上会加载已安装的3.7.5 gem,以便Puppet.version真实地报告错误的值,抛弃bundler。这可能是发生了什么?

Update 2

As suggested in the comments, I tried settings the path and version statically in the Gemfile.

正如评论中所建议的那样,我尝试在Gemfile中静态设置路径和版本。

gem "puppet", "3.4.2", :path => "/home/puppy/puppet-git-clone", :require => false

As for the result, well - at least bundler is consistent in its views ;-)

至于结果,好 - 至少捆绑在其观点中是一致的;-)

Could not find gem 'puppet (= 3.4.2) ruby' in source at /home/ffrank/git/puppet.
Source contains 'puppet' at: 3.7.3
Run `bundle install` to install missing gems.

6 个解决方案

#1


4  

The quick fix is to add -Ilib to your ruby command:

快速解决方法是将-Ilib添加到ruby命令:

$ bundle exec ruby -e "require 'puppet'; puts Facter.value(:puppetversion)"
3.7.5

$ bundle exec ruby -Ilib -e "require 'puppet'; puts Facter.value(:puppetversion)"
3.7.3

If we compare the load paths, you can see that adding -Ilib results in 3.7.5 not being present in the second load path:

如果我们比较加载路径,您可以看到添加-Ilib导致3.7.5不存在于第二个加载路径中:

$ diff <(bundle exec ruby -e 'puts $:') <(bundle exec ruby -Ilib -e 'puts $:') | grep 'puppet-'
< /Library/Ruby/Gems/2.0.0/gems/puppet-3.7.5/lib

It seems like this should be the default behavior, so there may be a bug in bundler.

看起来这应该是默认行为,因此捆绑器中可能存在错误。

#2


1  

Provided you've deleted your Gemfile.lock and removed all other versions of the gem before trying bundle exec ... although not explicitly defined by the same problem, this is a known problem with Bundler check this out:

如果你在尝试捆绑exec之前删除了你的Gemfile.lock并删除了所有其他版本的gem ...虽然没有明确定义同一个问题,但这是Bundler的一个已知问题检查出来:

And it ought to be fixed as of this merged Pull Request:

并且应该在此合并的Pull请求中修复:

This will cause your "preferred source" to be favored, and used.

这将使您的“首选来源”受到青睐和使用。

( Links used as answer because this refers to existing activities, not a solution I could put here in the answer. Not link-only answer. )

(链接用作答案,因为这是指现有活动,而不是我可以在答案中提供的解决方案。不是仅链接答案。)

#3


1  

try this :

尝试这个 :

source "file://home/puppy/puppet-git-clone"

gem "puppet", "3.4.2", :path => "/home/puppy/puppet-git-clone"

why do you need require false?

为什么你需要虚假?

#4


1  

After what you said in my previous answer, try this:

在你之前的回答中说了之后,试试这个:

Add gemspec to your Gemfile near the top.

If you do this, the subsequent gem ... calls will override the gemspec which is ultimately setting the version.

如果你这样做,后续的gem ...调用将覆盖最终设置版本的gemspec。

Add it right here:

source ENV['GEM_SOURCE'] || "https://rubygems.org"
gemspec # and let me know if this fixes it

#5


1  

Like I recently said, I found the same problem you had, in my own projects. And I've solved it by a workaround. The idea itself is what I'm giving here, I'm not saying it's the most efficient or bug-free way. A variation of this approach worked for me.

就像我最近说的那样,我在自己的项目中发现了同样的问题。我通过解决方法解决了这个问题。这个想法本身就是我在这里给出的,我并不是说它是最有效或无错误的方式。这种方法的一种变体对我有用。

It involves hijacking Gemfile and perhaps gemspec, depending on what's the offender in reality -- that part is still unknown. My most recent answer, the second approach I gave could solve this already. If not, you may need a workaround. There are many standing impasses for Bundler.

它涉及劫持Gemfile和gemspec,取决于现实中的罪犯 - 该部分仍然是未知的。我最近的回答,我给出的第二种方法可以解决这个问题。如果没有,您可能需要一个解决方法。 Bundler有许多常见的僵局。


As a work around, insert a curator.

I suggest, at the end of Gemfile you insert a processor such as this one, to curate Bundler::Dsl yourself. We can focus completely on the gem you're looking to resolve, but it could be done for any and all gems.

我建议,在Gemfile的末尾插入一个像这样的处理器来自己策划Bundler :: Dsl。我们可以完全专注于你想要解决的宝石,但它可以为任何和所有宝石完成。

For example... this is mostly a concept, it may run, but it may have a bug. You will need to harden it. This will remove everything but the version you expect:

例如......这主要是一个概念,它可能会运行,但它可能有一个bug。你需要强化它。除了您期望的版本之外,这将删除所有内容:

PUPPET_VERSION = 'version desired'
until(current = self.dependencies.find { |d| d.name == 'puppet' }) == 1
    current.each { |gem|
        if !gem.version == PUPPET_VERSION
            self.dependencies.delete(current)
        end
    }
end

I'm not sure which version you actually want. There are three versions mentioned, 3.7.3, 3.7.5 ... just plug in the one you do want. Any other versions will be purged from the dependencies Bundler is working with.

我不确定你真正想要的版本。提到了三个版本,3.7.3,3.7.5 ...只需插入您想要的版本。将从Bundler正在使用的依赖项中清除任何其他版本。

#6


1  

I had the same problem in past, I think you can specify your gem without the 'require: false' parameter and it will look for the Gemfile specific version.

我过去遇到了同样的问题,我认为你可以在没有'require:false'参数的情况下指定你的gem,它会查找特定于Ge​​mfile的版本。

gem "puppet", "3.4.2", :path => "/home/puppy/puppet-git-clone"

If you specify the 'require' option with 'gem' and run the irb command with bundle exec irb it always load the latest version for the gems which has declared with require: false option.

如果使用'gem'指定'require'选项并使用bundle exec irb运行irb命令,它总是加载已使用require:false选项声明的gem的最新版本。

#1


4  

The quick fix is to add -Ilib to your ruby command:

快速解决方法是将-Ilib添加到ruby命令:

$ bundle exec ruby -e "require 'puppet'; puts Facter.value(:puppetversion)"
3.7.5

$ bundle exec ruby -Ilib -e "require 'puppet'; puts Facter.value(:puppetversion)"
3.7.3

If we compare the load paths, you can see that adding -Ilib results in 3.7.5 not being present in the second load path:

如果我们比较加载路径,您可以看到添加-Ilib导致3.7.5不存在于第二个加载路径中:

$ diff <(bundle exec ruby -e 'puts $:') <(bundle exec ruby -Ilib -e 'puts $:') | grep 'puppet-'
< /Library/Ruby/Gems/2.0.0/gems/puppet-3.7.5/lib

It seems like this should be the default behavior, so there may be a bug in bundler.

看起来这应该是默认行为,因此捆绑器中可能存在错误。

#2


1  

Provided you've deleted your Gemfile.lock and removed all other versions of the gem before trying bundle exec ... although not explicitly defined by the same problem, this is a known problem with Bundler check this out:

如果你在尝试捆绑exec之前删除了你的Gemfile.lock并删除了所有其他版本的gem ...虽然没有明确定义同一个问题,但这是Bundler的一个已知问题检查出来:

And it ought to be fixed as of this merged Pull Request:

并且应该在此合并的Pull请求中修复:

This will cause your "preferred source" to be favored, and used.

这将使您的“首选来源”受到青睐和使用。

( Links used as answer because this refers to existing activities, not a solution I could put here in the answer. Not link-only answer. )

(链接用作答案,因为这是指现有活动,而不是我可以在答案中提供的解决方案。不是仅链接答案。)

#3


1  

try this :

尝试这个 :

source "file://home/puppy/puppet-git-clone"

gem "puppet", "3.4.2", :path => "/home/puppy/puppet-git-clone"

why do you need require false?

为什么你需要虚假?

#4


1  

After what you said in my previous answer, try this:

在你之前的回答中说了之后,试试这个:

Add gemspec to your Gemfile near the top.

If you do this, the subsequent gem ... calls will override the gemspec which is ultimately setting the version.

如果你这样做,后续的gem ...调用将覆盖最终设置版本的gemspec。

Add it right here:

source ENV['GEM_SOURCE'] || "https://rubygems.org"
gemspec # and let me know if this fixes it

#5


1  

Like I recently said, I found the same problem you had, in my own projects. And I've solved it by a workaround. The idea itself is what I'm giving here, I'm not saying it's the most efficient or bug-free way. A variation of this approach worked for me.

就像我最近说的那样,我在自己的项目中发现了同样的问题。我通过解决方法解决了这个问题。这个想法本身就是我在这里给出的,我并不是说它是最有效或无错误的方式。这种方法的一种变体对我有用。

It involves hijacking Gemfile and perhaps gemspec, depending on what's the offender in reality -- that part is still unknown. My most recent answer, the second approach I gave could solve this already. If not, you may need a workaround. There are many standing impasses for Bundler.

它涉及劫持Gemfile和gemspec,取决于现实中的罪犯 - 该部分仍然是未知的。我最近的回答,我给出的第二种方法可以解决这个问题。如果没有,您可能需要一个解决方法。 Bundler有许多常见的僵局。


As a work around, insert a curator.

I suggest, at the end of Gemfile you insert a processor such as this one, to curate Bundler::Dsl yourself. We can focus completely on the gem you're looking to resolve, but it could be done for any and all gems.

我建议,在Gemfile的末尾插入一个像这样的处理器来自己策划Bundler :: Dsl。我们可以完全专注于你想要解决的宝石,但它可以为任何和所有宝石完成。

For example... this is mostly a concept, it may run, but it may have a bug. You will need to harden it. This will remove everything but the version you expect:

例如......这主要是一个概念,它可能会运行,但它可能有一个bug。你需要强化它。除了您期望的版本之外,这将删除所有内容:

PUPPET_VERSION = 'version desired'
until(current = self.dependencies.find { |d| d.name == 'puppet' }) == 1
    current.each { |gem|
        if !gem.version == PUPPET_VERSION
            self.dependencies.delete(current)
        end
    }
end

I'm not sure which version you actually want. There are three versions mentioned, 3.7.3, 3.7.5 ... just plug in the one you do want. Any other versions will be purged from the dependencies Bundler is working with.

我不确定你真正想要的版本。提到了三个版本,3.7.3,3.7.5 ...只需插入您想要的版本。将从Bundler正在使用的依赖项中清除任何其他版本。

#6


1  

I had the same problem in past, I think you can specify your gem without the 'require: false' parameter and it will look for the Gemfile specific version.

我过去遇到了同样的问题,我认为你可以在没有'require:false'参数的情况下指定你的gem,它会查找特定于Ge​​mfile的版本。

gem "puppet", "3.4.2", :path => "/home/puppy/puppet-git-clone"

If you specify the 'require' option with 'gem' and run the irb command with bundle exec irb it always load the latest version for the gems which has declared with require: false option.

如果使用'gem'指定'require'选项并使用bundle exec irb运行irb命令,它总是加载已使用require:false选项声明的gem的最新版本。