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
|
# frozen_string_literal: true
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', ''],
['plugins', ''],
].freeze
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?
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
next if 'plugins' == sub_directory and Gem.plugin_suffix_regexp =~ basename
type = File.directory?(child) ? 'directory' : 'file'
action = if @dry_run
'Extra'
else
FileUtils.rm_r(child)
'Removed'
end
say "#{action} #{type} #{sub_directory}/#{File.basename(child)}"
end
rescue Errno::ENOENT
# ignore
end
end
|