artagnon/clayoven

View on GitHub
lib/clayoven/git.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# \Git \metadata information for the clayoven repository
#
# Information from the git index via new is cheap, but metadata is expensive due to the `git log --follow`
# invocation.
class Clayoven::Git
  # Look at the git index immediately; accepts a Clayoven::Config#tzmap hashtable
  def initialize(tzmap)
    git_ns = `git diff --name-status @ 2>/dev/null`
    @tzmap = tzmap
    @untracked = `git ls-files --others --exclude-standard`.split "\n"
    if !git_ns.empty?
      git_index = git_ns.split("\n").map { |line| line.split("\t")[0..1] }
      git_mod_index = git_index.select { |idx| idx.first == "M" }
      @modified = git_mod_index.map(&:last)
      @added = (git_index - git_mod_index).map(&:last)
    else
      @modified = []
      @added = []
    end
  end

  # Return the toplevel directory in the git tree, or an empty string
  def self.toplevel
    `git rev-parse --show-toplevel 2>/dev/null`.strip
  end

  # Indicates if a file was modified, from git index
  def modified?(file)
    @modified.any?(file) || @untracked.any?(file)
  end

  # Indicates if a file was added, from git index
  def added?(file)
    @added.any?(file) || @untracked.any?(file)
  end

  # Indicates if any of the files in the list of files were added, from git index
  def any_added?(files)
    files.any? { |file| added? file }
  end

  # Indicates if any of the files in the list of files were added or modified, from git index
  def added_or_modified?(file)
    added?(file) || modified?(file)
  end

  # Indicates if the config or the template was changed, in a way that requires a full rebuild
  def template_changed?
    modified?("design/template.slim") || modified?(".clayoven/hidden") ||
      modified?(".clayoven/tz") || modified?(".clayoven/subtopics")
  end

  # Indicates if `design/style.sass` or `design/script.js` was changed
  def design_changed?
    modified?("design/style.sass") || modified?("design/script.js")
  end

  # Returns a `[#{Last modified timestamp} # {Creation timestamp} #{Location strings}]`
  # The timestamps default to `Time.now` if the file hasn't been committed.
  # Expensive compared to HTML generation by Claytext.
  def metadata(file)
    dates =
      `git log --follow --format="%aD" --date=unix #{file} 2>/dev/null`.split(
        "\n"
      )
        .map { |d| Time.parse d }
    locs =
      dates.map { |d| d.strftime("%z") }.map { |tz| @tzmap[tz] }.flatten.uniq
    return Time.now, Time.now, locs unless dates.first

    lastmod = added_or_modified?(file) ? Time.now : dates.first
    [lastmod, dates.last, locs]
  end
end