Class Gem::SpecFetcher
In: lib/rubygems/spec_fetcher.rb
Parent: Object

SpecFetcher handles metadata updates from remote gem repositories.

Methods

Included Modules

Gem::UserInteraction

Public Class methods

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 31
31:   def self.fetcher
32:     @fetcher ||= new
33:   end

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 39
39:   def initialize
40:     @dir = File.join Gem.user_home, '.gem', 'specs'
41:     @update_cache = File.stat(Gem.user_home).uid == Process.uid
42: 
43:     @specs = {}
44:     @latest_specs = {}
45: 
46:     @fetcher = Gem::RemoteFetcher.fetcher
47:   end

Public Instance methods

Retuns the local directory to write uri to.

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 52
52:   def cache_dir(uri)
53:     File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
54:   end

Fetch specs matching dependency. If all is true, all matching versions are returned. If matching_platform is false, all platforms are returned.

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 61
61:   def fetch(dependency, all = false, matching_platform = true)
62:     specs_and_sources = find_matching dependency, all, matching_platform
63: 
64:     specs_and_sources.map do |spec_tuple, source_uri|
65:       [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
66:     end
67: 
68:   rescue Gem::RemoteFetcher::FetchError => e
69:     raise unless warn_legacy e do
70:       require 'rubygems/source_info_cache'
71: 
72:       return Gem::SourceInfoCache.search_with_source(dependency,
73:                                                      matching_platform, all)
74:     end
75:   end

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 77
 77:   def fetch_spec(spec, source_uri)
 78:     spec = spec - [nil, 'ruby', '']
 79:     spec_file_name = "#{spec.join '-'}.gemspec"
 80: 
 81:     uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
 82: 
 83:     cache_dir = cache_dir uri
 84: 
 85:     local_spec = File.join cache_dir, spec_file_name
 86: 
 87:     if File.exist? local_spec then
 88:       spec = Gem.read_binary local_spec
 89:     else
 90:       uri.path << '.rz'
 91: 
 92:       spec = @fetcher.fetch_path uri
 93:       spec = Gem.inflate spec
 94: 
 95:       if @update_cache then
 96:         FileUtils.mkdir_p cache_dir
 97: 
 98:         open local_spec, 'wb' do |io|
 99:           io.write spec
100:         end
101:       end
102:     end
103: 
104:     # TODO: Investigate setting Gem::Specification#loaded_from to a URI
105:     Marshal.load spec
106:   end

Find spec names that match dependency. If all is true, all matching versions are returned. If matching_platform is false, gems for all platforms are returned.

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 113
113:   def find_matching(dependency, all = false, matching_platform = true)
114:     found = {}
115: 
116:     list(all).each do |source_uri, specs|
117:       found[source_uri] = specs.select do |spec_name, version, spec_platform|
118:         dependency =~ Gem::Dependency.new(spec_name, version) and
119:           (not matching_platform or Gem::Platform.match(spec_platform))
120:       end
121:     end
122: 
123:     specs_and_sources = []
124: 
125:     found.each do |source_uri, specs|
126:       uri_str = source_uri.to_s
127:       specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
128:     end
129: 
130:     specs_and_sources
131:   end

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

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 137
137:   def legacy_repos
138:     Gem.sources.reject do |source_uri|
139:       source_uri = URI.parse source_uri
140:       spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
141: 
142:       begin
143:         @fetcher.fetch_size spec_path
144:       rescue Gem::RemoteFetcher::FetchError
145:         begin
146:           @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
147:         rescue Gem::RemoteFetcher::FetchError
148:           alert_error "#{source_uri} does not appear to be a repository"
149:           raise
150:         end
151:         false
152:       end
153:     end
154:   end

Returns a list of gems available for each source in Gem::sources. If all is true, all versions are returned instead of only latest versions.

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 160
160:   def list(all = false)
161:     list = {}
162: 
163:     file = all ? 'specs' : 'latest_specs'
164: 
165:     Gem.sources.each do |source_uri|
166:       source_uri = URI.parse source_uri
167: 
168:       if all and @specs.include? source_uri then
169:         list[source_uri] = @specs[source_uri]
170:       elsif not all and @latest_specs.include? source_uri then
171:         list[source_uri] = @latest_specs[source_uri]
172:       else
173:         specs = load_specs source_uri, file
174: 
175:         cache = all ? @specs : @latest_specs
176: 
177:         cache[source_uri] = specs
178:         list[source_uri] = specs
179:       end
180:     end
181: 
182:     list
183:   end

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

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 189
189:   def load_specs(source_uri, file)
190:     file_name  = "#{file}.#{Gem.marshal_version}"
191:     spec_path  = source_uri + "#{file_name}.gz"
192:     cache_dir  = cache_dir spec_path
193:     local_file = File.join(cache_dir, file_name)
194:     loaded     = false
195: 
196:     if File.exist? local_file then
197:       spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
198: 
199:       if spec_dump.nil? then
200:         spec_dump = Gem.read_binary local_file
201:       else
202:         loaded = true
203:       end
204:     else
205:       spec_dump = @fetcher.fetch_path spec_path
206:       loaded = true
207:     end
208: 
209:     specs = Marshal.load spec_dump
210: 
211:     if loaded and @update_cache then
212:       begin
213:         FileUtils.mkdir_p cache_dir
214: 
215:         open local_file, 'wb' do |io|
216:           Marshal.dump specs, io
217:         end
218:       rescue
219:       end
220:     end
221: 
222:     specs
223:   end

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.

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 230
230:   def warn_legacy(exception)
231:     uri = exception.uri.to_s
232:     if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
233:       alert_warning "RubyGems 1.2+ index not found for:\n\\t\#{legacy_repos.join \"\\n\\t\"}\n\nRubyGems will revert to legacy indexes degrading performance.\n"
234: 
235:       yield
236: 
237:       return true
238:     end
239: 
240:     false
241:   end

[Validate]