Gemfile.lock 应按依赖项优先级而不是字母顺序排序

Gemfile.lock should sort via dependency priority rather than alphabetical order

由于我们无法访问 ruby​​gems 网站,我们计划通过 Chef cookbook 在本地解决 gems 及其依赖项。我们想在这个过程中添加一个 rakefile。 我们在Rakefile中遵循的过程如下

  1. 创建正确版本的 Gemfile (inspec)
  2. 捆绑安装
  3. 明白了 Gemfile.lock <== 这就是问题所在。它按字母顺序排序
  4. 我们需要创建一个有依赖关系的数组,这样循环安装gems才不会冲突。需要此数组来将流程自动化到未来版本。

创建的数组按照字母顺序排列导致安装时出错。

我们的Gemfile

source 'https://rubygems.org'

gem "inspec", "0.22.1"

当我们运行"bundle install"创建一个Gemfile.lock如下:

GEM
  remote: https://rubygems.org/
  specs:
    builder (3.2.2)
    coderay (1.1.1)
    diff-lcs (1.2.5)
    docker-api (1.26.2)
      excon (>= 0.38.0)
      json
    erubis (2.7.0)
    excon (0.49.0)
    ffi (1.9.10-x86-mingw32)
    gssapi (1.2.0)
      ffi (>= 1.0.1)
    gyoku (1.3.1)
      builder (>= 2.1.2)
    hashie (3.4.4)
    httpclient (2.8.0)
    inspec (0.22.1)
      hashie (~> 3.4)
      json (~> 1.8)
      method_source (~> 0.8)
      pry (~> 0)
      r-train (~> 0.12)
      rainbow (~> 2)
      rspec (~> 3)
      rspec-its (~> 1.2)
      rubyzip (~> 1.1)
      thor (~> 0.19)
    json (1.8.3)
    little-plugger (1.1.4)
    logging (2.1.0)
      little-plugger (~> 1.1)
      multi_json (~> 1.10)
    method_source (0.8.2)
    mixlib-shellout (2.2.6-universal-mingw32)
      win32-process (~> 0.8.2)
      wmi-lite (~> 1.0)
    multi_json (1.12.0)
    net-scp (1.2.1)
      net-ssh (>= 2.6.5)
    net-ssh (3.1.1)
    nori (2.6.0)
    pry (0.10.3)
      coderay (~> 1.1.0)
      method_source (~> 0.8.1)
      slop (~> 3.4)
    r-train (0.12.0)
      docker-api (~> 1.26.2)
      json (~> 1.8)
      mixlib-shellout (~> 2.0)
      net-scp (~> 1.2)
      net-ssh (>= 2.9, < 4.0)
      winrm (~> 1.6)
      winrm-fs (~> 0.3)
    rainbow (2.1.0)
    rspec (3.4.0)
      rspec-core (~> 3.4.0)
      rspec-expectations (~> 3.4.0)
      rspec-mocks (~> 3.4.0)
    rspec-core (3.4.4)
      rspec-support (~> 3.4.0)
    rspec-expectations (3.4.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.4.0)
    rspec-its (1.2.0)
      rspec-core (>= 3.0.0)
      rspec-expectations (>= 3.0.0)
    rspec-mocks (3.4.1)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.4.0)
    rspec-support (3.4.1)
    rubyntlm (0.6.0)
    rubyzip (1.2.0)
    slop (3.6.0)
    thor (0.19.1)
    win32-process (0.8.3)
      ffi (>= 1.0.0)
    winrm (1.8.1)
      builder (>= 2.1.2)
      gssapi (~> 1.2)
      gyoku (~> 1.0)
      httpclient (~> 2.2, >= 2.2.0.2)
      logging (>= 1.6.1, < 3.0)
      nori (~> 2.0)
      rubyntlm (~> 0.6.0)
    winrm-fs (0.4.2)
      erubis (~> 2.7)
      logging (>= 1.6.1, < 3.0)
      rubyzip (~> 1.1)
      winrm (~> 1.5)
    wmi-lite (1.0.0)

PLATFORMS
  x86-mingw32

DEPENDENCIES
  inspec (= 0.22.1)

BUNDLED WITH
   1.11.2

Rakefile:

require 'bundler'
require 'json/pure'

  parsed_Gemfile_lock = Bundler::LockfileParser.new( File.read(File.dirname(__FILE__) + "\Gemfile.lock"))

  # Print a Ruby Array
  parsed_Gemfile_lock.specs.each do |spec|
    gem_array = spec.to_s.split
    gem_name = gem_array[0]
    gem_version = gem_array[1]
    gem_version = gem_version.gsub(/[()]/,"'")
    print "'" + gem_name + "'=>" + gem_version + ", "
  end

结果:

'builder'=>'3.2.2', 'coderay'=>'1.1.1', 'diff-lcs'=>'1.2.5', 'docker-api'=>'1.26.2', 'erubis'=>'2.7.0', 'excon'=>'0.49.0', 'ffi'=>'1.9.10', 'gssapi'=>'1.2.0', 'gyoku'=>'1.3.1', 'hashie'=>'3.4.4', 'httpclient'=>'2.8.0', 'inspec'=>'0.22.1', 'json'=>'1.8.3', 'little-plugger'=>'1.1.4', 'logging'=>'2.1.0', 'method_source'=>'0.8.2', 'mixlib-shellout'=>'2.2.6', 'multi_json'=>'1.12.0', 'net-scp'=>'1.2.1', 'net-ssh'=>'3.1.1', 'nori'=>'2.6.0', 'pry'=>'0.10.3', 'r-train'=>'0.12.0', 'rainbow'=>'2.1.0', 'rspec'=>'3.4.0', 'rspec-core'=>'3.4.4', 'rspec-expectations'=>'3.4.0', 'rspec-its'=>'1.2.0', 'rspec-mocks'=>'3.4.1', 'rspec-support'=>'3.4.1', 'rubyntlm'=>'0.6.0', 'rubyzip'=>'1.2.0', 'slop'=>'3.6.0', 'thor'=>'0.19.1', 'win32-process'=>'0.8.3', 'winrm'=>'1.8.1', 'winrm-fs'=>'0.4.2', 'wmi-lite'=>'1.0.0',

通过厨师食谱执行时出错:

===============================================================================
Error executing action `upgrade` on resource 'chef_gem[inspec]'
================================================================================

Mixlib::ShellOut::ShellCommandFailed
------------------------------------
Expected process to exit with [0], but received '2'
---- Begin output of /opt/chef/embedded/bin/gem install /var/chef/cache/rubygems/inspec-0.22.1.gem -q --no-rdoc --no-ri -v "0.22.1" --local ----
STDOUT:
STDERR: ERROR:  Could not find a valid gem 'r-train' (~> 0.12) in any repository
---- End output of /opt/chef/embedded/bin/gem install /var/chef/cache/rubygems/inspec-0.22.1.gem -q --no-rdoc --no-ri -v "0.22.1" --local ----
Ran /opt/chef/embedded/bin/gem install /var/chef/cache/rubygems/inspec-0.22.1.gem -q --no-rdoc --no-ri -v "0.22.1" --local returned 2

让我知道这个问题是否有任何 alternate/easy 解决方案,或者指导我为这个过程创建合适的 Rakefile。

要像 45 步一样倒带,不如镜像下您需要的 gem (https://github.com/rubygems/rubygems-mirror),然后在本地主机上使用 gem serve 来安装它们。这似乎少了很多工作。

关于您的实际问题:您可以尝试询问 Bundler 维护者,但我可以向您保证,他们会以超出范围为由关闭问题,因为这不是锁定文件的用途。

我找到了替代解决方案。

namespace :gem_attribute_array do
desc 'Generate gems attribute array'
task :generate do
puts "Generating gems attribute array and downloading all the dependent gem packages to ./vendor/cache :"
result = Mixlib::ShellOut.new('bundle package')
result.run_command
result.stdout.split("\n").each do |line|
  if line =~ /Using / or line =~ /Installing / then
    str=line.split(" ")
    gem_name=str[1]
    gem_version=str[2]
    print "'" + gem_name + "'=>'" + gem_version + "', "
  end #if loop
end # foreach loop
puts "\n" #Dummy line
end  #task
end  #namespace