From 5db08804b8fb3ecc6f48b19642790782733e0e21 Mon Sep 17 00:00:00 2001 From: Christian Bruckmayer Date: Wed, 4 Nov 2020 18:08:57 +0000 Subject: [PATCH] Implement file cache First approach to implement a file cache. https://github.com/Shopify/erb-lint/issues/158 Co-authored-by: Mike Dalessio --- lib/erb_lint.rb | 1 + lib/erb_lint/cache.rb | 47 +++++++++++++++++++++++++++++++++++++++++++ lib/erb_lint/cli.rb | 37 +++++++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 lib/erb_lint/cache.rb diff --git a/lib/erb_lint.rb b/lib/erb_lint.rb index 2e235e3b..55006cee 100644 --- a/lib/erb_lint.rb +++ b/lib/erb_lint.rb @@ -3,6 +3,7 @@ require 'rubocop' require 'erb_lint/corrector' +require 'erb_lint/cache' require 'erb_lint/file_loader' require 'erb_lint/linter_config' require 'erb_lint/linter_registry' diff --git a/lib/erb_lint/cache.rb b/lib/erb_lint/cache.rb new file mode 100644 index 00000000..72d16f6f --- /dev/null +++ b/lib/erb_lint/cache.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module ERBLint + class Cache + CACHE_DIRECTORY = '.erb-lint-cache' + private_constant :CACHE_DIRECTORY + + def initialize(config) + @config = config.to_hash + end + + def [](filename) + JSON.parse(File.read(File.join(CACHE_DIRECTORY, checksum(filename)))) + end + + def include?(filename) + File.exist?(File.join(CACHE_DIRECTORY, checksum(filename))) + end + + def []=(filename, messages) + FileUtils.mkdir_p(CACHE_DIRECTORY) + + File.open(File.join(CACHE_DIRECTORY, checksum(filename)), 'wb') do |f| + f.write messages.to_json + end + end + + private + + attr_reader :config + + def checksum(file) + digester = Digest::SHA1.new + mode = File.stat(file).mode + + digester.update( + "#{file}#{mode}#{config.to_s}" + ) + digester.file(file) + digester.hexdigest + rescue Errno::ENOENT + # Spurious files that come and go should not cause a crash, at least not + # here. + '_' + end + end +end diff --git a/lib/erb_lint/cli.rb b/lib/erb_lint/cli.rb index 46c204f6..6aba0851 100644 --- a/lib/erb_lint/cli.rb +++ b/lib/erb_lint/cli.rb @@ -38,6 +38,7 @@ def run(args = ARGV) @files = dupped_args load_config + @cache = Cache.new(config) if !@files.empty? && lint_files.empty? failure!("no files found...\n") @@ -60,7 +61,7 @@ def run(args = ARGV) lint_files.each do |filename| runner.clear_offenses begin - run_with_corrections(runner, filename) + puts run_on_file(runner, filename) rescue => e @stats.exceptions += 1 puts "Exception occured when processing: #{relative_filename(filename)}" @@ -101,10 +102,36 @@ def run(args = ARGV) private + attr_reader :cache, :config + + def run_on_file(runner, filename) + if with_cache? && !autocorrect? + run_using_cache(runner, filename) + else + run_with_corrections(runner, filename) + end + end + + def run_using_cache(runner, filename) + puts cache.include?(filename) + if cache.include?(filename) && !autocorrect? + result = cache[filename] + @stats.found += result.size + result + else + result = run_with_corrections(runner, filename) + cache[filename] = result + end + end + def autocorrect? @options[:autocorrect] end + def with_cache? + @options[:with_cache] + end + def run_with_corrections(runner, filename) file_content = File.read(filename, encoding: Encoding::UTF_8) @@ -128,8 +155,8 @@ def run_with_corrections(runner, filename) end @stats.found += runner.offenses.size - runner.offenses.each do |offense| - puts <<~EOF + runner.offenses.map do |offense| + <<~EOF #{offense.message}#{Rainbow(' (not autocorrected)').red if autocorrect?} In file: #{relative_filename(filename)}:#{offense.line_range.begin} @@ -266,6 +293,10 @@ def option_parser @options[:enabled_linters] = known_linter_names end + opts.on("--with_cache", "Enable caching") do |config| + @options[:with_cache] = config + end + opts.on("--enable-linters LINTER[,LINTER,...]", Array, "Only use specified linter", "Known linters are: #{known_linter_names.join(', ')}") do |linters| linters.each do |linter|