| 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