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 44 44: def initialize 45: @dir = File.join Gem.user_home, '.gem', 'specs' 46: @update_cache = File.stat(Gem.user_home).uid == Process.uid 47: 48: @specs = {} 49: @latest_specs = {} 50: @prerelease_specs = {} 51: 52: @fetcher = Gem::RemoteFetcher.fetcher 53: end
Retuns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 58 58: def cache_dir(uri) 59: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path) 60: end
Fetch specs matching dependency. If all is true, all matching 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 67 67: def fetch(dependency, all = false, matching_platform = true, prerelease = false) 68: specs_and_sources = find_matching dependency, all, matching_platform, prerelease 69: 70: specs_and_sources.map do |spec_tuple, source_uri| 71: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] 72: end 73: 74: rescue Gem::RemoteFetcher::FetchError => e 75: raise unless warn_legacy e do 76: require 'rubygems/source_info_cache' 77: 78: return Gem::SourceInfoCache.search_with_source(dependency, 79: matching_platform, all) 80: end 81: end
# File lib/rubygems/spec_fetcher.rb, line 83 83: def fetch_spec(spec, source_uri) 84: spec = spec - [nil, 'ruby', ''] 85: spec_file_name = "#{spec.join '-'}.gemspec" 86: 87: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" 88: 89: cache_dir = cache_dir uri 90: 91: local_spec = File.join cache_dir, spec_file_name 92: 93: if File.exist? local_spec then 94: spec = Gem.read_binary local_spec 95: else 96: uri.path << '.rz' 97: 98: spec = @fetcher.fetch_path uri 99: spec = Gem.inflate spec 100: 101: if @update_cache then 102: FileUtils.mkdir_p cache_dir 103: 104: open local_spec, 'wb' do |io| 105: io.write spec 106: end 107: end 108: end 109: 110: # TODO: Investigate setting Gem::Specification#loaded_from to a URI 111: Marshal.load spec 112: 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 119 119: def find_matching(dependency, all = false, matching_platform = true, prerelease = false) 120: found = {} 121: 122: list(all, prerelease).each do |source_uri, specs| 123: found[source_uri] = specs.select do |spec_name, version, spec_platform| 124: dependency =~ Gem::Dependency.new(spec_name, version) and 125: (not matching_platform or Gem::Platform.match(spec_platform)) 126: end 127: end 128: 129: specs_and_sources = [] 130: 131: found.each do |source_uri, specs| 132: uri_str = source_uri.to_s 133: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] }) 134: end 135: 136: specs_and_sources 137: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 143 143: def legacy_repos 144: Gem.sources.reject do |source_uri| 145: source_uri = URI.parse source_uri 146: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz" 147: 148: begin 149: @fetcher.fetch_size spec_path 150: rescue Gem::RemoteFetcher::FetchError 151: begin 152: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo 153: rescue Gem::RemoteFetcher::FetchError 154: alert_error "#{source_uri} does not appear to be a repository" 155: raise 156: end 157: false 158: end 159: end 160: 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. If prerelease is true, include prerelease versions.
# File lib/rubygems/spec_fetcher.rb, line 167 167: def list(all = false, prerelease = false) 168: # TODO: make type the only argument 169: type = if all 170: :all 171: elsif prerelease 172: :prerelease 173: else 174: :latest 175: end 176: 177: list = {} 178: 179: file = { :latest => 'latest_specs', 180: :prerelease => 'prerelease_specs', 181: :all => 'specs' }[type] 182: 183: cache = { :latest => @latest_specs, 184: :prerelease => @prerelease_specs, 185: :all => @specs }[type] 186: 187: Gem.sources.each do |source_uri| 188: source_uri = URI.parse source_uri 189: 190: unless cache.include? source_uri 191: cache[source_uri] = load_specs source_uri, file 192: end 193: 194: list[source_uri] = cache[source_uri] 195: end 196: 197: list 198: 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 204 204: def load_specs(source_uri, file) 205: file_name = "#{file}.#{Gem.marshal_version}" 206: spec_path = source_uri + "#{file_name}.gz" 207: cache_dir = cache_dir spec_path 208: local_file = File.join(cache_dir, file_name) 209: loaded = false 210: 211: if File.exist? local_file then 212: spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file) 213: 214: if spec_dump.nil? then 215: spec_dump = Gem.read_binary local_file 216: else 217: loaded = true 218: end 219: else 220: spec_dump = @fetcher.fetch_path spec_path 221: loaded = true 222: end 223: 224: specs = begin 225: Marshal.load spec_dump 226: rescue ArgumentError 227: spec_dump = @fetcher.fetch_path spec_path 228: loaded = true 229: 230: Marshal.load spec_dump 231: end 232: 233: if loaded and @update_cache then 234: begin 235: FileUtils.mkdir_p cache_dir 236: 237: open local_file, 'wb' do |io| 238: Marshal.dump specs, io 239: end 240: rescue 241: end 242: end 243: 244: specs 245: 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 252 252: def warn_legacy(exception) 253: uri = exception.uri.to_s 254: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then 255: 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" 256: 257: yield 258: 259: return true 260: end 261: 262: false 263: end