2013-03-20 83 views
10

有没有办法从Ruby程序中验证是否有最新版本的gem?也就是说,有没有办法以编程方式执行bundle outdated #{gemname}使用Ruby中的打包器验证gem的版本

我试着看着打包机的源代码,但我找不到一个简单的方法。目前,我这样做,这是脆弱的,速度慢等不雅:

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 
+0

谢谢大家,很多答案证实了我的发现:没有API来做到这一点。我选择了一个基于,它提供了一个工作的代码来完成这项任务。 – Pablo 2013-04-08 12:57:56

+0

我认为你选择的答案有一些问题。有一个'exit 1'会终止你的程序执行。你是否能够获得该代码的工作?尝试时发生错误。 – Emil 2013-04-09 20:49:35

+0

他们刚刚在版本1.2.x和1.3.x之间引入了'exit 1',所以现在需要一些猴子补丁来解决问题。 – 2013-04-09 21:50:40

回答

6

一种避免外部执行:

对于捆绑的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 

对于捆绑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  
+0

运行此错误时出现错误。另外,'过时'里面有一个鬼鬼祟祟的'出口1'。我不认为它可以这样工作。 – Emil 2013-04-09 20:45:51

+0

嗯。真正。它与bundler 1.2.3协同工作,并且与1.3.5一起工作。 – 2013-04-09 21:23:01

+0

我已经发布了1.3.5更新工作 – 2013-04-09 21:40:05

0

bundle check列表超出迄今为止的宝石,你可能想使用它。

+0

我的问题是关于从Ruby内部以编程方式运行它。 – Pablo 2013-03-20 11:49:10

3

还有就是用在打捆outdated命令没有编程的方式,因为该代码是在它打印输出给用户的CLI托尔文件。 Bundler的测试也将命令发布到系统并检查输出(Link to outdated tests)。

它应该是相当简单的写你自己的方法,以反映什么cli.rb的outdated方法是干什么的,虽然。请参阅突出显示的代码:Link to outdated method in Bundler source。与Bundler.ui删除线,并返回真/假基于out_count

更新的价值:我已经提取的“捆绑过时”到无控制台输出和退出可重复使用的方法。您可以在这里找到要点:link to gist。我已经在捆绑器1.3上测试过了,它似乎可行。

+0

不幸的是,这将最终成为以编程方式实现它的唯一真正方法。我很惊讶Bundler写得不好。根本不存在关注的分离; UI代码与版本检查逻辑完全交织在一起。看起来很伤心。 – 2013-04-05 23:36:50

+0

@JimStewart,我很确定他们会接受几个重构贡献。 – 2013-04-11 07:22:29

0

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

0

令人失望,这看起来相当困难。

有在捆绑几个openissues在官网上显示为:

在这个时间点,没有成文的红宝石API。不过,这是我们列表中的东西。

通过捆绑源代码cli.rb来看,这是相当清楚,这将是棘手的红宝石打电话,或以合理的方式再现的代码。

从CLI调用方法将很困难,因为他们洒了calls to exit

重现代码看起来并不好玩,因为那里有相当多的bundler逻辑。

祝你好运!

0

检查的最新捆绑源代码,源代码

我能想出这个

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"} 

这可能不是捆绑的早期版本。

相关问题