Class: Gem::SpecFetcher
- Inherits:
-
Object
- Object
- Gem::SpecFetcher
- Includes:
- Text, UserInteraction
- Defined in:
- lib/rubygems/spec_fetcher.rb
Overview
SpecFetcher handles metadata updates from remote gem repositories.
Instance Attribute Summary (collapse)
-
- (Object) dir
readonly
The SpecFetcher cache dir.
-
- (Object) latest_specs
readonly
Cache of latest specs.
-
- (Object) prerelease_specs
readonly
Cache of prerelease specs.
-
- (Object) specs
readonly
Cache of all released specs.
Class Method Summary (collapse)
Instance Method Summary (collapse)
-
- (Object) cache_dir(uri)
Returns the local directory to write uri to.
- - (Object) fetch(*args)
- - (Object) fetch_spec(spec, source_uri)
-
- (Object) fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
Fetch specs matching dependency.
- - (Object) find_matching(*args)
-
- (Object) find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
Find spec names that match dependency.
-
- (SpecFetcher) initialize
constructor
A new instance of SpecFetcher.
-
- (Object) legacy_repos
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
-
- (Object) list(all = false, prerelease = false)
Returns a list of gems available for each source in Gem::sources.
-
- (Object) load_specs(source_uri, file)
Loads specs in file, fetching from source_uri if the on-disk cache is out of date.
-
- (Object) suggest_gems_from_name(gem_name)
Suggests a gem based on the supplied gem_name.
-
- (Object) warn_legacy(exception)
Warn about legacy repositories if exception indicates only legacy repositories are available, and yield to the block.
Methods included from Text
#format_text, #levenshtein_distance
Methods included from UserInteraction
Methods included from DefaultUserInteraction
ui, #ui, #ui=, ui=, use_ui, #use_ui
Constructor Details
- (SpecFetcher) initialize
A new instance of SpecFetcher
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/rubygems/spec_fetcher.rb', line 44 def initialize require 'fileutils' @dir = File.join Gem.user_home, '.gem', 'specs' @update_cache = File.stat(Gem.user_home).uid == Process.uid @specs = {} @latest_specs = {} @prerelease_specs = {} @fetcher = Gem::RemoteFetcher.fetcher end |
Instance Attribute Details
- (Object) dir (readonly)
The SpecFetcher cache dir.
17 18 19 |
# File 'lib/rubygems/spec_fetcher.rb', line 17 def dir @dir end |
- (Object) latest_specs (readonly)
Cache of latest specs
22 23 24 |
# File 'lib/rubygems/spec_fetcher.rb', line 22 def latest_specs @latest_specs end |
- (Object) prerelease_specs (readonly)
Cache of prerelease specs
32 33 34 |
# File 'lib/rubygems/spec_fetcher.rb', line 32 def prerelease_specs @prerelease_specs end |
- (Object) specs (readonly)
Cache of all released specs
27 28 29 |
# File 'lib/rubygems/spec_fetcher.rb', line 27 def specs @specs end |
Class Method Details
+ (Object) fetcher
36 37 38 |
# File 'lib/rubygems/spec_fetcher.rb', line 36 def self.fetcher @fetcher ||= new end |
+ (Object) fetcher=(fetcher)
:nodoc:
40 41 42 |
# File 'lib/rubygems/spec_fetcher.rb', line 40 def self.fetcher=(fetcher) # :nodoc: @fetcher = fetcher end |
Instance Method Details
- (Object) cache_dir(uri)
Returns the local directory to write uri to.
60 61 62 |
# File 'lib/rubygems/spec_fetcher.rb', line 60 def cache_dir(uri) File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path) end |
- (Object) fetch(*args)
88 89 90 |
# File 'lib/rubygems/spec_fetcher.rb', line 88 def fetch(*args) fetch_with_errors(*args).first end |
- (Object) fetch_spec(spec, source_uri)
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 |
# File 'lib/rubygems/spec_fetcher.rb', line 92 def fetch_spec(spec, source_uri) spec = spec - [nil, 'ruby', ''] spec_file_name = "#{spec.join '-'}.gemspec" uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir uri local_spec = File.join cache_dir, spec_file_name if File.exist? local_spec then spec = Gem.read_binary local_spec else uri.path << '.rz' spec = @fetcher.fetch_path uri spec = Gem.inflate spec if @update_cache then FileUtils.mkdir_p cache_dir open local_spec, 'wb' do |io| io.write spec end end end # TODO: Investigate setting Gem::Specification#loaded_from to a URI Marshal.load spec end |
- (Object) fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
Fetch specs matching dependency. If all is true, all matching (released) versions are returned. If matching_platform is false, all platforms are returned. If prerelease is true, prerelease versions are included.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/rubygems/spec_fetcher.rb', line 70 def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease ss = specs_and_sources.map do |spec_tuple, source_uri| [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] end return [ss, errors] rescue Gem::RemoteFetcher::FetchError => e raise unless warn_legacy e do require 'rubygems/source_info_cache' return [Gem::SourceInfoCache.search_with_source(dependency, matching_platform, all), nil] end end |
- (Object) find_matching(*args)
159 160 161 |
# File 'lib/rubygems/spec_fetcher.rb', line 159 def find_matching(*args) find_matching_with_errors(*args).first end |
- (Object) find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
Find spec names that match dependency. If all is true, all matching released versions are returned. If matching_platform is false, gems for all platforms are returned.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/rubygems/spec_fetcher.rb', line 128 def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) found = {} rejected_specs = {} list(all, prerelease).each do |source_uri, specs| found[source_uri] = specs.select do |spec_name, version, spec_platform| if dependency.match?(spec_name, version) if matching_platform and !Gem::Platform.match(spec_platform) pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version)) pm.add_platform spec_platform false else true end end end end errors = rejected_specs.values specs_and_sources = [] found.each do |source_uri, specs| uri_str = source_uri.to_s specs_and_sources.push(*specs.map { |spec| [spec, uri_str] }) end [specs_and_sources, errors] end |
- (Object) legacy_repos
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/rubygems/spec_fetcher.rb', line 167 def legacy_repos Gem.sources.reject do |source_uri| source_uri = URI.parse source_uri spec_path = source_uri + "specs.#{Gem.marshal_version}.gz" begin @fetcher.fetch_size spec_path rescue Gem::RemoteFetcher::FetchError begin @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo rescue Gem::RemoteFetcher::FetchError alert_error "#{source_uri} does not appear to be a repository" raise end false end end end |
- (Object) list(all = false, prerelease = false)
Returns a list of gems available for each source in Gem::sources. If all is true, all released versions are returned instead of only latest versions. If prerelease is true, include prerelease versions.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/rubygems/spec_fetcher.rb', line 219 def list(all = false, prerelease = false) # TODO: make type the only argument type = if all :all elsif prerelease :prerelease else :latest end list = {} file = { :latest => 'latest_specs', :prerelease => 'prerelease_specs', :all => 'specs' }[type] cache = { :latest => @latest_specs, :prerelease => @prerelease_specs, :all => @specs }[type] Gem.sources.each do |source_uri| source_uri = URI.parse source_uri unless cache.include? source_uri cache[source_uri] = load_specs source_uri, file end list[source_uri] = cache[source_uri] end if type == :all list.values.map do |gems| gems.reject! { |g| !g[1] || g[1].prerelease? } end end list end |
- (Object) load_specs(source_uri, file)
Loads specs in file, fetching from source_uri if the on-disk cache is out of date.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/rubygems/spec_fetcher.rb', line 262 def load_specs(source_uri, file) file_name = "#{file}.#{Gem.marshal_version}" spec_path = source_uri + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) loaded = false if File.exist? local_file then spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file) if spec_dump.nil? then spec_dump = Gem.read_binary local_file else loaded = true end else spec_dump = @fetcher.fetch_path spec_path loaded = true end specs = begin Marshal.load spec_dump rescue ArgumentError spec_dump = @fetcher.fetch_path spec_path loaded = true Marshal.load spec_dump end if loaded and @update_cache then begin FileUtils.mkdir_p cache_dir open local_file, 'wb' do |io| io << spec_dump end rescue end end specs end |
- (Object) suggest_gems_from_name(gem_name)
Suggests a gem based on the supplied gem_name. Returns a string of the gem name if an approximate match can be found or nil otherwise. NOTE: for performance reasons only gems which exactly match the first character of gem_name are considered.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/rubygems/spec_fetcher.rb', line 192 def suggest_gems_from_name gem_name gem_name = gem_name.downcase max = gem_name.size / 2 specs = list.values.flatten(1) # flatten(1) is 1.8.7 and up matches = specs.map { |name, version, platform| next unless Gem::Platform.match platform distance = levenshtein_distance gem_name, name.downcase next if distance >= max return [name] if distance == 0 [name, distance] }.compact matches = matches.uniq.sort_by { |name, dist| dist } matches.first(5).map { |name, dist| name } end |
- (Object) warn_legacy(exception)
Warn about legacy repositories if exception indicates only legacy repositories are available, and yield to the block. Returns false if the exception indicates some other FetchError.
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/rubygems/spec_fetcher.rb', line 310 def warn_legacy(exception) uri = exception.uri.to_s if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then alert_warning <<-EOF RubyGems 1.2+ index not found for: \t#{legacy_repos.join "\n\t"} RubyGems will revert to legacy indexes degrading performance. EOF yield return true end false end |