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.


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

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

Class Attribute Details

.inhibit_cleanupObject

Returns the value of attribute inhibit_cleanup


96
97
98
# File 'lib/rubocop/result_cache.rb', line 96

def inhibit_cleanup
  @inhibit_cleanup
end

.source_checksumObject

Returns the value of attribute source_checksum


96
97
98
# File 'lib/rubocop/result_cache.rb', line 96

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.


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

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


24
25
26
# File 'lib/rubocop/result_cache.rb', line 24

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

#save(offenses, disabled_line_ranges, comments) ⇒ Object


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

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, 'wb') 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)

20
21
22
# File 'lib/rubocop/result_cache.rb', line 20

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