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 39 39: def initialize 40: @dir = File.join Gem.user_home, '.gem', 'specs' 41: @update_cache = File.stat(Gem.user_home).uid == Process.uid 42: 43: @specs = {} 44: @latest_specs = {} 45: 46: @fetcher = Gem::RemoteFetcher.fetcher 47: end
Retuns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 52 52: def cache_dir(uri) 53: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path) 54: end
Fetch specs matching dependency. If all is true, all matching versions are returned. If matching_platform is false, all platforms are returned.
# File lib/rubygems/spec_fetcher.rb, line 61 61: def fetch(dependency, all = false, matching_platform = true) 62: specs_and_sources = find_matching dependency, all, matching_platform 63: 64: specs_and_sources.map do |spec_tuple, source_uri| 65: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] 66: end 67: 68: rescue Gem::RemoteFetcher::FetchError => e 69: raise unless warn_legacy e do 70: require 'rubygems/source_info_cache' 71: 72: return Gem::SourceInfoCache.search_with_source(dependency, 73: matching_platform, all) 74: end 75: end
# File lib/rubygems/spec_fetcher.rb, line 77 77: def fetch_spec(spec, source_uri) 78: spec = spec - [nil, 'ruby', ''] 79: spec_file_name = "#{spec.join '-'}.gemspec" 80: 81: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" 82: 83: cache_dir = cache_dir uri 84: 85: local_spec = File.join cache_dir, spec_file_name 86: 87: if File.exist? local_spec then 88: spec = Gem.read_binary local_spec 89: else 90: uri.path << '.rz' 91: 92: spec = @fetcher.fetch_path uri 93: spec = Gem.inflate spec 94: 95: if @update_cache then 96: FileUtils.mkdir_p cache_dir 97: 98: open local_spec, 'wb' do |io| 99: io.write spec 100: end 101: end 102: end 103: 104: # TODO: Investigate setting Gem::Specification#loaded_from to a URI 105: Marshal.load spec 106: end
Find spec names that match dependency. If all is true, all matching versions are returned. If matching_platform is false, gems for all platforms are returned.
# File lib/rubygems/spec_fetcher.rb, line 113 113: def find_matching(dependency, all = false, matching_platform = true) 114: found = {} 115: 116: list(all).each do |source_uri, specs| 117: found[source_uri] = specs.select do |spec_name, version, spec_platform| 118: dependency =~ Gem::Dependency.new(spec_name, version) and 119: (not matching_platform or Gem::Platform.match(spec_platform)) 120: end 121: end 122: 123: specs_and_sources = [] 124: 125: found.each do |source_uri, specs| 126: uri_str = source_uri.to_s 127: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] }) 128: end 129: 130: specs_and_sources 131: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 137 137: def legacy_repos 138: Gem.sources.reject do |source_uri| 139: source_uri = URI.parse source_uri 140: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz" 141: 142: begin 143: @fetcher.fetch_size spec_path 144: rescue Gem::RemoteFetcher::FetchError 145: begin 146: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo 147: rescue Gem::RemoteFetcher::FetchError 148: alert_error "#{source_uri} does not appear to be a repository" 149: raise 150: end 151: false 152: end 153: end 154: end
Returns a list of gems available for each source in Gem::sources. If all is true, all versions are returned instead of only latest versions.
# File lib/rubygems/spec_fetcher.rb, line 160 160: def list(all = false) 161: list = {} 162: 163: file = all ? 'specs' : 'latest_specs' 164: 165: Gem.sources.each do |source_uri| 166: source_uri = URI.parse source_uri 167: 168: if all and @specs.include? source_uri then 169: list[source_uri] = @specs[source_uri] 170: elsif @latest_specs.include? source_uri then 171: list[source_uri] = @latest_specs[source_uri] 172: else 173: specs = load_specs source_uri, file 174: 175: cache = all ? @specs : @latest_specs 176: 177: cache[source_uri] = specs 178: list[source_uri] = specs 179: end 180: end 181: 182: list 183: end
# File lib/rubygems/spec_fetcher.rb, line 185 185: def load_specs(source_uri, file) 186: file_name = "#{file}.#{Gem.marshal_version}.gz" 187: 188: spec_path = source_uri + file_name 189: 190: cache_dir = cache_dir spec_path 191: 192: local_file = File.join(cache_dir, file_name).chomp '.gz' 193: 194: if File.exist? local_file then 195: local_size = File.stat(local_file).size 196: 197: remote_file = spec_path.dup 198: remote_file.path = remote_file.path.chomp '.gz' 199: remote_size = @fetcher.fetch_size remote_file 200: 201: spec_dump = Gem.read_binary local_file if remote_size == local_size 202: end 203: 204: unless spec_dump then 205: loaded = true 206: 207: spec_dump_gz = @fetcher.fetch_path spec_path 208: spec_dump = Gem.gunzip spec_dump_gz 209: end 210: 211: specs = Marshal.load spec_dump 212: 213: if loaded and @update_cache then 214: begin 215: FileUtils.mkdir_p cache_dir 216: 217: open local_file, 'wb' do |io| 218: Marshal.dump specs, io 219: end 220: rescue 221: end 222: end 223: 224: specs 225: 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 232 232: def warn_legacy(exception) 233: uri = exception.uri.to_s 234: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then 235: 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" 236: 237: yield 238: 239: return true 240: end 241: 242: false 243: end