Class | Gem::SourceIndex |
In: |
lib/rubygems/source_index.rb
|
Parent: | Object |
The SourceIndex object indexes all the gems available from a particular source (e.g. a list of gem directories, or a remote source). A SourceIndex maps a gem full name to a gem specification.
NOTE: | The class used to be named Cache, but that became confusing when cached source fetchers where introduced. The constant Gem::Cache is an alias for this class to allow old YAMLized source index objects to load properly. |
spec_dirs | [RW] | Directories to use to refresh this SourceIndex when calling refresh! |
Creates a new SourceIndex from the ruby format gem specifications in spec_dirs.
# File lib/rubygems/source_index.rb, line 71 71: def from_gems_in(*spec_dirs) 72: source_index = new 73: source_index.spec_dirs = spec_dirs 74: source_index.refresh! 75: end
Factory method to construct a source index instance for a given path.
deprecated: | If supplied, from_installed_gems will act just like from_gems_in. This argument is deprecated and is provided just for backwards compatibility, and should not generally be used. |
return: | SourceIndex instance |
# File lib/rubygems/source_index.rb, line 52 52: def from_installed_gems(*deprecated) 53: if deprecated.empty? 54: from_gems_in(*installed_spec_directories) 55: else 56: from_gems_in(*deprecated) # HACK warn 57: end 58: end
Loads a ruby-format specification from file_name and returns the loaded spec.
# File lib/rubygems/source_index.rb, line 81 81: def load_specification(file_name) 82: begin 83: spec_code = File.read(file_name).untaint 84: gemspec = eval spec_code, binding, file_name 85: if gemspec.is_a?(Gem::Specification) 86: gemspec.loaded_from = file_name 87: return gemspec 88: end 89: alert_warning "File '#{file_name}' does not evaluate to a gem specification" 90: rescue SignalException, SystemExit 91: raise 92: rescue SyntaxError => e 93: alert_warning e 94: alert_warning spec_code 95: rescue Exception => e 96: alert_warning(e.inspect.to_s + "\n" + spec_code) 97: alert_warning "Invalid .gemspec format in '#{file_name}'" 98: end 99: return nil 100: end
Add a gem specification to the source index.
# File lib/rubygems/source_index.rb, line 171 171: def add_spec(gem_spec) 172: @gems[gem_spec.full_name] = gem_spec 173: end
Add gem specifications to the source index.
# File lib/rubygems/source_index.rb, line 178 178: def add_specs(*gem_specs) 179: gem_specs.each do |spec| 180: add_spec spec 181: end 182: end
Iterate over the specifications in the source index.
# File lib/rubygems/source_index.rb, line 194 194: def each(&block) # :yields: gem.full_name, gem 195: @gems.each(&block) 196: end
Find a gem by an exact match on the short name.
# File lib/rubygems/source_index.rb, line 232 232: def find_name(gem_name, version_requirement = Gem::Requirement.default) 233: search(/^#{gem_name}$/, version_requirement) 234: end
The signature for the given gem specification.
# File lib/rubygems/source_index.rb, line 218 218: def gem_signature(gem_full_name) 219: require 'rubygems/digest/sha2' 220: 221: Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s 222: end
The signature for the source index. Changes in the signature indicate a change in the index.
# File lib/rubygems/source_index.rb, line 209 209: def index_signature 210: require 'rubygems/digest/sha2' 211: 212: Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s 213: end
Returns an Array specifications for the latest versions of each gem in this index.
# File lib/rubygems/source_index.rb, line 138 138: def latest_specs 139: result = Hash.new { |h,k| h[k] = [] } 140: latest = {} 141: 142: sort.each do |_, spec| 143: name = spec.name 144: curr_ver = spec.version 145: prev_ver = latest.key?(name) ? latest[name].version : nil 146: 147: next unless prev_ver.nil? or curr_ver >= prev_ver or 148: latest[name].platform != Gem::Platform::RUBY 149: 150: if prev_ver.nil? or 151: (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then 152: result[name].clear 153: latest[name] = spec 154: end 155: 156: if spec.platform != Gem::Platform::RUBY then 157: result[name].delete_if do |result_spec| 158: result_spec.platform == spec.platform 159: end 160: end 161: 162: result[name] << spec 163: end 164: 165: result.values.flatten 166: end
Reconstruct the source index from the specifications in spec_dirs.
# File lib/rubygems/source_index.rb, line 119 119: def load_gems_in(*spec_dirs) 120: @gems.clear 121: 122: spec_dirs.reverse_each do |spec_dir| 123: spec_files = Dir.glob File.join(spec_dir, '*.gemspec') 124: 125: spec_files.each do |spec_file| 126: gemspec = self.class.load_specification spec_file.untaint 127: add_spec gemspec if gemspec 128: end 129: end 130: 131: self 132: end
Returns an Array of Gem::Specifications that are not up to date.
# File lib/rubygems/source_index.rb, line 299 299: def outdated 300: outdateds = [] 301: 302: latest_specs.each do |local| 303: dependency = Gem::Dependency.new local.name, ">= #{local.version}" 304: 305: begin 306: fetcher = Gem::SpecFetcher.fetcher 307: remotes = fetcher.find_matching dependency 308: remotes = remotes.map { |(name, version,_),_| version } 309: rescue Gem::RemoteFetcher::FetchError => e 310: raise unless fetcher.warn_legacy e do 311: require 'rubygems/source_info_cache' 312: 313: specs = Gem::SourceInfoCache.search_with_source dependency, true 314: 315: remotes = specs.map { |spec,| spec.version } 316: end 317: end 318: 319: latest = remotes.sort.last 320: 321: outdateds << local.name if latest and local.version < latest 322: end 323: 324: outdateds 325: end
Replaces the gems in the source index from specifications in the directories this source index was created from. Raises an exception if this source index wasn‘t created from a directory (via from_gems_in or from_installed_gems, or having spec_dirs set).
# File lib/rubygems/source_index.rb, line 291 291: def refresh! 292: raise 'source index not created from disk' if @spec_dirs.nil? 293: load_gems_in(*@spec_dirs) 294: end
Remove a gem specification named full_name.
# File lib/rubygems/source_index.rb, line 187 187: def remove_spec(full_name) 188: @gems.delete(full_name) 189: end
Search for a gem by Gem::Dependency gem_pattern. If only_platform is true, only gems matching Gem::Platform.local will be returned. An Array of matching Gem::Specification objects is returned.
For backwards compatibility, a String or Regexp pattern may be passed as gem_pattern, and a Gem::Requirement for platform_only. This behavior is deprecated and will be removed.
# File lib/rubygems/source_index.rb, line 245 245: def search(gem_pattern, platform_only = false) 246: version_requirement = nil 247: only_platform = false 248: 249: case gem_pattern # TODO warn after 2008/03, remove three months after 250: when Regexp then 251: version_requirement = platform_only || Gem::Requirement.default 252: when Gem::Dependency then 253: only_platform = platform_only 254: version_requirement = gem_pattern.version_requirements 255: gem_pattern = if Regexp === gem_pattern.name then 256: gem_pattern.name 257: elsif gem_pattern.name.empty? then 258: // 259: else 260: /^#{Regexp.escape gem_pattern.name}$/ 261: end 262: else 263: version_requirement = platform_only || Gem::Requirement.default 264: gem_pattern = /^#{gem_pattern}/i 265: end 266: 267: unless Gem::Requirement === version_requirement then 268: version_requirement = Gem::Requirement.create version_requirement 269: end 270: 271: specs = @gems.values.select do |spec| 272: spec.name =~ gem_pattern and 273: version_requirement.satisfied_by? spec.version 274: end 275: 276: if only_platform then 277: specs = specs.select do |spec| 278: Gem::Platform.match spec.platform 279: end 280: end 281: 282: specs.sort_by { |s| s.sort_obj } 283: end
The gem specification given a full gem spec name.
# File lib/rubygems/source_index.rb, line 201 201: def specification(full_name) 202: @gems[full_name] 203: end
Updates this SourceIndex from source_uri. If all is false, only the latest gems are fetched.
# File lib/rubygems/source_index.rb, line 331 331: def update(source_uri, all) 332: source_uri = URI.parse source_uri unless URI::Generic === source_uri 333: source_uri.path += '/' unless source_uri.path =~ /\/$/ 334: 335: use_incremental = false 336: 337: begin 338: gem_names = fetch_quick_index source_uri, all 339: remove_extra gem_names 340: missing_gems = find_missing gem_names 341: 342: return false if missing_gems.size.zero? 343: 344: say "Missing metadata for #{missing_gems.size} gems" if 345: missing_gems.size > 0 and Gem.configuration.really_verbose 346: 347: use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold 348: rescue Gem::OperationNotSupportedError => ex 349: alert_error "Falling back to bulk fetch: #{ex.message}" if 350: Gem.configuration.really_verbose 351: use_incremental = false 352: end 353: 354: if use_incremental then 355: update_with_missing(source_uri, missing_gems) 356: else 357: new_index = fetch_bulk_index(source_uri) 358: @gems.replace(new_index.gems) 359: end 360: 361: true 362: end