Class | Gem::SpecFetcher |
In: |
lib/rubygems/spec_fetcher.rb
|
Parent: | Object |
SpecFetcher handles metadata updates from remote gem repositories.
# File lib/rubygems/spec_fetcher.rb, line 45 45: def initialize 46: @dir = File.join Gem.user_home, '.gem', 'specs' 47: @update_cache = File.stat(Gem.user_home).uid == Process.uid 48: 49: @specs = {} 50: @latest_specs = {} 51: @prerelease_specs = {} 52: 53: @fetcher = Gem::RemoteFetcher.fetcher 54: end
Returns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 59 59: def cache_dir(uri) 60: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path) 61: end
# File lib/rubygems/spec_fetcher.rb, line 87 87: def fetch(*args) 88: fetch_with_errors(*args).first 89: end
# File lib/rubygems/spec_fetcher.rb, line 91 91: def fetch_spec(spec, source_uri) 92: spec = spec - [nil, 'ruby', ''] 93: spec_file_name = "#{spec.join '-'}.gemspec" 94: 95: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" 96: 97: cache_dir = cache_dir uri 98: 99: local_spec = File.join cache_dir, spec_file_name 100: 101: if File.exist? local_spec then 102: spec = Gem.read_binary local_spec 103: else 104: uri.path << '.rz' 105: 106: spec = @fetcher.fetch_path uri 107: spec = Gem.inflate spec 108: 109: if @update_cache then 110: FileUtils.mkdir_p cache_dir 111: 112: open local_spec, 'wb' do |io| 113: io.write spec 114: end 115: end 116: end 117: 118: # TODO: Investigate setting Gem::Specification#loaded_from to a URI 119: Marshal.load spec 120: end
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.
# File lib/rubygems/spec_fetcher.rb, line 69 69: def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) 70: specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease 71: 72: ss = specs_and_sources.map do |spec_tuple, source_uri| 73: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] 74: end 75: 76: return [ss, errors] 77: 78: rescue Gem::RemoteFetcher::FetchError => e 79: raise unless warn_legacy e do 80: require 'rubygems/source_info_cache' 81: 82: return [Gem::SourceInfoCache.search_with_source(dependency, 83: matching_platform, all), nil] 84: end 85: end
# File lib/rubygems/spec_fetcher.rb, line 158 158: def find_matching(*args) 159: find_matching_with_errors(*args).first 160: end
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.
# File lib/rubygems/spec_fetcher.rb, line 127 127: def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) 128: found = {} 129: 130: rejected_specs = {} 131: 132: list(all, prerelease).each do |source_uri, specs| 133: found[source_uri] = specs.select do |spec_name, version, spec_platform| 134: if dependency.match?(spec_name, version) 135: if matching_platform and !Gem::Platform.match(spec_platform) 136: pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version)) 137: pm.add_platform spec_platform 138: false 139: else 140: true 141: end 142: end 143: end 144: end 145: 146: errors = rejected_specs.values 147: 148: specs_and_sources = [] 149: 150: found.each do |source_uri, specs| 151: uri_str = source_uri.to_s 152: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] }) 153: end 154: 155: [specs_and_sources, errors] 156: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 166 166: def legacy_repos 167: Gem.sources.reject do |source_uri| 168: source_uri = URI.parse source_uri 169: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz" 170: 171: begin 172: @fetcher.fetch_size spec_path 173: rescue Gem::RemoteFetcher::FetchError 174: begin 175: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo 176: rescue Gem::RemoteFetcher::FetchError 177: alert_error "#{source_uri} does not appear to be a repository" 178: raise 179: end 180: false 181: end 182: end 183: end
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.
# File lib/rubygems/spec_fetcher.rb, line 190 190: def list(all = false, prerelease = false) 191: # TODO: make type the only argument 192: type = if all 193: :all 194: elsif prerelease 195: :prerelease 196: else 197: :latest 198: end 199: 200: list = {} 201: 202: file = { :latest => 'latest_specs', 203: :prerelease => 'prerelease_specs', 204: :all => 'specs' }[type] 205: 206: cache = { :latest => @latest_specs, 207: :prerelease => @prerelease_specs, 208: :all => @specs }[type] 209: 210: Gem.sources.each do |source_uri| 211: source_uri = URI.parse source_uri 212: 213: unless cache.include? source_uri 214: cache[source_uri] = load_specs source_uri, file 215: end 216: 217: list[source_uri] = cache[source_uri] 218: end 219: 220: if type == :all 221: list.values.map do |gems| 222: gems.reject! { |g| !g[1] || g[1].prerelease? } 223: end 224: end 225: 226: list 227: end
Loads specs in file, fetching from source_uri if the on-disk cache is out of date.
# File lib/rubygems/spec_fetcher.rb, line 233 233: def load_specs(source_uri, file) 234: file_name = "#{file}.#{Gem.marshal_version}" 235: spec_path = source_uri + "#{file_name}.gz" 236: cache_dir = cache_dir spec_path 237: local_file = File.join(cache_dir, file_name) 238: loaded = false 239: 240: if File.exist? local_file then 241: spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file) 242: 243: if spec_dump.nil? then 244: spec_dump = Gem.read_binary local_file 245: else 246: loaded = true 247: end 248: else 249: spec_dump = @fetcher.fetch_path spec_path 250: loaded = true 251: end 252: 253: specs = begin 254: Marshal.load spec_dump 255: rescue ArgumentError 256: spec_dump = @fetcher.fetch_path spec_path 257: loaded = true 258: 259: Marshal.load spec_dump 260: end 261: 262: if loaded and @update_cache then 263: begin 264: FileUtils.mkdir_p cache_dir 265: 266: open local_file, 'wb' do |io| 267: io << spec_dump 268: end 269: rescue 270: end 271: end 272: 273: specs 274: end
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.
# File lib/rubygems/spec_fetcher.rb, line 281 281: def warn_legacy(exception) 282: uri = exception.uri.to_s 283: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then 284: alert_warning "RubyGems 1.2+ index not found for:\n\\t\#{legacy_repos.join \"\\n\\t\"}\n\nRubyGems will revert to legacy indexes degrading performance.\n" 285: 286: yield 287: 288: return true 289: end 290: 291: false 292: end