class Jekyll::Regenerator

def add(path)

Returns true, also on failure.

Add a path to the metadata
def add(path)
  return true unless File.exist?(path)
  metadata[path] = {
    "mtime" => File.mtime(path),
    "deps"  => [],
  }
  cache[path] = true
end

def add_dependency(path, dependency)

Returns nothing.

Add a dependency of a path
def add_dependency(path, dependency)
  return if metadata[path].nil? || disabled
  unless metadata[path]["deps"].include? dependency
    metadata[path]["deps"] << dependency
    add(dependency) unless metadata.include?(dependency)
  end
  regenerate? dependency
end

def clear

Returns nothing

Clear the metadata and cache
def clear
  @metadata = {}
  clear_cache
end

def clear_cache

Returns nothing

Clear just the cache
def clear_cache
  @cache = {}
end

def disabled?

Returns a Boolean (true for disabled, false for enabled).

Check if metadata has been disabled
def disabled?
  self.disabled = !site.incremental? if disabled.nil?
  disabled
end

def existing_file_modified?(path)

def existing_file_modified?(path)
  # If one of this file dependencies have been modified,
  # set the regeneration bit for both the dependency and the file to true
  metadata[path]["deps"].each do |dependency|
    return cache[dependency] = cache[path] = true if modified?(dependency)
  end
  if File.exist?(path) && metadata[path]["mtime"].eql?(File.mtime(path))
    # If this file has not been modified, set the regeneration bit to false
    cache[path] = false
  else
    # If it has been modified, set it to true
    add(path)
  end
end

def force(path)

Returns true.

Force a path to regenerate
def force(path)
  cache[path] = true
end

def initialize(site)

def initialize(site)
  @site = site
  # Read metadata from file
  read_metadata
  # Initialize cache to an empty hash
  clear_cache
end

def metadata_file

Returns the String path of the file.

Produce the absolute path of the metadata file
def metadata_file
  @metadata_file ||= site.in_source_dir(".jekyll-metadata")
end

def modified?(path)

Returns a boolean.

mtime has changed
Checks if a path's (or one of its dependencies)
def modified?(path)
  return true if disabled?
  # objects that don't have a path are always regenerated
  return true if path.nil?
  # Check for path in cache
  return cache[path] if cache.key? path
  if metadata[path]
    # If we have seen this file before,
    # check if it or one of its dependencies has been modified
    existing_file_modified?(path)
  else
    # If we have not seen this file before, add it to the metadata and regenerate it
    add(path)
  end
end

def read_metadata

Returns the read metadata.

initialize with an empty hash
Read metadata from the metadata file, if no file is found,
def read_metadata
  @metadata =
    if !disabled? && File.file?(metadata_file)
      content = File.binread(metadata_file)
      begin
        Marshal.load(content)
      rescue TypeError
        SafeYAML.load(content)
      rescue ArgumentError => e
        Jekyll.logger.warn("Failed to load #{metadata_file}: #{e}")
        {}
      end
    else
      {}
    end
end

def regenerate?(document)

Returns a boolean.

Checks if a renderable object needs to be regenerated
def regenerate?(document)
  return true if disabled
  case document
  when Page
    regenerate_page?(document)
  when Document
    regenerate_document?(document)
  else
    source_path = document.respond_to?(:path) ? document.path : nil
    dest_path = document.destination(@site.dest) if document.respond_to?(:destination)
    source_modified_or_dest_missing?(source_path, dest_path)
  end
end

def regenerate_document?(document)

def regenerate_document?(document)
  !document.write? || document.data["regenerate"] ||
    source_modified_or_dest_missing?(
      document.path, document.destination(@site.dest)
    )
end

def regenerate_page?(document)

def regenerate_page?(document)
  document.asset_file? || document.data["regenerate"] ||
    source_modified_or_dest_missing?(
      site.in_source_dir(document.relative_path), document.destination(@site.dest)
    )
end

def source_modified_or_dest_missing?(source_path, dest_path)

returns a boolean

destination is missing
Checks if the source has been modified or the
def source_modified_or_dest_missing?(source_path, dest_path)
  modified?(source_path) || (dest_path && !File.exist?(dest_path))
end

def write_metadata

Returns nothing.

Write the metadata to disk
def write_metadata
  unless disabled?
    Jekyll.logger.debug "Writing Metadata:", ".jekyll-metadata"
    File.binwrite(metadata_file, Marshal.dump(metadata))
  end
end