Class: RuboCop::ResultCache Private

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

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Provides functionality for caching rubocop runs.

Constant Summary collapse

NON_CHANGING =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%i[color format formatters out debug fail_level auto_correct
cache fail_fast stdin parallel].freeze

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of ResultCache.


88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rubocop/result_cache.rb', line 88

def initialize(file, team, options, config_store, cache_root = nil)
  cache_root ||= options[:cache_root]
  cache_root ||= ResultCache.cache_root(config_store)
  @allow_symlinks_in_cache_location =
    ResultCache.allow_symlinks_in_cache_location?(config_store)
  @path = File.join(cache_root,
                    rubocop_checksum,
                    context_checksum(team, options),
                    file_checksum(file, config_store))
  @cached_data = CachedData.new(file)
  @debug = options[:debug]
end

Class Attribute Details

.inhibit_cleanupObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


174
175
176
# File 'lib/rubocop/result_cache.rb', line 174

def inhibit_cleanup
  @inhibit_cleanup
end

.rubocop_required_featuresObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


35
36
37
# File 'lib/rubocop/result_cache.rb', line 35

def rubocop_required_features
  @rubocop_required_features
end

.source_checksumObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


174
175
176
# File 'lib/rubocop/result_cache.rb', line 174

def source_checksum
  @source_checksum
end

Instance Attribute Details

#pathObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


86
87
88
# File 'lib/rubocop/result_cache.rb', line 86

def path
  @path
end

Class Method Details

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

82
83
84
# File 'lib/rubocop/result_cache.rb', line 82

def self.allow_symlinks_in_cache_location?(config_store)
  config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
end

.cache_root(config_store) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rubocop/result_cache.rb', line 69

def self.cache_root(config_store)
  root = ENV['RUBOCOP_CACHE_ROOT']
  root ||= config_store.for_pwd.for_all_cops['CacheRootDirectory']
  root ||= if ENV.key?('XDG_CACHE_HOME')
             # Include user ID in the path to make sure the user has write
             # access.
             File.join(ENV['XDG_CACHE_HOME'], Process.uid.to_s)
           else
             File.join(ENV['HOME'], '.cache')
           end
  File.join(root, 'rubocop_cache')
end

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

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Remove old files so that the cache doesn't grow too big. When the threshold MaxFilesInCache has been exceeded, the oldest 50% of 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.


21
22
23
24
25
26
27
28
29
30
31
# File 'lib/rubocop/result_cache.rb', line 21

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) }
  return unless requires_file_removal?(files.length, config_store)

  remove_oldest_files(files, dirs, cache_root, verbose)
end

Instance Method Details

#debug?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

101
102
103
# File 'lib/rubocop/result_cache.rb', line 101

def debug?
  @debug
end

#loadObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


109
110
111
112
# File 'lib/rubocop/result_cache.rb', line 109

def load
  puts "Loading cache from #{@path}" if debug?
  @cached_data.from_json(IO.read(@path, encoding: Encoding::UTF_8))
end

#save(offenses) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rubocop/result_cache.rb', line 114

def save(offenses)
  dir = File.dirname(@path)

  begin
    FileUtils.mkdir_p(dir)
  rescue Errno::EACCES, Errno::EROFS => e
    warn "Couldn't create cache directory. Continuing without cache."\
         "\n  #{e.message}"
    return
  end

  preliminary_path = "#{@path}_#{rand(1_000_000_000)}"
  # RuboCop must be in control of where its cached data is stored. A
  # symbolic link anywhere in the cache directory tree can be an
  # indication that a symlink attack is being waged.
  return if symlink_protection_triggered?(dir)

  File.open(preliminary_path, 'w', encoding: Encoding::UTF_8) do |f|
    f.write(@cached_data.to_json(offenses))
  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

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

105
106
107
# File 'lib/rubocop/result_cache.rb', line 105

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