Class: RuboCop::ResultCache

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/result_cache.rb

Overview

Provides functionality for caching rubocop runs.

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, options, config_store, cache_root = nil) ⇒ ResultCache

Include the user name in the path as a simple means of avoiding write collisions.



12
13
14
15
16
# File 'lib/rubocop/result_cache.rb', line 12

def initialize(file, options, config_store, cache_root = nil)
  cache_root ||= ResultCache.cache_root(config_store)
  @path = File.join(cache_root, rubocop_checksum, relevant_options(options),
                    file_checksum(file, config_store))
end

Class Attribute Details

.inhibit_cleanupObject

Returns the value of attribute inhibit_cleanup.



94
95
96
# File 'lib/rubocop/result_cache.rb', line 94

def inhibit_cleanup
  @inhibit_cleanup
end

.source_checksumObject

Returns the value of attribute source_checksum.



94
95
96
# File 'lib/rubocop/result_cache.rb', line 94

def source_checksum
  @source_checksum
end

Class Method Details

.cleanup(config_store, verbose, cache_root = nil) ⇒ Object

Remove old files so that the cache doesn't grow too big. When the threshold MaxFilesInCache has been exceeded, the oldest 50% all the files in the cache are removed. The reason for removing so much is that cleaning should be done relatively seldom, since there is a slight risk that some other RuboCop process was just about to read the file, when there's parallel execution and the cache is shared.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rubocop/result_cache.rb', line 50

def self.cleanup(config_store, verbose, cache_root = nil)
  return if inhibit_cleanup # OPTIMIZE: For faster testing
  cache_root ||= cache_root(config_store)
  return unless File.exist?(cache_root)

  files, dirs = Find.find(cache_root).partition { |path| File.file?(path) }
  if files.length > config_store.for('.')['AllCops']['MaxFilesInCache'] &&
     files.length > 1
    # Add 1 to half the number of files, so that we remove the file if
    # there's only 1 left.
    remove_count = 1 + files.length / 2
    if verbose
      puts "Removing the #{remove_count} oldest files from #{cache_root}"
    end
    sorted = files.sort_by { |path| File.mtime(path) }
    begin
      sorted[0, remove_count].each { |path| File.delete(path) }
      dirs.each { |dir| Dir.rmdir(dir) if Dir["#{dir}/*"].empty? }
    rescue Errno::ENOENT
      # This can happen if parallel RuboCop invocations try to remove the
      # same files. No problem.
      puts $ERROR_INFO if verbose
    end
  end
end

Instance Method Details

#loadObject



22
23
24
# File 'lib/rubocop/result_cache.rb', line 22

def load
  Marshal.load(IO.read(@path))
end

#save(offenses, disabled_line_ranges, comments) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rubocop/result_cache.rb', line 26

def save(offenses, disabled_line_ranges, comments)
  FileUtils.mkdir_p(File.dirname(@path))
  preliminary_path = "#{@path}_#{rand(1_000_000_000)}"
  File.open(preliminary_path, 'w') do |f|
    # The Hash[x.sort] call is a trick that converts a Hash with a default
    # block to a Hash without a default block. Thus making it possible to
    # dump.
    f.write(Marshal.dump([offenses, Hash[disabled_line_ranges.sort],
                          comments]))
  end
  # The preliminary path is used so that if there are multiple RuboCop
  # processes trying to save data for the same inspected file
  # simultaneously, the only problem we run in to is a competition who gets
  # to write to the final file. The contents are the same, so no corruption
  # of data should occur.
  FileUtils.mv(preliminary_path, @path)
end

#valid?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/rubocop/result_cache.rb', line 18

def valid?
  File.exist?(@path)
end