Module: RailVerdict::Git::DiffParser

Defined in:
lib/rail_verdict/git/diff_parser.rb

Class Method Summary collapse

Class Method Details

.parse_changed_lines_unified(raw, changed_paths) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rail_verdict/git/diff_parser.rb', line 96

def parse_changed_lines_unified(raw, changed_paths)
  return {} if raw.nil? || raw.empty?

  return {} if changed_paths.nil? || changed_paths.empty?

  binary_set = Set.new
  changed_paths.each do |file|
    binary_set.add(file[:path]) if file[:binary]
    binary_set.add(file[:new_path]) if file[:binary] && file[:new_path]
  end

  segments = split_unified_by_nul(raw)
  line_set = {}
  segments.each do |segment|
    path, diff_text = segment
    normalized = normalize_path(path.to_s)
    next if binary_set.include?(normalized)
    next if diff_text.nil? || diff_text.empty?

    lines = parse_unified_hunks(diff_text)
    line_set[normalized] = lines.sort.freeze unless lines.empty?
  end
  line_set
end

.parse_name_status_nul(raw) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
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
50
51
52
53
54
# File 'lib/rail_verdict/git/diff_parser.rb', line 8

def parse_name_status_nul(raw)
  return [] if raw.nil? || raw.empty?

  parts = raw.split("\0")
  parts.pop if parts.last == ""
  files = []
  index = 0
  while index < parts.length
    entry = parts[index]
    break if entry.nil? || entry.empty?

    status_char = entry[0]
    case status_char
    when "R", "C"
      old_path = parts[index + 1]
      new_path = parts[index + 2]
      if old_path.nil? || new_path.nil?
        raise Git::Error, "malformed git name-status output (rename requires two paths)"
      end
      score = entry[1..].to_i
      files << ChangedFile.new(status: status_char == "R" ? :renamed : :copied, path: normalize_path(new_path), old_path: normalize_path(old_path), new_path: normalize_path(new_path), score: score, binary: false)
      index += 3
    when "A"
      path = parts[index + 1]
      raise Git::Error, "malformed git name-status output (added requires path)" if path.nil?

      files << ChangedFile.new(status: :added, path: normalize_path(path), old_path: nil, new_path: normalize_path(path), score: nil, binary: false)
      index += 2
    when "D"
      path = parts[index + 1]
      raise Git::Error, "malformed git name-status output (deleted requires path)" if path.nil?

      files << ChangedFile.new(status: :deleted, path: nil, old_path: normalize_path(path), new_path: nil, score: nil, binary: false)
      index += 2
    when "M", "T"
      path = parts[index + 1]
      raise Git::Error, "malformed git name-status output (modified requires path)" if path.nil?

      mapped = status_char == "T" ? :typechange : :modified
      files << ChangedFile.new(status: mapped, path: normalize_path(path), old_path: normalize_path(path), new_path: normalize_path(path), score: nil, binary: false)
      index += 2
    else
      raise Git::Error, "unexpected git name-status entry: #{entry.inspect}"
    end
  end
  files.sort_by { |file| (file.path || file.old_path || "").to_s }
end

.parse_numstat_nul(raw) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rail_verdict/git/diff_parser.rb', line 56

def parse_numstat_nul(raw)
  return {} if raw.nil? || raw.empty?

  parts = raw.split("\0")
  parts.pop if parts.last == ""
  result = {}
  parts.each do |entry|
    next if entry.empty?

    fields = entry.split("\t")
    next unless fields.length == 3

    added, deleted, path = fields
    binary = added == "-" || deleted == "-"
    result[normalize_path(path)] = { added: binary ? nil : added.to_i, deleted: binary ? nil : deleted.to_i, binary: binary }
  end
  result
end

.parse_numstat_rename_nul(raw) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rail_verdict/git/diff_parser.rb', line 75

def parse_numstat_rename_nul(raw)
  return {} if raw.nil? || raw.empty?

  parts = raw.split("\0")
  parts.pop if parts.last == ""
  result = {}
  parts.each do |entry|
    next if entry.empty?

    fields = entry.split("\t")
    next unless fields.length >= 3

    added, deleted = fields[0], fields[1]
    binary = added == "-" || deleted == "-"
    path = fields.length == 4 ? fields[3] : fields[2]
    key = normalize_path(path)
    result[key] = { added: binary ? nil : added.to_i, deleted: binary ? nil : deleted.to_i, binary: binary }
  end
  result
end

.split_unified_by_nul(raw) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rail_verdict/git/diff_parser.rb', line 121

def split_unified_by_nul(raw)
  raw_text = raw.dup.force_encoding(Encoding::UTF_8).scrub("?")
  if raw_text.include?("\0")
    parts = raw_text.split("\0")
    parts.pop if parts.last == ""
    segments = []
    parts.each_slice(2) do |path, diff_text|
      next if path.nil?

      segments << [path, diff_text || ""]
    end
    segments
  else
    split_unified_without_nul(raw_text)
  end
end