Reputation: 434
I'd like to clean a little system-house. Essentially,
(Gem.all_system_gems - Bundler.referenced_gems(array_of_gemfile_locks)).each do |gem, ver|
`gem uninstall #{gem} -v #{ver}
end
Any such RubyGems/Bundler methods? Or any known/efficient way of accomplishing the same?
Thanks, Ben
Upvotes: 3
Views: 1437
Reputation: 434
This code is based off of what @Kashyap answered (Bundler::LockfileParser is a good find). I ended up changing it a bit and wanted to share what I ended up using.
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
Primary differences are use of Gem::Specification.find_all and output to a shell script so I could review the gems before uninstalling. Oh, and still doing it the old-fashioned OO-way. :)
Leaving selected answer with @Kashyap. Props.
Upvotes: 0
Reputation: 4796
Caution: Severe brain-damage possible.
I put up a version here explaining each function.
# 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)
Why did I write this snippet this way? I happened to see this the other day: http://www.confreaks.com/videos/2382-rmw2013-functional-principles-for-oo-development
Upvotes: 3
Reputation: 518
Bundler has a clean
command to remove unused gems.
bundle clean --force
This will remove all gems that are not needed by the current project.
If you want to keep your system's gem repository clean you should consider using the --path
option with bundle install
. This will allow you to keep project dependencies outside of the system's gem repository.
Upvotes: 11
Reputation: 160551
If you're on *nix or Mac OS, you can put the names of the gems you want to remove in a text file. Then run this command:
xargs gem uninstall < path/to/text/file
xargs
is a great tool for processing long lists of files. In this case, it takes the contents of the text file, when its piped in via STDIN, and puts each line read into the command-line of gem uninstall
. It will continue to do that until the text file is exhausted.
Upvotes: 3