class GitCommitMailer::FileDiff

Constants

CHANGED_TYPE

Attributes

changes[R]
index[RW]

Public Class Methods

new(mailer, lines, revision) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 30
def initialize(mailer, lines, revision)
  @mailer = mailer
  @index = nil
  @body = ''
  @changes = []

  @type = :modified
  @is_binary = false
  @is_mode_changed = false

  @old_blob = @new_blob = nil

  parse_header(lines)
  detect_metadata(revision)
  parse_extended_headers(lines)
  parse_body(lines)
end

Public Instance Methods

file_path() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 48
def file_path
  @to_file
end
format() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 61
def format
  formatted_diff = format_header

  if @mailer.add_diff?
    formatted_diff << headers + @body
  else
    formatted_diff << git_command
  end

  formatted_diff
end
format_header() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 52
def format_header
  header = "  #{CHANGED_TYPE[@type]}: #{@to_file} "
  header << "(+#{@added_line} -#{@deleted_line})"
  header << "#{format_file_mode}#{format_similarity_index}\n"
  header << "  Mode: #{@old_mode} -> #{@new_mode}\n" if @is_mode_changed
  header << diff_separator
  header
end

Private Instance Methods

detect_metadata(revision) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 98
def detect_metadata(revision)
  @new_revision = revision
  @new_date = Time.at(@mailer.get_record(@new_revision, "%at").to_i)

  begin
    @old_revision = @mailer.parent_commit(revision)
    @old_date = Time.at(@mailer.get_record(@old_revision, "%at").to_i)
  rescue NoParentCommit
    @old_revision = '0' * 40
    @old_date = nil
  end
  # @old_revision = @mailer.parent_commit(revision)
end
diff_separator() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 359
def diff_separator
  "#{"=" * 67}\n"
end
extract_file_path(file_path) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 74
def extract_file_path(file_path)
  case CommitInfo.unescape_file_path(file_path)
  when /\A[ab]\/(.*)\z/
    $1
  else
    raise "unknown file path format: #{@to_file}"
  end
end
format_blob(blob) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 256
def format_blob(blob)
  if blob
    " (#{blob})"
  else
    ""
  end
end
format_date(date) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 236
def format_date(date)
  date.strftime('%Y-%m-%d %X %z')
end
format_file_mode() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 340
def format_file_mode
  case @type
  when :added
    " #{@new_file_mode}"
  when :deleted
    " #{@deleted_file_mode}"
  else
    ""
  end
end
format_new_blob() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 264
def format_new_blob
  format_blob(@new_blob)
end
format_new_date() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 244
def format_new_date
  format_date(@new_date)
end
format_new_date_and_blob() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 276
def format_new_date_and_blob
  format_new_date + format_new_blob
end
format_old_blob() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 268
def format_old_blob
  format_blob(@old_blob)
end
format_old_date() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 240
def format_old_date
  format_date(@old_date)
end
format_old_date_and_blob() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 272
def format_old_date_and_blob
  format_old_date + format_old_blob
end
format_similarity_index() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 351
def format_similarity_index
  if @type == :renamed or @type == :copied
    " #{@similarity_index}%"
  else
    ""
  end
end
from_header() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 280
def from_header
  "--- #{@from_file}    #{format_old_date_and_blob}\n"
end
git_command() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 307
def git_command
  case @type
  when :added
    command = "show"
    args = ["#{short_new_revision}:#{@to_file}"]
  when :deleted
    command = "show"
    args = ["#{short_old_revision}:#{@to_file}"]
  when :modified
    command = "diff"
    args = [short_old_revision, short_new_revision, "--", @to_file]
  when :renamed
    command = "diff"
    args = [
      "-C", "--diff-filter=R",
      short_old_revision, short_new_revision, "--",
      @from_file, @to_file,
    ]
  when :copied
    command = "diff"
    args = [
      "-C", "--diff-filter=C",
      short_old_revision, short_new_revision, "--",
      @from_file, @to_file,
    ]
  else
    raise "unknown diff type: #{@type}"
  end

  command += " #{args.join(' ')}" unless args.empty?
  "    % git #{command}\n"
end
headers() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 288
def headers
  if @is_binary
    "(Binary files differ)\n"
  else
    if (@type == :renamed || @type == :copied) && @similarity_index == 100
      return ""
    end

    case @type
    when :added
      "--- /dev/null\n" + to_header
    when :deleted
      from_header + "+++ /dev/null\n"
    else
      from_header + to_header
    end
  end
end
parse_add_and_remove(line) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 132
def parse_add_and_remove(line)
  case line
  when /\Anew file mode (.*)\z/
    @type = :added
    @new_file_mode = $1
  when /\Adeleted file mode (.*)\z/
    @type = :deleted
    @deleted_file_mode = $1
  else
    return false
  end
  true
end
parse_binary_file_change(line) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 160
def parse_binary_file_change(line)
  if line =~ /\ABinary files (.*) and (.*) differ\z/
    @is_binary = true
    if $1 == '/dev/null'
      @type = :added
    elsif $2 == '/dev/null'
      @type = :deleted
    else
      @type = :modified
    end
    true
  else
    false
  end
end
parse_body(lines) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 208
def parse_body(lines)
  @added_line = @deleted_line = 0
  from_offset = 0
  to_offset = 0
  lines.each do |line|
    case line
    when /\A@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)?/
      from_offset = $1.to_i
      to_offset = $2.to_i
      @changes << [:hunk_header, [from_offset, to_offset], line]
    when /\A\+/
      @added_line += 1
      @changes << [:added, to_offset, line]
      to_offset += 1
    when /\A\-/
      @deleted_line += 1
      @changes << [:deleted, from_offset, line]
      from_offset += 1
    else
      @changes << [:not_changed, [from_offset, to_offset], line]
      from_offset += 1
      to_offset += 1
    end

    @body << line + "\n"
  end
end
parse_copy_and_rename(line) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 146
def parse_copy_and_rename(line)
  case line
  when /\Arename (from|to) (.*)\z/
    @type = :renamed
  when /\Acopy (from|to) (.*)\z/
    @type = :copied
  when /\Asimilarity index (.*)%\z/
    @similarity_index = $1.to_i
  else
    return false
  end
  true
end
parse_extended_headers(lines) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 190
def parse_extended_headers(lines)
  line = lines.shift
  while line != nil and not line =~ /\A@@/
    is_parsed = false
    is_parsed ||= parse_ordinary_change(line)
    is_parsed ||= parse_add_and_remove(line)
    is_parsed ||= parse_copy_and_rename(line)
    is_parsed ||= parse_binary_file_change(line)
    is_parsed ||= parse_mode_change(line)
    unless is_parsed
      raise "unexpected extended line header: " + line
    end

    line = lines.shift
  end
  lines.unshift(line) if line
end
parse_header(lines) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 83
def parse_header(lines)
  line = lines.shift.strip
  case line
  when /\Adiff --git ("?a\/.*) ("?b\/.*)/
    @from_file = extract_file_path($1)
    @to_file = extract_file_path($2)
  when /\Adiff --(?:combined|cc) (.*?)/
    path = CommitInfo.unescape_file_path($1)
    @from_file = path
    @to_file = path
  else
    raise "Unexpected diff header format: #{line}"
  end
end
parse_mode_change(line) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 176
def parse_mode_change(line)
  case line
  when /\Aold mode (.*)\z/
    @old_mode = $1
    @is_mode_changed = true
  when /\Anew mode (.*)\z/
    @new_mode = $1
    @is_mode_changed = true
  else
    return false
  end
  true
end
parse_ordinary_change(line) click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 112
def parse_ordinary_change(line)
  case line
  when /\A--- (a\/.*|"a\/.*"|\/dev\/null)\z/
    @minus_file = CommitInfo.unescape_file_path($1)
    @type = :added if $1 == '/dev/null'
  when /\A\+\+\+ (b\/.*|"b\/.*"|\/dev\/null)\z/
    @plus_file = CommitInfo.unescape_file_path($1)
    @type = :deleted if $1 == '/dev/null'
  when /\Aindex ([0-9a-f]{7,})\.\.([0-9a-f]{7,})/
    @old_blob = $1
    @new_blob = $2
  when /\Aindex ([0-9a-f]{7,}),([0-9a-f]{7,}\.\.[0-9a-f]{7,})/
    @old_blob = $1
    @new_blob = $2
  else
    return false
  end
  true
end
short_new_revision() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 252
def short_new_revision
  GitCommitMailer.short_revision(@new_revision)
end
short_old_revision() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 248
def short_old_revision
  GitCommitMailer.short_revision(@old_revision)
end
to_header() click to toggle source
# File lib/git-commit-mailer/file-diff.rb, line 284
def to_header
  "+++ #{@to_file}    #{format_new_date_and_blob}\n"
end