2018-11-09 13:39:43 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-01-04 13:43:06 -05:00
|
|
|
module Gitlab
|
|
|
|
module Git
|
|
|
|
class Blame
|
2017-06-01 17:21:14 -04:00
|
|
|
include Gitlab::EncodingHelper
|
2017-01-04 13:43:06 -05:00
|
|
|
|
|
|
|
attr_reader :lines, :blames
|
|
|
|
|
|
|
|
def initialize(repository, sha, path)
|
|
|
|
@repo = repository
|
|
|
|
@sha = sha
|
|
|
|
@path = path
|
|
|
|
@lines = []
|
|
|
|
@blames = load_blame
|
|
|
|
end
|
|
|
|
|
|
|
|
def each
|
|
|
|
@blames.each do |blame|
|
2018-05-08 09:13:43 -04:00
|
|
|
yield(blame.commit, blame.line)
|
2017-01-04 13:43:06 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def load_blame
|
2018-06-13 10:44:59 -04:00
|
|
|
output = encode_utf8(@repo.gitaly_commit_client.raw_blame(@sha, @path))
|
2017-07-28 08:16:26 -04:00
|
|
|
|
2018-06-13 10:44:59 -04:00
|
|
|
process_raw_blame(output)
|
2017-07-28 08:16:26 -04:00
|
|
|
end
|
|
|
|
|
2017-01-04 13:43:06 -05:00
|
|
|
def process_raw_blame(output)
|
|
|
|
lines, final = [], []
|
|
|
|
info, commits = {}, {}
|
|
|
|
|
|
|
|
# process the output
|
|
|
|
output.split("\n").each do |line|
|
|
|
|
if line[0, 1] == "\t"
|
|
|
|
lines << line[1, line.size]
|
|
|
|
elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
|
|
|
|
commit_id, old_lineno, lineno = m[1], m[2].to_i, m[3].to_i
|
|
|
|
commits[commit_id] = nil unless commits.key?(commit_id)
|
|
|
|
info[lineno] = [commit_id, old_lineno]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-05-08 09:13:43 -04:00
|
|
|
Gitlab::Git::Commit.batch_by_oid(@repo, commits.keys).each do |commit|
|
|
|
|
commits[commit.sha] = commit
|
2017-01-04 13:43:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
# get it together
|
|
|
|
info.sort.each do |lineno, (commit_id, old_lineno)|
|
|
|
|
commit = commits[commit_id]
|
|
|
|
final << BlameLine.new(lineno, old_lineno, commit, lines[lineno - 1])
|
|
|
|
end
|
|
|
|
|
|
|
|
@lines = final
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class BlameLine
|
|
|
|
attr_accessor :lineno, :oldlineno, :commit, :line
|
|
|
|
def initialize(lineno, oldlineno, commit, line)
|
|
|
|
@lineno = lineno
|
|
|
|
@oldlineno = oldlineno
|
|
|
|
@commit = commit
|
|
|
|
@line = line
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|