卸载不在指定的Gemfile.lock文件列表中的所有gem

时间:2013-05-10 06:15:53

标签: ruby rubygems bundler

我想清理一个小系统。从本质上讲,

(Gem.all_system_gems - Bundler.referenced_gems(array_of_gemfile_locks)).each do |gem, ver|
  `gem uninstall #{gem} -v #{ver}
end

任何这样的RubyGems / Bundler方法?或者任何已知/有效的方法来实现它?

谢谢, 本

4 个答案:

答案 0 :(得分:8)

Bundler有一个clean命令可以删除未使用的宝石。

bundle clean --force

这将删除当前项目不需要的所有宝石。

如果您希望保持系统的gem存储库清洁,则应考虑将--path选项与bundle install一起使用。这将允许您将项目依赖项保留在系统的gem存储库之外。

答案 1 :(得分:3)

如果您使用的是* nix或Mac OS,则可以将要删除的宝石的名称放在文本文件中。然后运行以下命令:

xargs gem uninstall < path/to/text/file

xargs是处理长文件列表的绝佳工具。在这种情况下,它通过STDIN管道传输文本文件的内容,并将每行读入gem uninstall的命令行。它将继续这样做,直到文本文件用完为止。

答案 2 :(得分:3)

警告:可能造成严重的脑损伤。

I put up a version here解释每个功能。


# gem_cleaner.rb

require 'bundler'

`touch Gemfile` unless File.exists?("Gemfile")

dot_lockfiles = [ "/path/to/gemfile1.lock", "/path/to/gemfile2.lock" 
  # ..and so on...
]

lockfile_parser = ->(path) do
  Bundler::LockfileParser.new(File.read(path))
end

lockfile_specs = ->(lockfile) { lockfile.specs.map(&:to_s) }

de_parenthesize = ->(string) { string.gsub(/\,|\(|\)/, "") }

uninstaller = ->(string) do
  `gem uninstall #{string.split(" ").map(&de_parenthesize).join(" -v ")}`
end

splitter = ->(string) do
  temp = string.split(" ").map(&de_parenthesize)
  gem_name = temp.shift
  temp.map {|x| "#{gem_name} (#{x})"}
end

# Remove #lazy and #to_a if on Ruby version < 2.0
gems_to_be_kept    = dot_lockfiles.lazy.map(&lockfile_parser).map(&lockfile_specs).to_a.uniq
all_installed_gems = `gem list`.split("\n").map(&splitter).flatten
gems_to_be_uninstalled = all_installed_gems - gems_to_be_kept
gems_to_be_uninstalled.map(&uninstaller)

为什么我这样写这个片段?前几天我碰巧看到了这个:http://www.confreaks.com/videos/2382-rmw2013-functional-principles-for-oo-development

答案 3 :(得分:0)

此代码基于@Kashyap所回答的内容(Bundler :: LockfileParser是一个很好的查找)。我最后改变了一点,想分享我最终使用的东西。

require 'rubygems'
require 'bundler'

LOCK_FILES = %w(/path/to/first/Gemfile.lock /path/to/second/Gemfile.lock)
REVIEWABLE_SHELL_SCRIPT = 'gem_cleaner.csh'

class GemCleaner
  def initialize lock_files, output_file
    @lock_files = lock_files
    @output_file = output_file
  end
  def lock_file_gems
    @lock_files.map do |lock_file| 
      Bundler::LockfileParser.new(File.read(lock_file)).specs.
        map {|s| [s.name, s.version.version] } 
    end.flatten(1).uniq
  end
  def installed_gems
    Gem::Specification.find_all.map {|s| [s.name, s.version.version] }
  end
  def gems_to_uninstall
    installed_gems - lock_file_gems
  end
  def create_shell_script
    File.open(@output_file, 'w', 0744) do |f|
      f.puts "#!/bin/csh"
      gems_to_uninstall.sort.each {|g| f.puts "gem uninstall #{g[0]} -v #{g[1]}" }
    end
  end
end

gc = GemCleaner.new(LOCK_FILES, REVIEWABLE_SHELL_SCRIPT)
gc.create_shell_script

主要区别是使用Gem :: Specification.find_all并输出到shell脚本,因此我可以在卸载前查看gem。哦,仍然是老式的OO方式。 :)

用@Kashyap留下选定的答案。道具。