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 36
36:   def self.fetcher
37:     @fetcher ||= new
38:   end

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 44
44:   def initialize
45:     @dir = File.join Gem.user_home, '.gem', 'specs'
46:     @update_cache = File.stat(Gem.user_home).uid == Process.uid
47: 
48:     @specs = {}
49:     @latest_specs = {}
50:     @prerelease_specs = {}
51: 
52:     @fetcher = Gem::RemoteFetcher.fetcher
53:   end

Public Instance methods

Retuns the local directory to write uri to.

[Source]

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

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

[Source]

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

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 83
 83:   def fetch_spec(spec, source_uri)
 84:     spec = spec - [nil, 'ruby', '']
 85:     spec_file_name = "#{spec.join '-'}.gemspec"
 86: 
 87:     uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
 88: 
 89:     cache_dir = cache_dir uri
 90: 
 91:     local_spec = File.join cache_dir, spec_file_name
 92: 
 93:     if File.exist? local_spec then
 94:       spec = Gem.read_binary local_spec
 95:     else
 96:       uri.path << '.rz'
 97: 
 98:       spec = @fetcher.fetch_path uri
 99:       spec = Gem.inflate spec
100: 
101:       if @update_cache then
102:         FileUtils.mkdir_p cache_dir
103: 
104:         open local_spec, 'wb' do |io|
105:           io.write spec
106:         end
107:       end
108:     end
109: 
110:     # TODO: Investigate setting Gem::Specification#loaded_from to a URI
111:     Marshal.load spec
112:   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 119
119:   def find_matching(dependency, all = false, matching_platform = true, prerelease = false)
120:     found = {}
121: 
122:     list(all, prerelease).each do |source_uri, specs|
123:       found[source_uri] = specs.select do |spec_name, version, spec_platform|
124:         dependency =~ Gem::Dependency.new(spec_name, version) and
125:           (not matching_platform or Gem::Platform.match(spec_platform))
126:       end
127:     end
128: 
129:     specs_and_sources = []
130: 
131:     found.each do |source_uri, specs|
132:       uri_str = source_uri.to_s
133:       specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
134:     end
135: 
136:     specs_and_sources
137:   end

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

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 143
143:   def legacy_repos
144:     Gem.sources.reject do |source_uri|
145:       source_uri = URI.parse source_uri
146:       spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
147: 
148:       begin
149:         @fetcher.fetch_size spec_path
150:       rescue Gem::RemoteFetcher::FetchError
151:         begin
152:           @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
153:         rescue Gem::RemoteFetcher::FetchError
154:           alert_error "#{source_uri} does not appear to be a repository"
155:           raise
156:         end
157:         false
158:       end
159:     end
160:   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. If prerelease is true, include prerelease versions.

[Source]

     # File lib/rubygems/spec_fetcher.rb, line 167
167:   def list(all = false, prerelease = false)
168:     # TODO: make type the only argument
169:     type = if all
170:              :all
171:            elsif prerelease
172:              :prerelease
173:            else
174:              :latest
175:            end
176: 
177:     list = {}
178: 
179:     file = { :latest => 'latest_specs',
180:       :prerelease => 'prerelease_specs',
181:       :all => 'specs' }[type]
182: 
183:     cache = { :latest => @latest_specs,
184:       :prerelease => @prerelease_specs,
185:       :all => @specs }[type]
186:     
187:     Gem.sources.each do |source_uri|
188:       source_uri = URI.parse source_uri
189: 
190:       unless cache.include? source_uri
191:         cache[source_uri] = load_specs source_uri, file
192:       end
193: 
194:       list[source_uri] = cache[source_uri]
195:     end
196: 
197:     list
198:   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 204
204:   def load_specs(source_uri, file)
205:     file_name  = "#{file}.#{Gem.marshal_version}"
206:     spec_path  = source_uri + "#{file_name}.gz"
207:     cache_dir  = cache_dir spec_path
208:     local_file = File.join(cache_dir, file_name)
209:     loaded     = false
210: 
211:     if File.exist? local_file then
212:       spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
213: 
214:       if spec_dump.nil? then
215:         spec_dump = Gem.read_binary local_file
216:       else
217:         loaded = true
218:       end
219:     else
220:       spec_dump = @fetcher.fetch_path spec_path
221:       loaded = true
222:     end
223: 
224:     specs = begin
225:               Marshal.load spec_dump
226:             rescue ArgumentError
227:               spec_dump = @fetcher.fetch_path spec_path
228:               loaded = true
229: 
230:               Marshal.load spec_dump
231:             end
232: 
233:     if loaded and @update_cache then
234:       begin
235:         FileUtils.mkdir_p cache_dir
236: 
237:         open local_file, 'wb' do |io|
238:           Marshal.dump specs, io
239:         end
240:       rescue
241:       end
242:     end
243: 
244:     specs
245:   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 252
252:   def warn_legacy(exception)
253:     uri = exception.uri.to_s
254:     if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
255:       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"
256: 
257:       yield
258: 
259:       return true
260:     end
261: 
262:     false
263:   end

[Validate]