In Files

  • rubygems/spec_fetcher.rb

Class/Module Index [+]

Quicksearch

Gem::SpecFetcher

SpecFetcher handles metadata updates from remote gem repositories.

Public Class Methods

fetcher() click to toggle source
 
               # File rubygems/spec_fetcher.rb, line 37
def self.fetcher
  @fetcher ||= new
end
            
new() click to toggle source
 
               # File rubygems/spec_fetcher.rb, line 45
def initialize
  @dir = File.join Gem.user_home, '.gem', 'specs'
  @update_cache = File.stat(Gem.user_home).uid == Process.uid

  @specs = {}
  @latest_specs = {}
  @prerelease_specs = {}

  @fetcher = Gem::RemoteFetcher.fetcher
end
            

Public Instance Methods

cache_dir(uri) click to toggle source

Returns the local directory to write uri to.

 
               # File rubygems/spec_fetcher.rb, line 59
def cache_dir(uri)
  File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
end
            
fetch(*args) click to toggle source
 
               # File rubygems/spec_fetcher.rb, line 87
def fetch(*args)
  fetch_with_errors(*args).first
end
            
fetch_spec(spec, source_uri) click to toggle source
 
               # File rubygems/spec_fetcher.rb, line 91
def fetch_spec(spec, source_uri)
  spec = spec - [nil, 'ruby', '']
  spec_file_name = "#{spec.join '-'}.gemspec"

  uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"

  cache_dir = cache_dir uri

  local_spec = File.join cache_dir, spec_file_name

  if File.exist? local_spec then
    spec = Gem.read_binary local_spec
  else
    uri.path << '.rz'

    spec = @fetcher.fetch_path uri
    spec = Gem.inflate spec

    if @update_cache then
      FileUtils.mkdir_p cache_dir

      open local_spec, 'wb' do |io|
        io.write spec
      end
    end
  end

  # TODO: Investigate setting Gem::Specification#loaded_from to a URI
  Marshal.load spec
end
            
fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) click to toggle source

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 rubygems/spec_fetcher.rb, line 69
def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
  specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease

  ss = specs_and_sources.map do |spec_tuple, source_uri|
    [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
  end

  return [ss, errors]

rescue Gem::RemoteFetcher::FetchError => e
  raise unless warn_legacy e do
    require 'rubygems/source_info_cache'

    return [Gem::SourceInfoCache.search_with_source(dependency,
                                                   matching_platform, all), nil]
  end
end
            
find_matching(*args) click to toggle source
 
               # File rubygems/spec_fetcher.rb, line 158
def find_matching(*args)
  find_matching_with_errors(*args).first
end
            
find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) click to toggle source

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 rubygems/spec_fetcher.rb, line 127
def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
  found = {}

  rejected_specs = {}

  list(all, prerelease).each do |source_uri, specs|
    found[source_uri] = specs.select do |spec_name, version, spec_platform|
      if dependency.match?(spec_name, version)
        if matching_platform and !Gem::Platform.match(spec_platform)
          pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version))
          pm.add_platform spec_platform
          false
        else
          true
        end
      end
    end
  end

  errors = rejected_specs.values

  specs_and_sources = []

  found.each do |source_uri, specs|
    uri_str = source_uri.to_s
    specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
  end

  [specs_and_sources, errors]
end
            
legacy_repos() click to toggle source

Returns Array of gem repositories that were generated with RubyGems less than 1.2.

 
               # File rubygems/spec_fetcher.rb, line 166
def legacy_repos
  Gem.sources.reject do |source_uri|
    source_uri = URI.parse source_uri
    spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"

    begin
      @fetcher.fetch_size spec_path
    rescue Gem::RemoteFetcher::FetchError
      begin
        @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
      rescue Gem::RemoteFetcher::FetchError
        alert_error "#{source_uri} does not appear to be a repository"
        raise
      end
      false
    end
  end
end
            
list(all = false, prerelease = false) click to toggle source

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 rubygems/spec_fetcher.rb, line 190
def list(all = false, prerelease = false)
  # TODO: make type the only argument
  type = if all
           :all
         elsif prerelease
           :prerelease
         else
           :latest
         end

  list = {}

  file = { :latest => 'latest_specs',
    :prerelease => 'prerelease_specs',
    :all => 'specs' }[type]

  cache = { :latest => @latest_specs,
    :prerelease => @prerelease_specs,
    :all => @specs }[type]

  Gem.sources.each do |source_uri|
    source_uri = URI.parse source_uri

    unless cache.include? source_uri
      cache[source_uri] = load_specs source_uri, file
    end

    list[source_uri] = cache[source_uri]
  end

  if type == :all
    list.values.map do |gems|
      gems.reject! { |g| !g[1] || g[1].prerelease? }
    end
  end

  list
end
            
load_specs(source_uri, file) click to toggle source

Loads specs in file, fetching from source_uri if the on-disk cache is out of date.

 
               # File rubygems/spec_fetcher.rb, line 233
def load_specs(source_uri, file)
  file_name  = "#{file}.#{Gem.marshal_version}"
  spec_path  = source_uri + "#{file_name}.gz"
  cache_dir  = cache_dir spec_path
  local_file = File.join(cache_dir, file_name)
  loaded     = false

  if File.exist? local_file then
    spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)

    if spec_dump.nil? then
      spec_dump = Gem.read_binary local_file
    else
      loaded = true
    end
  else
    spec_dump = @fetcher.fetch_path spec_path
    loaded = true
  end

  specs = begin
            Marshal.load spec_dump
          rescue ArgumentError
            spec_dump = @fetcher.fetch_path spec_path
            loaded = true

            Marshal.load spec_dump
          end

  if loaded and @update_cache then
    begin
      FileUtils.mkdir_p cache_dir

      open local_file, 'wb' do |io|
        io << spec_dump
      end
    rescue
    end
  end

  specs
end
            
warn_legacy(exception) click to toggle source

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 rubygems/spec_fetcher.rb, line 281
  def warn_legacy(exception)
    uri = exception.uri.to_s
    if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
      alert_warning <<-EOF
RubyGems 1.2+ index not found for:
\t#{legacy_repos.join "\n\t"}

RubyGems will revert to legacy indexes degrading performance.
      EOF

      yield

      return true
    end

    false
  end
            

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus