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