Class: LibGems::SourceIndex
- Inherits:
-
Object
- Object
- LibGems::SourceIndex
- Extended by:
- UserInteraction
- Includes:
- Enumerable, UserInteraction
- Defined in:
- lib/libgems/source_index.rb
Overview
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 LibGems::Cache is an alias for this class to allow old YAMLized source index objects to load properly.
Instance Attribute Summary collapse
-
#gems ⇒ Object
readonly
:nodoc:.
-
#spec_dirs ⇒ Object
Directories to use to refresh this SourceIndex when calling refresh!.
Class Method Summary collapse
-
.from_gems_in(*spec_dirs) ⇒ Object
Creates a new SourceIndex from the ruby format gem specifications in
spec_dirs
. -
.from_installed_gems(*deprecated) ⇒ Object
Factory method to construct a source index instance for a given path.
-
.installed_spec_directories ⇒ Object
Returns a list of directories from LibGems.path that contain specifications.
-
.load_specification(file_name) ⇒ Object
Loads a ruby-format specification from
file_name
and returns the loaded spec.
Instance Method Summary collapse
-
#==(other) ⇒ Object
:nodoc:.
-
#add_spec(gem_spec, name = gem_spec.full_name) ⇒ Object
Add a gem specification to the source index.
-
#add_specs(*gem_specs) ⇒ Object
Add gem specifications to the source index.
-
#all_gems ⇒ Object
TODO: remove method.
- #dump ⇒ Object
-
#each(&block) ⇒ Object
Iterate over the specifications in the source index.
-
#find_name(gem_name, version_requirement = LibGems::Requirement.default) ⇒ Object
Find a gem by an exact match on the short name.
-
#gem_signature(gem_full_name) ⇒ Object
The signature for the given gem specification.
-
#index_signature ⇒ Object
The signature for the source index.
-
#initialize(specifications = {}) ⇒ SourceIndex
constructor
Constructs a source index instance from the provided specifications, which is a Hash of gem full names and LibGems::Specifications.
-
#latest_specs ⇒ Object
Returns an Array specifications for the latest released versions of each gem in this index.
-
#load_gems_in(*spec_dirs) ⇒ Object
Reconstruct the source index from the specifications in
spec_dirs
. -
#outdated ⇒ Object
Returns an Array of LibGems::Specifications that are not up to date.
- #prerelease_gems ⇒ Object
-
#prerelease_specs ⇒ Object
An array including only the prerelease gemspecs.
-
#refresh! ⇒ Object
Replaces the gems in the source index from specifications in the directories this source index was created from.
- #released_gems ⇒ Object
-
#released_specs ⇒ Object
An array including only the released gemspecs.
-
#remove_spec(full_name) ⇒ Object
Remove a gem specification named
full_name
. -
#search(gem_pattern, platform_only = false) ⇒ Object
Search for a gem by LibGems::Dependency
gem_pattern
. - #size ⇒ Object (also: #length)
-
#specification(full_name) ⇒ Object
The gem specification given a full gem spec name.
-
#update(source_uri, all) ⇒ Object
Updates this SourceIndex from
source_uri
.
Methods included from UserInteraction
Methods included from DefaultUserInteraction
ui, #ui, ui=, #ui=, use_ui, #use_ui
Constructor Details
#initialize(specifications = {}) ⇒ SourceIndex
Constructs a source index instance from the provided specifications, which is a Hash of gem full names and LibGems::Specifications. – TODO merge @gems and @prerelease_gems and provide a separate method #prerelease_gems
124 125 126 127 128 |
# File 'lib/libgems/source_index.rb', line 124 def initialize(specifications={}) @gems = {} specifications.each{ |full_name, spec| add_spec spec } @spec_dirs = nil end |
Instance Attribute Details
#gems ⇒ Object (readonly)
:nodoc:
33 34 35 |
# File 'lib/libgems/source_index.rb', line 33 def gems @gems end |
#spec_dirs ⇒ Object
Directories to use to refresh this SourceIndex when calling refresh!
38 39 40 |
# File 'lib/libgems/source_index.rb', line 38 def spec_dirs @spec_dirs end |
Class Method Details
.from_gems_in(*spec_dirs) ⇒ Object
Creates a new SourceIndex from the ruby format gem specifications in spec_dirs
.
75 76 77 78 79 |
# File 'lib/libgems/source_index.rb', line 75 def from_gems_in(*spec_dirs) source_index = new source_index.spec_dirs = spec_dirs source_index.refresh! end |
.from_installed_gems(*deprecated) ⇒ Object
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
56 57 58 59 60 61 62 |
# File 'lib/libgems/source_index.rb', line 56 def from_installed_gems(*deprecated) if deprecated.empty? from_gems_in(*installed_spec_directories) else from_gems_in(*deprecated) # HACK warn end end |
.installed_spec_directories ⇒ Object
Returns a list of directories from LibGems.path that contain specifications.
67 68 69 |
# File 'lib/libgems/source_index.rb', line 67 def installed_spec_directories LibGems.path.collect { |dir| File.join(dir, "specifications") } end |
.load_specification(file_name) ⇒ Object
Loads a ruby-format specification from file_name
and returns the loaded spec.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/libgems/source_index.rb', line 85 def load_specification(file_name) return nil unless file_name and File.exist? file_name spec_code = if defined? Encoding then File.read file_name, :encoding => 'UTF-8' else File.read file_name end.untaint begin gemspec = LibGems.with_rubygems_compat{ eval(spec_code, binding, file_name) } if gemspec.is_a?(LibGems::Specification) gemspec.loaded_from = file_name return gemspec end alert_warning "File '#{file_name}' does not evaluate to a gem specification" rescue SignalException, SystemExit raise rescue SyntaxError => e alert_warning e alert_warning spec_code rescue Exception => e alert_warning "#{e.inspect}\n#{spec_code}" alert_warning "Invalid .gemspec format in '#{file_name}'" end return nil end |
Instance Method Details
#==(other) ⇒ Object
:nodoc:
416 417 418 |
# File 'lib/libgems/source_index.rb', line 416 def ==(other) # :nodoc: self.class === other and @gems == other.gems end |
#add_spec(gem_spec, name = gem_spec.full_name) ⇒ Object
Add a gem specification to the source index.
215 216 217 218 219 |
# File 'lib/libgems/source_index.rb', line 215 def add_spec(gem_spec, name = gem_spec.full_name) # No idea why, but the Indexer wants to insert them using original_name # instead of full_name. So we make it an optional arg. @gems[name] = gem_spec end |
#add_specs(*gem_specs) ⇒ Object
Add gem specifications to the source index.
224 225 226 227 228 |
# File 'lib/libgems/source_index.rb', line 224 def add_specs(*gem_specs) gem_specs.each do |spec| add_spec spec end end |
#all_gems ⇒ Object
TODO: remove method
131 132 133 |
# File 'lib/libgems/source_index.rb', line 131 def all_gems @gems end |
#dump ⇒ Object
420 421 422 |
# File 'lib/libgems/source_index.rb', line 420 def dump Marshal.dump(self) end |
#each(&block) ⇒ Object
Iterate over the specifications in the source index.
240 241 242 |
# File 'lib/libgems/source_index.rb', line 240 def each(&block) # :yields: gem.full_name, gem @gems.each(&block) end |
#find_name(gem_name, version_requirement = LibGems::Requirement.default) ⇒ Object
Find a gem by an exact match on the short name.
278 279 280 281 |
# File 'lib/libgems/source_index.rb', line 278 def find_name(gem_name, version_requirement = LibGems::Requirement.default) dep = LibGems::Dependency.new gem_name, version_requirement search dep end |
#gem_signature(gem_full_name) ⇒ Object
The signature for the given gem specification.
264 265 266 267 268 |
# File 'lib/libgems/source_index.rb', line 264 def gem_signature(gem_full_name) require 'digest' Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s end |
#index_signature ⇒ Object
The signature for the source index. Changes in the signature indicate a change in the index.
255 256 257 258 259 |
# File 'lib/libgems/source_index.rb', line 255 def index_signature require 'digest' Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s end |
#latest_specs ⇒ Object
Returns an Array specifications for the latest released versions of each gem in this index.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/libgems/source_index.rb', line 165 def latest_specs result = Hash.new { |h,k| h[k] = [] } latest = {} sort.each do |_, spec| name = spec.name curr_ver = spec.version prev_ver = latest.key?(name) ? latest[name].version : nil next if curr_ver.prerelease? next unless prev_ver.nil? or curr_ver >= prev_ver or latest[name].platform != LibGems::Platform::RUBY if prev_ver.nil? or (curr_ver > prev_ver and spec.platform == LibGems::Platform::RUBY) then result[name].clear latest[name] = spec end if spec.platform != LibGems::Platform::RUBY then result[name].delete_if do |result_spec| result_spec.platform == spec.platform end end result[name] << spec end # TODO: why is this a hash while @gems is an array? Seems like # structural similarity would be good. result.values.flatten end |
#load_gems_in(*spec_dirs) ⇒ Object
Reconstruct the source index from the specifications in spec_dirs
.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/libgems/source_index.rb', line 146 def load_gems_in(*spec_dirs) @gems.clear spec_dirs.reverse_each do |spec_dir| spec_files = Dir.glob File.join(spec_dir, '*.gemspec') spec_files.each do |spec_file| gemspec = self.class.load_specification spec_file.untaint add_spec gemspec if gemspec end end self end |
#outdated ⇒ Object
Returns an Array of LibGems::Specifications that are not up to date.
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/libgems/source_index.rb', line 351 def outdated outdateds = [] latest_specs.each do |local| dependency = LibGems::Dependency.new local.name, ">= #{local.version}" begin fetcher = LibGems::SpecFetcher.fetcher remotes = fetcher.find_matching dependency remotes = remotes.map { |(name, version,_),_| version } rescue LibGems::RemoteFetcher::FetchError => e raise unless fetcher.warn_legacy e do require 'libgems/source_info_cache' specs = LibGems::SourceInfoCache.search_with_source dependency, true remotes = specs.map { |spec,| spec.version } end end latest = remotes.sort.last outdateds << local.name if latest and local.version < latest end outdateds end |
#prerelease_gems ⇒ Object
135 136 137 |
# File 'lib/libgems/source_index.rb', line 135 def prerelease_gems @gems.reject{ |name, gem| !gem.version.prerelease? } end |
#prerelease_specs ⇒ Object
An array including only the prerelease gemspecs
201 202 203 |
# File 'lib/libgems/source_index.rb', line 201 def prerelease_specs prerelease_gems.values end |
#refresh! ⇒ Object
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).
343 344 345 346 |
# File 'lib/libgems/source_index.rb', line 343 def refresh! raise 'source index not created from disk' if @spec_dirs.nil? load_gems_in(*@spec_dirs) end |
#released_gems ⇒ Object
139 140 141 |
# File 'lib/libgems/source_index.rb', line 139 def released_gems @gems.reject{ |name, gem| gem.version.prerelease? } end |
#released_specs ⇒ Object
An array including only the released gemspecs
208 209 210 |
# File 'lib/libgems/source_index.rb', line 208 def released_specs released_gems.values end |
#remove_spec(full_name) ⇒ Object
Remove a gem specification named full_name
.
233 234 235 |
# File 'lib/libgems/source_index.rb', line 233 def remove_spec(full_name) @gems.delete full_name end |
#search(gem_pattern, platform_only = false) ⇒ Object
Search for a gem by LibGems::Dependency gem_pattern
. If only_platform
is true, only gems matching LibGems::Platform.local will be returned. An Array of matching LibGems::Specification objects is returned.
For backwards compatibility, a String or Regexp pattern may be passed as gem_pattern
, and a LibGems::Requirement for platform_only
. This behavior is deprecated and will be removed.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/libgems/source_index.rb', line 292 def search(gem_pattern, platform_only = false) version_requirement = nil only_platform = false # TODO - Remove support and warning for legacy arguments after 2008/11 unless LibGems::Dependency === gem_pattern warn "#{LibGems.location_of_caller.join ':'}:Warning: LibGems::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name" end case gem_pattern when Regexp then version_requirement = platform_only || LibGems::Requirement.default when LibGems::Dependency then only_platform = platform_only version_requirement = gem_pattern.requirement gem_pattern = if Regexp === gem_pattern.name then gem_pattern.name elsif gem_pattern.name.empty? then // else /^#{Regexp.escape gem_pattern.name}$/ end else version_requirement = platform_only || LibGems::Requirement.default gem_pattern = /#{gem_pattern}/i end unless LibGems::Requirement === version_requirement then version_requirement = LibGems::Requirement.create version_requirement end specs = all_gems.values.select do |spec| spec.name =~ gem_pattern and version_requirement.satisfied_by? spec.version end if only_platform then specs = specs.select do |spec| LibGems::Platform.match spec.platform end end specs.sort_by { |s| s.sort_obj } end |
#size ⇒ Object Also known as: length
270 271 272 |
# File 'lib/libgems/source_index.rb', line 270 def size @gems.size end |
#specification(full_name) ⇒ Object
The gem specification given a full gem spec name.
247 248 249 |
# File 'lib/libgems/source_index.rb', line 247 def specification(full_name) @gems[full_name] end |
#update(source_uri, all) ⇒ Object
Updates this SourceIndex from source_uri
. If all
is false, only the latest gems are fetched.
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/libgems/source_index.rb', line 383 def update(source_uri, all) source_uri = URI.parse source_uri unless URI::Generic === source_uri source_uri.path += '/' unless source_uri.path =~ /\/$/ use_incremental = false begin gem_names = fetch_quick_index source_uri, all remove_extra gem_names missing_gems = find_missing gem_names return false if missing_gems.size.zero? say "Missing metadata for #{missing_gems.size} gems" if missing_gems.size > 0 and LibGems.configuration.really_verbose use_incremental = missing_gems.size <= LibGems.configuration.bulk_threshold rescue LibGems::OperationNotSupportedError => ex alert_error "Falling back to bulk fetch: #{ex.}" if LibGems.configuration.really_verbose use_incremental = false end if use_incremental then update_with_missing(source_uri, missing_gems) else new_index = fetch_bulk_index(source_uri) @gems.replace(new_index.gems) end true end |