Geminstaller C0 Coverage Information - RCov

spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/source_info_cache.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/source_info_cache.rb 395 212
71.14%
55.19%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 require 'fileutils'
2 
3 require 'rubygems'
4 require 'rubygems/source_info_cache_entry'
5 require 'rubygems/user_interaction'
6 
7 ##
8 # SourceInfoCache stores a copy of the gem index for each gem source.
9 #
10 # There are two possible cache locations, the system cache and the user cache:
11 # * The system cache is preferred if it is writable or can be created.
12 # * The user cache is used otherwise
13 #
14 # Once a cache is selected, it will be used for all operations.
15 # SourceInfoCache will not switch between cache files dynamically.
16 #
17 # Cache data is a Hash mapping a source URI to a SourceInfoCacheEntry.
18 #
19 #--
20 # To keep things straight, this is how the cache objects all fit together:
21 #
22 #   Gem::SourceInfoCache
23 #     @cache_data = {
24 #       source_uri => Gem::SourceInfoCacheEntry
25 #         @size = source index size
26 #         @source_index = Gem::SourceIndex
27 #       ...
28 #     }
29 
30 class Gem::SourceInfoCache
31 
32   include Gem::UserInteraction
33 
34   ##
35   # The singleton Gem::SourceInfoCache.  If +all+ is true, a full refresh will
36   # be performed if the singleton instance is being initialized.
37 
38   def self.cache(all = false)
39     return @cache if @cache
40     @cache = new
41     @cache.refresh all if Gem.configuration.update_sources
42     @cache
43   end
44 
45   def self.cache_data
46     cache.cache_data
47   end
48 
49   ##
50   # The name of the system cache file.
51 
52   def self.latest_system_cache_file
53     File.join File.dirname(system_cache_file),
54               "latest_#{File.basename system_cache_file}"
55   end
56 
57   ##
58   # The name of the latest user cache file.
59 
60   def self.latest_user_cache_file
61     File.join File.dirname(user_cache_file),
62               "latest_#{File.basename user_cache_file}"
63   end
64 
65   ##
66   # Reset all singletons, discarding any changes.
67 
68   def self.reset
69     @cache = nil
70     @system_cache_file = nil
71     @user_cache_file = nil
72   end
73 
74   ##
75   # Search all source indexes.  See Gem::SourceInfoCache#search.
76 
77   def self.search(*args)
78     cache.search(*args)
79   end
80 
81   ##
82   # Search all source indexes returning the source_uri.  See
83   # Gem::SourceInfoCache#search_with_source.
84 
85   def self.search_with_source(*args)
86     cache.search_with_source(*args)
87   end
88 
89   ##
90   # The name of the system cache file. (class method)
91 
92   def self.system_cache_file
93     @system_cache_file ||= Gem.default_system_source_cache_dir
94   end
95 
96   ##
97   # The name of the user cache file.
98 
99   def self.user_cache_file
100     @user_cache_file ||=
101       ENV['GEMCACHE'] || Gem.default_user_source_cache_dir
102   end
103 
104   def initialize # :nodoc:
105     @cache_data = nil
106     @cache_file = nil
107     @dirty = false
108     @only_latest = true
109   end
110 
111   ##
112   # The most recent cache data.
113 
114   def cache_data
115     return @cache_data if @cache_data
116     cache_file # HACK writable check
117 
118     @only_latest = true
119 
120     @cache_data = read_cache_data latest_cache_file
121 
122     @cache_data
123   end
124 
125   ##
126   # The name of the cache file.
127 
128   def cache_file
129     return @cache_file if @cache_file
130     @cache_file = (try_file(system_cache_file) or
131       try_file(user_cache_file) or
132       raise "unable to locate a writable cache file")
133   end
134 
135   ##
136   # Write the cache to a local file (if it is dirty).
137 
138   def flush
139     write_cache if @dirty
140     @dirty = false
141   end
142 
143   def latest_cache_data
144     latest_cache_data = {}
145 
146     cache_data.each do |repo, sice|
147       latest = sice.source_index.latest_specs
148 
149       new_si = Gem::SourceIndex.new
150       new_si.add_specs(*latest)
151 
152       latest_sice = Gem::SourceInfoCacheEntry.new new_si, sice.size
153       latest_cache_data[repo] = latest_sice
154     end
155 
156     latest_cache_data
157   end
158 
159   ##
160   # The name of the latest cache file.
161 
162   def latest_cache_file
163     File.join File.dirname(cache_file), "latest_#{File.basename cache_file}"
164   end
165 
166   ##
167   # The name of the latest system cache file.
168 
169   def latest_system_cache_file
170     self.class.latest_system_cache_file
171   end
172 
173   ##
174   # The name of the latest user cache file.
175 
176   def latest_user_cache_file
177     self.class.latest_user_cache_file
178   end
179 
180   ##
181   # Merges the complete cache file into this Gem::SourceInfoCache.
182 
183   def read_all_cache_data
184     if @only_latest then
185       @only_latest = false
186       all_data = read_cache_data cache_file
187 
188       cache_data.update all_data do |source_uri, latest_sice, all_sice|
189         all_sice.source_index.gems.update latest_sice.source_index.gems
190 
191         Gem::SourceInfoCacheEntry.new all_sice.source_index, latest_sice.size
192       end
193 
194       begin
195         refresh true
196       rescue Gem::RemoteFetcher::FetchError
197       end
198     end
199   end
200 
201   ##
202   # Reads cached data from +file+.
203 
204   def read_cache_data(file)
205     # Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
206     data = open file, 'rb' do |fp| fp.read end
207     cache_data = Marshal.load data
208 
209     cache_data.each do |url, sice|
210       next unless sice.is_a?(Hash)
211       update
212 
213       cache = sice['cache']
214       size  = sice['size']
215 
216       if cache.is_a?(Gem::SourceIndex) and size.is_a?(Numeric) then
217         new_sice = Gem::SourceInfoCacheEntry.new cache, size
218         cache_data[url] = new_sice
219       else # irreperable, force refetch.
220         reset_cache_for url, cache_data
221       end
222     end
223 
224     cache_data
225   rescue Errno::ENOENT
226     {}
227   rescue => e
228     if Gem.configuration.really_verbose then
229       say "Exception during cache_data handling: #{e.class} - #{e}"
230       say "Cache file was: #{file}"
231       say "\t#{e.backtrace.join "\n\t"}"
232     end
233 
234     {}
235   end
236 
237   ##
238   # Refreshes each source in the cache from its repository.  If +all+ is
239   # false, only latest gems are updated.
240 
241   def refresh(all)
242     Gem.sources.each do |source_uri|
243       cache_entry = cache_data[source_uri]
244       if cache_entry.nil? then
245         cache_entry = Gem::SourceInfoCacheEntry.new nil, 0
246         cache_data[source_uri] = cache_entry
247       end
248 
249       update if cache_entry.refresh source_uri, all
250     end
251 
252     flush
253   end
254 
255   def reset_cache_for(url, cache_data)
256     say "Reseting cache for #{url}" if Gem.configuration.really_verbose
257 
258     sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
259     sice.refresh url, false # HACK may be unnecessary, see ::cache and #refresh
260 
261     cache_data[url] = sice
262     cache_data
263   end
264 
265   def reset_cache_data
266     @cache_data = nil
267     @only_latest = true
268   end
269 
270   ##
271   # Force cache file to be reset, useful for integration testing of rubygems
272 
273   def reset_cache_file
274     @cache_file = nil
275   end
276 
277   ##
278   # Searches all source indexes.  See Gem::SourceIndex#search for details on
279   # +pattern+ and +platform_only+.  If +all+ is set to true, the full index
280   # will be loaded before searching.
281 
282   def search(pattern, platform_only = false, all = false)
283     read_all_cache_data if all
284 
285     cache_data.map do |source_uri, sic_entry|
286       next unless Gem.sources.include? source_uri
287       # TODO - Remove this gunk after 2008/11
288       unless pattern.kind_of? Gem::Dependency then
289         pattern = Gem::Dependency.new pattern, Gem::Requirement.default
290       end
291       sic_entry.source_index.search pattern, platform_only
292     end.flatten.compact
293   end
294 
295   ##
296   # Searches all source indexes for +pattern+.  If +only_platform+ is true,
297   # only gems matching Gem.platforms will be selected.  Returns an Array of
298   # pairs containing the Gem::Specification found and the source_uri it was
299   # found at.
300 
301   def search_with_source(pattern, only_platform = false, all = false)
302     read_all_cache_data if all
303 
304     results = []
305 
306     cache_data.map do |source_uri, sic_entry|
307       next unless Gem.sources.include? source_uri
308 
309       # TODO - Remove this gunk after 2008/11
310       unless pattern.kind_of?(Gem::Dependency)
311         pattern = Gem::Dependency.new(pattern, Gem::Requirement.default) 
312       end
313 
314       sic_entry.source_index.search(pattern, only_platform).each do |spec|
315         results << [spec, source_uri]
316       end
317     end
318 
319     results
320   end
321 
322   ##
323   # Set the source info cache data directly.  This is mainly used for unit
324   # testing when we don't want to read a file system to grab the cached source
325   # index information.  The +hash+ should map a source URL into a
326   # SourceInfoCacheEntry.
327 
328   def set_cache_data(hash)
329     @cache_data = hash
330     update
331   end
332 
333   ##
334   # The name of the system cache file.
335 
336   def system_cache_file
337     self.class.system_cache_file
338   end
339 
340   ##
341   # Determine if +path+ is a candidate for a cache file.  Returns +path+ if
342   # it is, nil if not.
343 
344   def try_file(path)
345     return path if File.writable? path
346     return nil if File.exist? path
347 
348     dir = File.dirname path
349 
350     unless File.exist? dir then
351       begin
352         FileUtils.mkdir_p dir
353       rescue RuntimeError, SystemCallError
354         return nil
355       end
356     end
357 
358     return path if File.writable? dir
359 
360     nil
361   end
362 
363   ##
364   # Mark the cache as updated (i.e. dirty).
365 
366   def update
367     @dirty = true
368   end
369 
370   ##
371   # The name of the user cache file.
372 
373   def user_cache_file
374     self.class.user_cache_file
375   end
376 
377   ##
378   # Write data to the proper cache files.
379 
380   def write_cache
381     if not File.exist?(cache_file) or not @only_latest then
382       open cache_file, 'wb' do |io|
383         io.write Marshal.dump(cache_data)
384       end
385     end
386 
387     open latest_cache_file, 'wb' do |io|
388       io.write Marshal.dump(latest_cache_data)
389     end
390   end
391 
392   reset
393 
394 end
395 

Generated on Mon May 10 23:40:28 -0700 2010 with rcov 0.9.8