Object
SpecFetcher handles metadata updates from remote gem repositories.
# File lib/rubygems/spec_fetcher.rb, line 42 42: def self.fetcher 43: @fetcher ||= new 44: end
# File lib/rubygems/spec_fetcher.rb, line 50 50: def initialize 51: require 'fileutils' 52: 53: @dir = File.join Gem.user_home, '.gem', 'specs' 54: @update_cache = File.stat(Gem.user_home).uid == Process.uid 55: 56: @specs = {} 57: @latest_specs = {} 58: @prerelease_specs = {} 59: 60: @caches = { 61: :latest => @latest_specs, 62: :prerelease => @prerelease_specs, 63: :all => @specs 64: } 65: 66: @fetcher = Gem::RemoteFetcher.fetcher 67: end
Returns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 72 72: def cache_dir(uri) 73: # Correct for windows paths 74: escaped_path = uri.path.sub(/^\/([a-z]):\//, '/\1-/') 75: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) 76: end
# File lib/rubygems/spec_fetcher.rb, line 101 101: def fetch(*args) 102: fetch_with_errors(*args).first 103: end
# File lib/rubygems/spec_fetcher.rb, line 105 105: def fetch_spec(spec, source_uri) 106: source_uri = URI.parse source_uri if String === source_uri 107: spec = spec - [nil, 'ruby', ''] 108: spec_file_name = "#{spec.join '-'}.gemspec" 109: 110: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" 111: 112: cache_dir = cache_dir uri 113: 114: local_spec = File.join cache_dir, spec_file_name 115: 116: if File.exist? local_spec then 117: spec = Gem.read_binary local_spec 118: else 119: uri.path << '.rz' 120: 121: spec = @fetcher.fetch_path uri 122: spec = Gem.inflate spec 123: 124: if @update_cache then 125: FileUtils.mkdir_p cache_dir 126: 127: open local_spec, 'wb' do |io| 128: io.write spec 129: end 130: end 131: end 132: 133: # TODO: Investigate setting Gem::Specification#loaded_from to a URI 134: Marshal.load spec 135: 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 84 84: def fetch_with_errors(dependency, 85: all = false, 86: matching_platform = true, 87: prerelease = false) 88: 89: specs_and_sources, errors = find_matching_with_errors(dependency, 90: all, 91: matching_platform, 92: prerelease) 93: 94: ss = specs_and_sources.map do |spec_tuple, source_uri| 95: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] 96: end 97: 98: return [ss, errors] 99: end
# File lib/rubygems/spec_fetcher.rb, line 176 176: def find_matching(*args) 177: find_matching_with_errors(*args).first 178: 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 142 142: def find_matching_with_errors(dependency, 143: all = false, 144: matching_platform = true, 145: prerelease = false) 146: found = {} 147: 148: rejected_specs = {} 149: 150: list(all, prerelease).each do |source_uri, specs| 151: found[source_uri] = specs.select do |spec_name, version, spec_platform| 152: if dependency.match?(spec_name, version) 153: if matching_platform and !Gem::Platform.match(spec_platform) 154: pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version)) 155: pm.add_platform spec_platform 156: false 157: else 158: true 159: end 160: end 161: end 162: end 163: 164: errors = rejected_specs.values 165: 166: specs_and_sources = [] 167: 168: found.each do |source_uri, specs| 169: uri_str = source_uri.to_s 170: specs_and_sources.concat(specs.map { |spec| [spec, uri_str] }) 171: end 172: 173: [specs_and_sources, errors] 174: 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 213 213: def list(all = false, prerelease = false) 214: # TODO: make type the only argument 215: type = if all 216: :all 217: elsif prerelease 218: :prerelease 219: else 220: :latest 221: end 222: 223: list = {} 224: file = FILES[type] 225: cache = @caches[type] 226: 227: Gem.sources.each do |source_uri| 228: source_uri = URI.parse source_uri 229: 230: unless cache.include? source_uri 231: cache[source_uri] = load_specs source_uri, file 232: end 233: 234: list[source_uri] = cache[source_uri] 235: end 236: 237: if type == :all 238: list.values.map do |gems| 239: gems.reject! { |g| !g[1] || g[1].prerelease? } 240: end 241: end 242: 243: list 244: 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 250 250: def load_specs(source_uri, file) 251: file_name = "#{file}.#{Gem.marshal_version}" 252: spec_path = source_uri + "#{file_name}.gz" 253: cache_dir = cache_dir spec_path 254: local_file = File.join(cache_dir, file_name) 255: loaded = false 256: 257: if File.exist? local_file then 258: spec_dump = 259: @fetcher.fetch_path(spec_path, File.mtime(local_file)) rescue nil 260: 261: loaded = true if spec_dump 262: 263: spec_dump ||= Gem.read_binary local_file 264: else 265: spec_dump = @fetcher.fetch_path spec_path 266: loaded = true 267: end 268: 269: specs = begin 270: Marshal.load spec_dump 271: rescue ArgumentError 272: spec_dump = @fetcher.fetch_path spec_path 273: loaded = true 274: 275: Marshal.load spec_dump 276: end 277: 278: if loaded and @update_cache then 279: begin 280: FileUtils.mkdir_p cache_dir 281: 282: open local_file, 'wb' do |io| 283: io << spec_dump 284: end 285: rescue 286: end 287: end 288: 289: specs 290: end
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.
# File lib/rubygems/spec_fetcher.rb, line 186 186: def suggest_gems_from_name gem_name 187: gem_name = gem_name.downcase 188: max = gem_name.size / 2 189: specs = list.values.flatten 1 190: 191: matches = specs.map { |name, version, platform| 192: next unless Gem::Platform.match platform 193: 194: distance = levenshtein_distance gem_name, name.downcase 195: 196: next if distance >= max 197: 198: return [name] if distance == 0 199: 200: [name, distance] 201: }.compact 202: 203: matches = matches.uniq.sort_by { |name, dist| dist } 204: 205: matches.first(5).map { |name, dist| name } 206: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.