Class: LibGems::SourceInfoCache

Inherits:
Object
  • Object
show all
Includes:
UserInteraction
Defined in:
lib/libgems/source_info_cache.rb

Overview

SourceInfoCache stores a copy of the gem index for each gem source.

There are two possible cache locations, the system cache and the user cache:

  • The system cache is preferred if it is writable or can be created.

  • The user cache is used otherwise

Once a cache is selected, it will be used for all operations. SourceInfoCache will not switch between cache files dynamically.

Cache data is a Hash mapping a source URI to a SourceInfoCacheEntry.

– To keep things straight, this is how the cache objects all fit together:

LibGems::SourceInfoCache
  @cache_data = {
    source_uri => LibGems::SourceInfoCacheEntry
      @size = source index size
      @source_index = LibGems::SourceIndex
    ...
  }

Class Method Summary collapse

Instance Method Summary collapse

Methods included from UserInteraction

#methname

Methods included from DefaultUserInteraction

ui, #ui, ui=, #ui=, use_ui, #use_ui

Constructor Details

#initializeSourceInfoCache

:nodoc:



104
105
106
107
108
109
# File 'lib/libgems/source_info_cache.rb', line 104

def initialize # :nodoc:
  @cache_data = nil
  @cache_file = nil
  @dirty = false
  @only_latest = true
end

Class Method Details

.cache(all = false) ⇒ Object

The singleton LibGems::SourceInfoCache. If all is true, a full refresh will be performed if the singleton instance is being initialized.



38
39
40
41
42
43
# File 'lib/libgems/source_info_cache.rb', line 38

def self.cache(all = false)
  return @cache if @cache
  @cache = new
  @cache.refresh all if LibGems.configuration.update_sources
  @cache
end

.cache_dataObject



45
46
47
# File 'lib/libgems/source_info_cache.rb', line 45

def self.cache_data
  cache.cache_data
end

.latest_system_cache_fileObject

The name of the system cache file.



52
53
54
55
# File 'lib/libgems/source_info_cache.rb', line 52

def self.latest_system_cache_file
  File.join File.dirname(system_cache_file),
            "latest_#{File.basename system_cache_file}"
end

.latest_user_cache_fileObject

The name of the latest user cache file.



60
61
62
63
# File 'lib/libgems/source_info_cache.rb', line 60

def self.latest_user_cache_file
  File.join File.dirname(user_cache_file),
            "latest_#{File.basename user_cache_file}"
end

.resetObject

Reset all singletons, discarding any changes.



68
69
70
71
72
# File 'lib/libgems/source_info_cache.rb', line 68

def self.reset
  @cache = nil
  @system_cache_file = nil
  @user_cache_file = nil
end

.search(*args) ⇒ Object

Search all source indexes. See LibGems::SourceInfoCache#search.



77
78
79
# File 'lib/libgems/source_info_cache.rb', line 77

def self.search(*args)
  cache.search(*args)
end

.search_with_source(*args) ⇒ Object

Search all source indexes returning the source_uri. See LibGems::SourceInfoCache#search_with_source.



85
86
87
# File 'lib/libgems/source_info_cache.rb', line 85

def self.search_with_source(*args)
  cache.search_with_source(*args)
end

.system_cache_fileObject

The name of the system cache file. (class method)



92
93
94
# File 'lib/libgems/source_info_cache.rb', line 92

def self.system_cache_file
  @system_cache_file ||= LibGems.default_system_source_cache_dir
end

.user_cache_fileObject

The name of the user cache file.



99
100
101
102
# File 'lib/libgems/source_info_cache.rb', line 99

def self.user_cache_file
  @user_cache_file ||=
    ENV['LIBGEMSCACHE'] || ENV['GEMCACHE'] || LibGems.default_user_source_cache_dir
end

Instance Method Details

#cache_dataObject

The most recent cache data.



114
115
116
117
118
119
120
121
122
123
# File 'lib/libgems/source_info_cache.rb', line 114

def cache_data
  return @cache_data if @cache_data
  cache_file # HACK writable check

  @only_latest = true

  @cache_data = read_cache_data latest_cache_file

  @cache_data
end

#cache_fileObject

The name of the cache file.



128
129
130
131
132
133
# File 'lib/libgems/source_info_cache.rb', line 128

def cache_file
  return @cache_file if @cache_file
  @cache_file = (try_file(system_cache_file) or
    try_file(user_cache_file) or
    raise "unable to locate a writable cache file")
end

#flushObject

Write the cache to a local file (if it is dirty).



138
139
140
141
# File 'lib/libgems/source_info_cache.rb', line 138

def flush
  write_cache if @dirty
  @dirty = false
end

#latest_cache_dataObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/libgems/source_info_cache.rb', line 143

def latest_cache_data
  latest_cache_data = {}

  cache_data.each do |repo, sice|
    latest = sice.source_index.latest_specs

    new_si = LibGems::SourceIndex.new
    new_si.add_specs(*latest)

    latest_sice = LibGems::SourceInfoCacheEntry.new new_si, sice.size
    latest_cache_data[repo] = latest_sice
  end

  latest_cache_data
end

#latest_cache_fileObject

The name of the latest cache file.



162
163
164
# File 'lib/libgems/source_info_cache.rb', line 162

def latest_cache_file
  File.join File.dirname(cache_file), "latest_#{File.basename cache_file}"
end

#latest_system_cache_fileObject

The name of the latest system cache file.



169
170
171
# File 'lib/libgems/source_info_cache.rb', line 169

def latest_system_cache_file
  self.class.latest_system_cache_file
end

#latest_user_cache_fileObject

The name of the latest user cache file.



176
177
178
# File 'lib/libgems/source_info_cache.rb', line 176

def latest_user_cache_file
  self.class.latest_user_cache_file
end

#read_all_cache_dataObject

Merges the complete cache file into this LibGems::SourceInfoCache.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/libgems/source_info_cache.rb', line 183

def read_all_cache_data
  if @only_latest then
    @only_latest = false
    all_data = read_cache_data cache_file

    cache_data.update all_data do |source_uri, latest_sice, all_sice|
      all_sice.source_index.gems.update latest_sice.source_index.gems

      LibGems::SourceInfoCacheEntry.new all_sice.source_index, latest_sice.size
    end

    begin
      refresh true
    rescue LibGems::RemoteFetcher::FetchError
    end
  end
end

#read_cache_data(file) ⇒ Object

Reads cached data from file.



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/libgems/source_info_cache.rb', line 204

def read_cache_data(file)
  # Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
  data = open file, 'rb' do |fp| fp.read end
  cache_data = Marshal.load data

  cache_data.each do |url, sice|
    next unless sice.is_a?(Hash)
    update

    cache = sice['cache']
    size  = sice['size']

    if cache.is_a?(LibGems::SourceIndex) and size.is_a?(Numeric) then
      new_sice = LibGems::SourceInfoCacheEntry.new cache, size
      cache_data[url] = new_sice
    else # irreperable, force refetch.
      reset_cache_for url, cache_data
    end
  end

  cache_data
rescue Errno::ENOENT
  {}
rescue => e
  if LibGems.configuration.really_verbose then
    say "Exception during cache_data handling: #{e.class} - #{e}"
    say "Cache file was: #{file}"
    say "\t#{e.backtrace.join "\n\t"}"
  end

  {}
end

#refresh(all) ⇒ Object

Refreshes each source in the cache from its repository. If all is false, only latest gems are updated.



241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/libgems/source_info_cache.rb', line 241

def refresh(all)
  LibGems.sources.each do |source_uri|
    cache_entry = cache_data[source_uri]
    if cache_entry.nil? then
      cache_entry = LibGems::SourceInfoCacheEntry.new nil, 0
      cache_data[source_uri] = cache_entry
    end

    update if cache_entry.refresh source_uri, all
  end

  flush
end

#reset_cache_dataObject



265
266
267
268
# File 'lib/libgems/source_info_cache.rb', line 265

def reset_cache_data
  @cache_data = nil
  @only_latest = true
end

#reset_cache_fileObject

Force cache file to be reset, useful for integration testing of rubygems



273
274
275
# File 'lib/libgems/source_info_cache.rb', line 273

def reset_cache_file
  @cache_file = nil
end

#reset_cache_for(url, cache_data) ⇒ Object



255
256
257
258
259
260
261
262
263
# File 'lib/libgems/source_info_cache.rb', line 255

def reset_cache_for(url, cache_data)
  say "Reseting cache for #{url}" if LibGems.configuration.really_verbose

  sice = LibGems::SourceInfoCacheEntry.new LibGems::SourceIndex.new, 0
  sice.refresh url, false # HACK may be unnecessary, see ::cache and #refresh

  cache_data[url] = sice
  cache_data
end

#search(pattern, platform_only = false, all = false) ⇒ Object

Searches all source indexes. See LibGems::SourceIndex#search for details on pattern and platform_only. If all is set to true, the full index will be loaded before searching.



282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/libgems/source_info_cache.rb', line 282

def search(pattern, platform_only = false, all = false)
  read_all_cache_data if all

  cache_data.map do |source_uri, sic_entry|
    next unless LibGems.sources.include? source_uri
    # TODO - Remove this gunk after 2008/11
    unless pattern.kind_of? LibGems::Dependency then
      pattern = LibGems::Dependency.new pattern, LibGems::Requirement.default
    end
    sic_entry.source_index.search pattern, platform_only
  end.flatten.compact
end

#search_with_source(pattern, only_platform = false, all = false) ⇒ Object

Searches all source indexes for pattern. If only_platform is true, only gems matching LibGems.platforms will be selected. Returns an Array of pairs containing the LibGems::Specification found and the source_uri it was found at.



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/libgems/source_info_cache.rb', line 301

def search_with_source(pattern, only_platform = false, all = false)
  read_all_cache_data if all

  results = []

  cache_data.map do |source_uri, sic_entry|
    next unless LibGems.sources.include? source_uri

    # TODO - Remove this gunk after 2008/11
    unless pattern.kind_of?(LibGems::Dependency)
      pattern = LibGems::Dependency.new(pattern, LibGems::Requirement.default) 
    end

    sic_entry.source_index.search(pattern, only_platform).each do |spec|
      results << [spec, source_uri]
    end
  end

  results
end

#set_cache_data(hash) ⇒ Object

Set the source info cache data directly. This is mainly used for unit testing when we don’t want to read a file system to grab the cached source index information. The hash should map a source URL into a SourceInfoCacheEntry.



328
329
330
331
# File 'lib/libgems/source_info_cache.rb', line 328

def set_cache_data(hash)
  @cache_data = hash
  update
end

#system_cache_fileObject

The name of the system cache file.



336
337
338
# File 'lib/libgems/source_info_cache.rb', line 336

def system_cache_file
  self.class.system_cache_file
end

#try_file(path) ⇒ Object

Determine if path is a candidate for a cache file. Returns path if it is, nil if not.



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/libgems/source_info_cache.rb', line 344

def try_file(path)
  return path if File.writable? path
  return nil if File.exist? path

  dir = File.dirname path

  unless File.exist? dir then
    begin
      FileUtils.mkdir_p dir
    rescue RuntimeError, SystemCallError
      return nil
    end
  end

  return path if File.writable? dir

  nil
end

#updateObject

Mark the cache as updated (i.e. dirty).



366
367
368
# File 'lib/libgems/source_info_cache.rb', line 366

def update
  @dirty = true
end

#user_cache_fileObject

The name of the user cache file.



373
374
375
# File 'lib/libgems/source_info_cache.rb', line 373

def user_cache_file
  self.class.user_cache_file
end

#write_cacheObject

Write data to the proper cache files.



380
381
382
383
384
385
386
387
388
389
390
# File 'lib/libgems/source_info_cache.rb', line 380

def write_cache
  if not File.exist?(cache_file) or not @only_latest then
    open cache_file, 'wb' do |io|
      io.write Marshal.dump(cache_data)
    end
  end

  open latest_cache_file, 'wb' do |io|
    io.write Marshal.dump(latest_cache_data)
  end
end