从Ruby内部使用bundler验证gem的版本

时间:2013-03-20 10:12:39

标签: ruby bundler

有没有办法在Ruby程序中验证我是否拥有最新版本的gem?也就是说,有没有办法以编程方式进行bundle outdated #{gemname}

我尝试查看bundler的源代码,但我找不到直截了当的方法。目前我正在这样做,这是脆弱,缓慢和如此不优雅:

IO.popen(%w{/usr/bin/env bundle outdated gemname}) do |proc|
  output = proc.readlines.join("\n")
  return output.include?("Your bundle is up to date!")
end

6 个答案:

答案 0 :(得分:6)

避免外部执行的方法:

对于bundler 1.2.x

require 'bundler/cli'

# intercepting $stdout into a StringIO
old_stdout, $stdout = $stdout, StringIO.new 

# running the same code run in the 'bundler outdated' utility
Bundler::CLI.new.outdated('rails')

# storing the output
output = $stdout.string 

# restoring $stdout
$stdout = old_stdout 

对于bundler 1.3.x

require 'bundler/cli'
require 'bundler/friendly_errors'

# let's cheat the CLI class with fake exit method
module Bundler
  class CLI 
    desc 'exit', 'fake exit' # this is required by Thor
    def exit(*); end         # simply do nothing
  end 
end

# intercepting $stdout into a StringIO
old_stdout, $stdout = $stdout, StringIO.new 

# running the same code run in the 'bundler outdated' utility
Bundler.with_friendly_errors { Bundler::CLI.start(['outdated', 'rails']) }

# storing the output
output = $stdout.string 

# restoring $stdout
$stdout = old_stdout     

答案 1 :(得分:4)

在bundler中没有以编程方式使用outdated命令,因为代码位于Thor CLI文件中,该文件将输出打印给用户。 Bundler的测试也向系统发出命令并检查输出(Link to outdated tests)。

编写自己的方法来反映cli.rb中的outdated方法正在做什么应该相当简单。请参阅此处突出显示的代码:Link to outdated method in Bundler source。删除Bundler.ui行,并根据out_count

的值返回true / false

更新:我已经提取了过时的'没有控制台输出和退出的可重用方法。你可以在这里找到要点:link to gist。我已经在bundler 1.3上测试了它,它似乎有效。

答案 2 :(得分:0)

bundle check列出过时的宝石,您可能想要使用它。

答案 3 :(得分:0)

嗯,听起来你可能想要bundle showgem env

答案 4 :(得分:0)

令人失望,这看起来非常困难。

捆绑工具中有几个open issues,官方行似乎是:

  

此时,没有记录的ruby API。   不过,这是我们名单上的内容。

查看bundler源代码cli.rb,很明显从ruby调用或以合理的方式重现代码会很棘手。

从CLI调用方法很困难,因为它们带有calls to exit

重现代码看起来并不好看,因为那里有很多捆绑逻辑。

祝你好运!

答案 5 :(得分:0)

检查最新bundler源代码的源代码

我能想出这个

https://github.com/carlhuda/bundler/blob/master/lib/bundler/cli.rb#L398

$ irb
1.9.3p327 :001 > require 'bundler'
 => true 
1.9.3p327 :002 > def outdated_gems(gem_name,options={})
1.9.3p327 :003?>   options[:source] ||= 'https://rubygems.org'
1.9.3p327 :004?>   sources = Array(options[:source])
1.9.3p327 :005?>   current_spec= Bundler.load.specs[gem_name].first
1.9.3p327 :006?>   raise "not found in Gemfile" if current_spec.nil?
1.9.3p327 :007?>   definition = Bundler.definition(:gems => [gem_name], :sources => sources)
1.9.3p327 :008?>   options["local"] ? definition.resolve_with_cache! : definition.resolve_remotely!
1.9.3p327 :009?>       active_spec = definition.index[gem_name].sort_by { |b| b.version }
1.9.3p327 :010?>    if !current_spec.version.prerelease? && !options[:pre] && active_spec.size > 1
1.9.3p327 :011?>             active_spec = active_spec.delete_if { |b| b.respond_to?(:version) && b.version.prerelease? }
1.9.3p327 :012?>         end
1.9.3p327 :013?>       active_spec = active_spec.last
1.9.3p327 :014?>       raise "Error" if active_spec.nil?
1.9.3p327 :015?>   outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version)
1.9.3p327 :016?>   {:outdated=>outdated,:current_spec_version=>current_spec.version.to_s,:latest_version=>active_spec.version.to_s}
1.9.3p327 :017?>   end
 => nil 
1.9.3p327 :018 > 
1.9.3p327 :019 >   
1.9.3p327 :020 >   
1.9.3p327 :021 >   
1.9.3p327 :022 >   outdated_gems('rake')
 => {:outdated=>true, :current_spec_version=>"10.0.3", :latest_version=>"10.0.4"} 

这可能不适用于早期版本的bundler。