Class: GitSpelunk::Blame

Inherits:
Object
  • Object
show all
Defined in:
lib/git_spelunk/blame.rb

Instance Method Summary collapse

Constructor Details

#initialize(repo, file, sha) ⇒ Blame

Returns a new instance of Blame.



7
8
9
10
11
12
# File 'lib/git_spelunk/blame.rb', line 7

def initialize(repo, file, sha)
  @lines = nil
  @repo = repo
  @file = file
  @sha = sha
end

Instance Method Details

#linesObject



14
15
16
17
18
19
# File 'lib/git_spelunk/blame.rb', line 14

def lines
  return @lines if @lines
  cmd = ["git", "--git-dir", @repo.path, "blame", "--porcelain", @sha, "--", @file]
  output, err, status = Open3.capture3(*cmd)
  @lines ||= process_raw_blame(output)
end

#process_raw_blame(output) ⇒ Object

Raises:



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/git_spelunk/blame.rb', line 21

def process_raw_blame(output)
  lines = []
  commits = {}
  commit_file_map = {}

  raise EmptyBlame.new if output.empty?

  split_output = output.split(/^(\w{40} \d+ \d+(?: \d+)?\n)/m)
  split_output.shift if split_output.first.empty?

  lines = split_output.each_slice(2).map do |sha_line, rest|
    sha_split = sha_line.split(' ')

    sha, old_lineno, lineno = sha_split[0], sha_split[1].to_i, sha_split[2].to_i

    commits[sha] ||= @repo.lookup(sha)

    if rest =~ /^filename (.*)$/
      commit_file_map[sha] = $1
    end

    data = rest.split("\n").detect { |l| l[0] == "\t" }[1..-1]
    { :data => data, :sha => sha, :filename => commit_file_map[sha], :old_line_number => old_lineno, :line_number => lineno }
  end

  lines.map do |hash|
    GitSpelunk::BlameLine.new(hash[:line_number], hash[:old_line_number], hash[:sha], commits[hash[:sha]], hash[:filename], hash[:data])
  end
end