lib/jekyll/cache.rb in jekyll-4.0.0.pre.alpha1 vs lib/jekyll/cache.rb in jekyll-4.0.0.pre.beta1

- old
+ new

@@ -2,41 +2,74 @@ require "digest" module Jekyll class Cache - # rubocop:disable Style/ClassVars - @@caches = {} - @@disk_cache_enabled = true + # class-wide base cache + @base_cache = {} + # class-wide directive to write cache to disk is enabled by default + @disk_cache_enabled = true + + class << self + # class-wide cache location + attr_accessor :cache_dir + + # class-wide directive to write cache to disk + attr_reader :disk_cache_enabled + + # class-wide base cache reader + attr_reader :base_cache + + # Disable Marshaling cached items to disk + def disable_disk_cache! + @disk_cache_enabled = false + end + + # Clear all caches + def clear + delete_cache_files + base_cache.each_value(&:clear) + end + + # Compare the current config to the cached config + # If they are different, clear all caches + # + # Returns nothing. + def clear_if_config_changed(config) + config = config.inspect + cache = Jekyll::Cache.new "Jekyll::Cache" + return if cache.key?("config") && cache["config"] == config + + clear + cache = Jekyll::Cache.new "Jekyll::Cache" + cache["config"] = config + nil + end + + private + + # Delete all cached items from all caches + # + # Returns nothing. + def delete_cache_files + FileUtils.rm_rf(@cache_dir) if disk_cache_enabled + end + end + + # + # Get an existing named cache, or create a new one if none exists # # name - name of the cache # # Returns nothing. def initialize(name) - @cache = @@caches[name] ||= {} + @cache = Jekyll::Cache.base_cache[name] ||= {} @name = name.gsub(%r![^\w\s-]!, "-") end - # Set class-wide base_dir - def self.base_dir=(dir_path) - @@base_dir = dir_path - end - - # Disable Marshaling cached items to disk - def self.disable_disk_cache! - @@disk_cache_enabled = false - end - # rubocop:enable Style/ClassVars - - # Clear all caches - def self.clear - delete_cache_files - @@caches.each_value(&:clear) - end - # Clear this particular cache def clear delete_cache_files @cache.clear end @@ -47,11 +80,11 @@ # Returns cached value def [](key) return @cache[key] if @cache.key?(key) path = path_to(hash(key)) - if @@disk_cache_enabled && File.file?(path) && File.readable?(path) + if disk_cache_enabled? && File.file?(path) && File.readable?(path) @cache[key] = load(path) else raise end end @@ -59,22 +92,21 @@ # Add an item to cache # # Returns nothing. def []=(key, value) @cache[key] = value - return unless @@disk_cache_enabled + return unless disk_cache_enabled? path = path_to(hash(key)) value = new Hash(value) if value.is_a?(Hash) && !value.default.nil? dump(path, value) rescue TypeError Jekyll.logger.debug "Cache:", "Cannot dump object #{key}" end - # If an item already exists in the cache, retrieve it - # Else execute code block, and add the result to the cache, and return that - # result + # If an item already exists in the cache, retrieve it. + # Else execute code block, and add the result to the cache, and return that result. def getset(key) self[key] rescue StandardError value = yield self[key] = value @@ -84,98 +116,73 @@ # Remove one particular item from the cache # # Returns nothing. def delete(key) @cache.delete(key) - return unless @@disk_cache_enabled - - path = path_to(hash(key)) - File.delete(path) + File.delete(path_to(hash(key))) if disk_cache_enabled? end # Check if `key` already exists in this cache # # Returns true if key exists in the cache, false otherwise def key?(key) # First, check if item is already cached in memory return true if @cache.key?(key) # Otherwise, it might be cached on disk # but we should not consider the disk cache if it is disabled - return false unless @@disk_cache_enabled + return false unless disk_cache_enabled? path = path_to(hash(key)) File.file?(path) && File.readable?(path) end - # Compare the current config to the cached config - # If they are different, clear all caches - # - # Returns nothing. - def self.clear_if_config_changed(config) - config = config.inspect - cache = Jekyll::Cache.new "Jekyll::Cache" - return if cache.key?("config") && cache["config"] == config - - clear - cache = Jekyll::Cache.new "Jekyll::Cache" - cache["config"] = config - nil + def disk_cache_enabled? + !!Jekyll::Cache.disk_cache_enabled end private - # Given a hashed key, return the path to where this item would be saved on - # disk + # Given a hashed key, return the path to where this item would be saved on disk. def path_to(hash = nil) - @base_dir ||= File.join(@@base_dir, @name) + @base_dir ||= File.join(Jekyll::Cache.cache_dir, @name) return @base_dir if hash.nil? File.join(@base_dir, hash[0..1], hash[2..-1]).freeze end - # Given a key, return a SHA2 hash that can be used for caching this item to - # disk + # Given a key, return a SHA2 hash that can be used for caching this item to disk. def hash(key) Digest::SHA2.hexdigest(key).freeze end # Remove all this caches items from disk # # Returns nothing. def delete_cache_files - FileUtils.rm_rf(path_to) if @@disk_cache_enabled + FileUtils.rm_rf(path_to) if disk_cache_enabled? end - # Delete all cached items from all caches - # - # Returns nothing. - def self.delete_cache_files - FileUtils.rm_rf(@@base_dir) if @@disk_cache_enabled - end - private_class_method :delete_cache_files - - # Load `path` from disk and return the result + # Load `path` from disk and return the result. # This MUST NEVER be called in Safe Mode # rubocop:disable Security/MarshalLoad def load(path) - raise unless @@disk_cache_enabled + raise unless disk_cache_enabled? cached_file = File.open(path, "rb") value = Marshal.load(cached_file) cached_file.close value end # rubocop:enable Security/MarshalLoad - # Given a path and a value, save value to disk at path + # Given a path and a value, save value to disk at path. # This should NEVER be called in Safe Mode # # Returns nothing. def dump(path, value) - return unless @@disk_cache_enabled + return unless disk_cache_enabled? - dir = File.dirname(path) - FileUtils.mkdir_p(dir) + FileUtils.mkdir_p(File.dirname(path)) File.open(path, "wb") do |cached_file| Marshal.dump(value, cached_file) end end end