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