1require 'rubygems' 2require 'rubygems/user_interaction' 3require 'pathname' 4 5## 6# Cleans up after a partially-failed uninstall or for an invalid 7# Gem::Specification. 8# 9# If a specification was removed by hand this will remove any remaining files. 10# 11# If a corrupt specification was installed this will clean up warnings by 12# removing the bogus specification. 13 14class Gem::Doctor 15 16 include Gem::UserInteraction 17 18 ## 19 # Maps a gem subdirectory to the files that are expected to exist in the 20 # subdirectory. 21 22 REPOSITORY_EXTENSION_MAP = [ # :nodoc: 23 ['specifications', '.gemspec'], 24 ['build_info', '.info'], 25 ['cache', '.gem'], 26 ['doc', ''], 27 ['gems', ''], 28 ] 29 30 raise 'Update REPOSITORY_EXTENSION_MAP' unless 31 Gem::REPOSITORY_SUBDIRECTORIES.sort == 32 REPOSITORY_EXTENSION_MAP.map { |(k,_)| k }.sort 33 34 ## 35 # Creates a new Gem::Doctor that will clean up +gem_repository+. Only one 36 # gem repository may be cleaned at a time. 37 # 38 # If +dry_run+ is true no files or directories will be removed. 39 40 def initialize gem_repository, dry_run = false 41 @gem_repository = Pathname(gem_repository) 42 @dry_run = dry_run 43 44 @installed_specs = nil 45 end 46 47 ## 48 # Specs installed in this gem repository 49 50 def installed_specs # :nodoc: 51 @installed_specs ||= Gem::Specification.map { |s| s.full_name } 52 end 53 54 ## 55 # Are we doctoring a gem repository? 56 57 def gem_repository? 58 not installed_specs.empty? 59 end 60 61 ## 62 # Cleans up uninstalled files and invalid gem specifications 63 64 def doctor 65 @orig_home = Gem.dir 66 @orig_path = Gem.path 67 68 say "Checking #{@gem_repository}" 69 70 Gem.use_paths @gem_repository.to_s 71 72 unless gem_repository? then 73 say 'This directory does not appear to be a RubyGems repository, ' + 74 'skipping' 75 say 76 return 77 end 78 79 doctor_children 80 81 say 82 ensure 83 Gem.use_paths @orig_home, *@orig_path 84 end 85 86 ## 87 # Cleans up children of this gem repository 88 89 def doctor_children # :nodoc: 90 REPOSITORY_EXTENSION_MAP.each do |sub_directory, extension| 91 doctor_child sub_directory, extension 92 end 93 end 94 95 ## 96 # Removes files in +sub_directory+ with +extension+ 97 98 def doctor_child sub_directory, extension # :nodoc: 99 directory = @gem_repository + sub_directory 100 101 directory.children.sort.each do |child| 102 next unless child.exist? 103 104 basename = child.basename(extension).to_s 105 next if installed_specs.include? basename 106 next if /^rubygems-\d/ =~ basename 107 next if 'specifications' == sub_directory and 'default' == basename 108 109 type = child.directory? ? 'directory' : 'file' 110 111 action = if @dry_run then 112 'Extra' 113 else 114 child.rmtree 115 'Removed' 116 end 117 118 say "#{action} #{type} #{sub_directory}/#{child.basename}" 119 end 120 rescue Errno::ENOENT 121 # ignore 122 end 123 124end 125 126