Ruby Bundler。如何使用Gemfile.lock中的工作集锁定Gemfile中的所有版本?

Ruby Bundler。如何使用Gemfile.lock中的工作集锁定Gemfile中的所有版本?,ruby,bundler,Ruby,Bundler,我想将我的Gemfile设置为使用工作Gemfile.lock中的所有精确版本 最简单的方法是什么 我不想手动操作。bundler是否开箱即用。如果没有,是否有一个宝石呢 为了澄清,我有一个如下的Gemfile: source 'https://rubygems.org' gem 'pg' gem 'puma' gem 'rails' 我运行bundle install,得到一个适用于我的Gemfile.lock: GEM remote: https://rubygems.org/

我想将我的
Gemfile
设置为使用工作
Gemfile.lock
中的所有精确版本

最简单的方法是什么

我不想手动操作。
bundler
是否开箱即用。如果没有,是否有一个宝石呢

为了澄清,我有一个如下的
Gemfile

source 'https://rubygems.org'

gem 'pg'
gem 'puma'
gem 'rails'
我运行
bundle install
,得到一个适用于我的
Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:
    pg (0.21.0)
    puma (3.10.0)
    rails (5.0.5)
      actioncable (= 5.0.5)
      actionmailer (= 5.0.5)
      actionpack (= 5.0.5)
      actionview (= 5.0.5)
      activejob (= 5.0.5)
      activemodel (= 5.0.5)
      activerecord (= 5.0.5)
      activesupport (= 5.0.5)
      bundler (>= 1.3.0)
      railties (= 5.0.5)
      sprockets-rails (>= 2.0.0)
现在我需要一个命令来更新我的
Gemfile
,以便指定版本:

source 'https://rubygems.org'

gem 'pg', '0.21.0'
gem 'puma', '3.10.0'
gem 'rails', '5.0.5' 

如果您试图在另一个项目的
Gemfile
中复制当前的
Gemfile.lock
,则可以指定gems的确切版本

假设我的Rails应用程序中有以下
Gemfile

source 'https://rubygems.org'

gem 'pg', '~> 0.18'
gem 'puma', '~> 3.0'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1' 
它生成以下
Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:
    pg (0.21.0)
    puma (3.10.0)
    rails (5.0.5)
      actioncable (= 5.0.5)
      actionmailer (= 5.0.5)
      actionpack (= 5.0.5)
      actionview (= 5.0.5)
      activejob (= 5.0.5)
      activemodel (= 5.0.5)
      activerecord (= 5.0.5)
      activesupport (= 5.0.5)
      bundler (>= 1.3.0)
      railties (= 5.0.5)
      sprockets-rails (>= 2.0.0)
如果我想在新项目中再现完全相同的情况,我将创建一个具有精确版本的Gemfile:

source 'https://rubygems.org'

gem 'pg', '0.21.0'
gem 'puma', '3.10.0'
gem 'rails', '5.0.5'
等等

你可以参考

编辑 在您更改了问题的焦点之后,似乎您正在尝试从
Gemfile.lock
创建
Gemfile

你可以看看。我看到了几个关于输出的问题

因此,如果不是100%令人满意,您可以使用
Bundler::LockfileParser
并编写自己的脚本,例如:

# test.rb
require 'bundler'

lockfile = Bundler::LockfileParser.new(Bundler.read_file('Gemfile.lock'))

specs = lockfile.specs
gems_hash = Hash.new.tap do |h|
  specs.each do |s|
    h[s.name] = {
      spec: s,
      dependencies: s.dependencies.map(&:name)
    }
  end
end

dependencies = gems_hash.keys && gems_hash.values.map { |h| h[:dependencies] }.flatten.uniq.sort

# Remove from the new Gemfile all gems installed as dependencies
dependencies.each { |dep| gems_hash.delete(dep) }

relevant_specs = gems_hash.values.map { |h| h[:spec] }

# I assume that by default you are installing from rubygems
puts "source 'https://rubygems.org'"
puts

relevant_specs.each do |s|
  if s.source.to_s =~ /https:\/\/rubygems.org/
    puts "gem '#{s.name}', '#{s.version}'" # eventually add "plaftform: :#{s.platform}"
  # I consider as only alternative a git source. 
  elsif s.source.is_a?(Bundler::Source::Git)
    uri = s.source.uri
    branch = s.source.branch
    ref = s.source.ref
    puts
    puts "git '#{uri}', branch: '#{branch}', ref: :#{ref} do"
    puts "  gem '#{s.name}'"
    puts "end"
    puts
  end
end
puts
我创建这个是为了方便阅读

然后,您可以通过运行以下命令创建
Gemfile

$ ruby test.rb > Gemfile

你可以自己写:)

result=“”
File.readlines(“Gemfile”)。每个do |行|
如果行.strip.以?(“gem”)和开头&!行。包括?(“,”)
name=line.match(/gem'(.+)'/)[1]
输出=`bundle info#{name}`
version=output.match(/#{name}\(.+)\)/)[1]

结果要查看gem文件格式的gem名称和版本,请参见

捆绑秀

在linux上,我使用这个快速而肮脏的代码片段将其转换为一种可以复制到文件上的格式


bundle show | ruby-ne"put$\.gsub(/\*/,“gem\”).gsub(/\(/,“\”,“\”,\“~>”).gsub(/\)/,“\”)

也许你也可以解释一下你为什么要这么做?@Kris通过改变我的问题澄清了这一点。我唯一能想到的办法是删除所有非父级gem(例如
actioncable
等)在
spec
键下,然后进行一些查找/替换以将其转换为正确的格式。
bundle auto update
似乎接近我需要的格式,但它对我不起作用。你肯定应该使用它,而不是一些手工制作的解析器。这是由bundler本身实现的,用于读取
.lock
文件。这需要一些可能性,但我相信你会通过这个答案来澄清我的问题。我从没有指定特定版本的文件开始。嘿,大卫,如果这是你问题的答案,你能把它标记为已解决吗?或者如果有帮助的话,至少提供一次投票?这并不能解决我的问题。从你的尝试中我可以看出我的问题并不清楚。所以我认为这值得一试:)然后你需要解析Gemfile.lock来生成一个具有固定gem版本的新Gemfile吗?太棒了!我很感激。而且有人做了一个单行线!
result = ""
File.readlines("Gemfile").each do |line|
  if line.strip.start_with?("gem") && !line.include?(",")
    name = line.match(/gem '(.+)'/)[1]
    output = `bundle info #{name}`
    version = output.match(/#{name} \((.+)\)/)[1]
    result << "  " if line.start_with?("  ")
    result << "gem '#{name}', '#{version}'\n"
  else
    result << line
  end
end
puts result