summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-01-04 22:58:15 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-01-04 22:58:15 +0000
commitda9fe1c4528ef8b25f099345428a30b99bdf76ee (patch)
tree7aeee6685ce3535f6c15114bcd67b14d0a56ad84 /lib
parent1b82e0776c26136d5dd121e969d8d73d261cb42e (diff)
* lib/rubygems/commands/cleanup_command.rb: Clean all possible gems
using multiple passes. Fixes RubyGems bug #422. Refactored for maintainability. * test/rubygems/test_gem_commands_cleanup_command.rb: Test for above. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38698 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/rubygems/commands/cleanup_command.rb148
1 files changed, 98 insertions, 50 deletions
diff --git a/lib/rubygems/commands/cleanup_command.rb b/lib/rubygems/commands/cleanup_command.rb
index a7071ce679..61f189e449 100644
--- a/lib/rubygems/commands/cleanup_command.rb
+++ b/lib/rubygems/commands/cleanup_command.rb
@@ -12,6 +12,14 @@ class Gem::Commands::CleanupCommand < Gem::Command
add_option('-d', '--dryrun', "") do |value, options|
options[:dryrun] = true
end
+
+ @candidate_gems = nil
+ @default_gems = []
+ @full = nil
+ @gems_to_cleanup = nil
+ @original_home = nil
+ @original_path = nil
+ @primary_gems = nil
end
def arguments # :nodoc:
@@ -38,79 +46,119 @@ are not removed.
def execute
say "Cleaning up installed gems..."
- primary_gems = {}
- Gem::Specification.each do |spec|
- if primary_gems[spec.name].nil? or
- primary_gems[spec.name].version < spec.version then
- primary_gems[spec.name] = spec
+ if options[:args].empty? then
+ done = false
+ last_set = nil
+
+ until done do
+ clean_gems
+
+ this_set = @gems_to_cleanup.map { |spec| spec.full_name }.sort
+
+ done = this_set.empty? || last_set == this_set
+
+ last_set = this_set
end
+ else
+ clean_gems
end
- candidate_gems = unless options[:args].empty? then
- options[:args].map do |gem_name|
- Gem::Specification.find_all_by_name gem_name
- end.flatten
- else
- Gem::Specification.to_a
- end
-
- gems_to_cleanup = candidate_gems.select { |spec|
- !spec.default_gem? and
- primary_gems[spec.name].version != spec.version
- }
+ say "Clean Up Complete"
- full = Gem::DependencyList.from_specs
+ if Gem.configuration.really_verbose then
+ skipped = @default_gems.map { |spec| spec.full_name }
+
+ say "Skipped default gems: #{skipped.join ', '}"
+ end
+ end
+
+ def clean_gems
+ get_primary_gems
+ get_candidate_gems
+ get_gems_to_cleanup
+
+ @full = Gem::DependencyList.from_specs
deplist = Gem::DependencyList.new
- gems_to_cleanup.uniq.each do |spec| deplist.add spec end
+ @gems_to_cleanup.each do |spec| deplist.add spec end
+
+ deps = deplist.strongly_connected_components.flatten
- deps = deplist.strongly_connected_components.flatten.reverse
+ @original_home = Gem.dir
+ @original_path = Gem.path
- original_home = Gem.dir
- original_path = Gem.path
+ deps.reverse_each do |spec|
+ uninstall_dep spec
+ end
- deps.each do |spec|
- next unless full.ok_to_remove?(spec.full_name)
+ Gem::Specification.reset
+ end
- if options[:dryrun] then
- say "Dry Run Mode: Would uninstall #{spec.full_name}"
- else
- say "Attempting to uninstall #{spec.full_name}"
+ def get_candidate_gems
+ @candidate_gems = unless options[:args].empty? then
+ options[:args].map do |gem_name|
+ Gem::Specification.find_all_by_name gem_name
+ end.flatten
+ else
+ Gem::Specification.to_a
+ end
+ end
- options[:args] = [spec.name]
+ def get_gems_to_cleanup
+ gems_to_cleanup = @candidate_gems.select { |spec|
+ @primary_gems[spec.name].version != spec.version
+ }
- uninstall_options = {
- :executables => false,
- :version => "= #{spec.version}",
- }
+ default_gems, gems_to_cleanup = gems_to_cleanup.partition { |spec|
+ spec.default_gem?
+ }
- uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
+ @default_gems += default_gems
+ @default_gems.uniq!
+ @gems_to_cleanup = gems_to_cleanup.uniq
+ end
- uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
+ def get_primary_gems
+ @primary_gems = {}
- begin
- uninstaller.uninstall
- rescue Gem::DependencyRemovalException, Gem::InstallError,
- Gem::GemNotInHomeException, Gem::FilePermissionError => e
- say "Unable to uninstall #{spec.full_name}:"
- say "\t#{e.class}: #{e.message}"
- end
+ Gem::Specification.each do |spec|
+ if @primary_gems[spec.name].nil? or
+ @primary_gems[spec.name].version < spec.version then
+ @primary_gems[spec.name] = spec
end
+ end
+ end
+
+ def uninstall_dep spec
+ return unless @full.ok_to_remove?(spec.full_name)
- # Restore path Gem::Uninstaller may have change
- Gem.use_paths(original_home, *original_path)
+ if options[:dryrun] then
+ say "Dry Run Mode: Would uninstall #{spec.full_name}"
+ return
end
- say "Clean Up Complete"
+ say "Attempting to uninstall #{spec.full_name}"
- if Gem.configuration.really_verbose then
- skipped = candidate_gems.
- select { |spec| spec.default_gem? }.
- map { |spec| spec.full_name}
+ uninstall_options = {
+ :executables => false,
+ :version => "= #{spec.version}",
+ }
- say "Skipped default gems: #{skipped.join ', '}"
+ uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
+
+ uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
+
+ begin
+ uninstaller.uninstall
+ rescue Gem::DependencyRemovalException, Gem::InstallError,
+ Gem::GemNotInHomeException, Gem::FilePermissionError => e
+ say "Unable to uninstall #{spec.full_name}:"
+ say "\t#{e.class}: #{e.message}"
end
+ ensure
+ # Restore path Gem::Uninstaller may have changed
+ Gem.use_paths @original_home, *@original_path
end
end