debian-mirror-gitlab/lib/gitlab/git/diff_collection.rb

224 lines
5.5 KiB
Ruby
Raw Normal View History

2019-02-15 15:39:39 +05:30
# frozen_string_literal: true
2017-09-10 17:25:29 +05:30
# Gitaly note: JV: no RPC's here.
2017-08-17 22:00:37 +05:30
module Gitlab
module Git
class DiffCollection
include Enumerable
2017-09-10 17:25:29 +05:30
attr_reader :limits
delegate :max_files, :max_lines, :max_bytes, :safe_max_files, :safe_max_lines, :safe_max_bytes, to: :limits
2021-01-03 14:25:43 +05:30
def self.default_limits(project: nil)
2021-09-04 01:27:46 +05:30
{ max_files: ::Commit.diff_safe_max_files(project: project), max_lines: ::Commit.diff_safe_max_lines(project: project) }
2021-01-03 14:25:43 +05:30
end
2018-11-20 20:47:30 +05:30
def self.limits(options = {})
2017-09-10 17:25:29 +05:30
limits = {}
2021-01-03 14:25:43 +05:30
defaults = default_limits(project: options[:project])
limits[:max_files] = options.fetch(:max_files, defaults[:max_files])
limits[:max_lines] = options.fetch(:max_lines, defaults[:max_lines])
2017-09-10 17:25:29 +05:30
limits[:max_bytes] = limits[:max_files] * 5.kilobytes # Average 5 KB per file
2021-01-03 14:25:43 +05:30
limits[:safe_max_files] = [limits[:max_files], defaults[:max_files]].min
limits[:safe_max_lines] = [limits[:max_lines], defaults[:max_lines]].min
2017-09-10 17:25:29 +05:30
limits[:safe_max_bytes] = limits[:safe_max_files] * 5.kilobytes # Average 5 KB per file
2018-12-05 23:21:45 +05:30
limits[:max_patch_bytes] = Gitlab::Git::Diff.patch_hard_limit_bytes
2017-09-10 17:25:29 +05:30
OpenStruct.new(limits)
end
2017-08-17 22:00:37 +05:30
def initialize(iterator, options = {})
@iterator = iterator
2018-11-20 20:47:30 +05:30
@limits = self.class.limits(options)
2017-09-10 17:25:29 +05:30
@enforce_limits = !!options.fetch(:limits, true)
@expanded = !!options.fetch(:expanded, true)
2019-12-21 20:55:43 +05:30
@offset_index = options.fetch(:offset_index, 0)
2017-08-17 22:00:37 +05:30
@line_count = 0
@byte_count = 0
@overflow = false
2017-09-10 17:25:29 +05:30
@empty = true
2020-11-24 15:15:51 +05:30
@array = []
2017-08-17 22:00:37 +05:30
end
def each(&block)
2017-09-10 17:25:29 +05:30
@array.each(&block)
return if @overflow
return if @iterator.nil?
2018-11-18 11:00:15 +05:30
if @iterator.is_a?(Gitlab::GitalyClient::DiffStitcher)
each_gitaly_patch(&block)
else
each_serialized_patch(&block)
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
@populated = true
# Allow iterator to be garbage-collected. It cannot be reused anyway.
@iterator = nil
2017-08-17 22:00:37 +05:30
end
2021-02-22 17:27:13 +05:30
def sort(&block)
@array = @array.sort(&block)
self
end
2017-08-17 22:00:37 +05:30
def empty?
2017-09-10 17:25:29 +05:30
any? # Make sure the iterator has been exercised
@empty
2017-08-17 22:00:37 +05:30
end
def overflow?
populate!
!!@overflow
end
2021-04-29 21:17:54 +05:30
def overflow_max_lines?
!!@overflow_max_lines
end
def overflow_max_bytes?
!!@overflow_max_bytes
end
def overflow_max_files?
!!@overflow_max_files
end
def collapsed_safe_lines?
!!@collapsed_safe_lines
end
def collapsed_safe_files?
!!@collapsed_safe_files
end
def collapsed_safe_bytes?
!!@collapsed_safe_bytes
end
2017-08-17 22:00:37 +05:30
def size
@size ||= count # forces a loop using each method
end
def real_size
populate!
if @overflow
"#{size}+"
else
size.to_s
end
end
2019-12-04 20:38:33 +05:30
def line_count
populate!
@line_count
end
2017-08-17 22:00:37 +05:30
def decorate!
2021-04-29 21:17:54 +05:30
each_with_index do |element, i|
2017-08-17 22:00:37 +05:30
@array[i] = yield(element)
end
end
2017-09-10 17:25:29 +05:30
alias_method :to_ary, :to_a
2017-08-17 22:00:37 +05:30
private
def populate!
return if @populated
2020-03-13 15:44:24 +05:30
each {} # force a loop through all diffs
2017-08-17 22:00:37 +05:30
nil
end
def over_safe_limits?(files)
2021-04-29 21:17:54 +05:30
if files >= safe_max_files
@collapsed_safe_files = true
elsif @line_count > safe_max_lines
@collapsed_safe_lines = true
elsif @byte_count >= safe_max_bytes
@collapsed_safe_bytes = true
end
@collapsed_safe_files || @collapsed_safe_lines || @collapsed_safe_bytes
2017-08-17 22:00:37 +05:30
end
2021-01-03 14:25:43 +05:30
def expand_diff?
# Force single-entry diff collections to always present as expanded
#
@iterator.size == 1 || !@enforce_limits || @expanded
end
2017-09-10 17:25:29 +05:30
def each_gitaly_patch
i = @array.length
@iterator.each do |raw|
2021-01-03 14:25:43 +05:30
diff = Gitlab::Git::Diff.new(raw, expanded: expand_diff?)
2017-09-10 17:25:29 +05:30
if raw.overflow_marker
@overflow = true
break
end
2017-08-17 22:00:37 +05:30
yield @array[i] = diff
2017-09-10 17:25:29 +05:30
i += 1
2017-08-17 22:00:37 +05:30
end
end
2018-11-18 11:00:15 +05:30
def each_serialized_patch
2017-09-10 17:25:29 +05:30
i = @array.length
2017-08-17 22:00:37 +05:30
2019-12-21 20:55:43 +05:30
@iterator.each_with_index do |raw, iterator_index|
2017-09-10 17:25:29 +05:30
@empty = false
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
if @enforce_limits && i >= max_files
2017-08-17 22:00:37 +05:30
@overflow = true
2021-04-29 21:17:54 +05:30
@overflow_max_files = true
2017-08-17 22:00:37 +05:30
break
end
2021-01-03 14:25:43 +05:30
diff = Gitlab::Git::Diff.new(raw, expanded: expand_diff?)
2017-08-17 22:00:37 +05:30
2021-01-03 14:25:43 +05:30
if !expand_diff? && over_safe_limits?(i) && diff.line_count > 0
2017-09-10 17:25:29 +05:30
diff.collapse!
2017-08-17 22:00:37 +05:30
end
@line_count += diff.line_count
@byte_count += diff.diff.bytesize
2021-04-29 21:17:54 +05:30
if @enforce_limits && @line_count >= max_lines
# This last Diff instance pushes us over the lines limit. We stop and
# discard it.
@overflow = true
@overflow_max_lines = true
break
end
if @enforce_limits && @byte_count >= max_bytes
2017-08-17 22:00:37 +05:30
# This last Diff instance pushes us over the lines limit. We stop and
# discard it.
@overflow = true
2021-04-29 21:17:54 +05:30
@overflow_max_bytes = true
2017-08-17 22:00:37 +05:30
break
end
2019-12-21 20:55:43 +05:30
# We should not yield / memoize diffs before the offset index. Though,
# we still consider the limit buffers for diffs before it.
if iterator_index >= @offset_index
yield @array[i] = diff
i += 1
end
2017-08-17 22:00:37 +05:30
end
end
end
end
end