lib/gitlab_git/diff.rb in gitlab_git-10.6.3 vs lib/gitlab_git/diff.rb in gitlab_git-10.6.4

- old
+ new

@@ -11,10 +11,16 @@ # Stats properties attr_accessor :new_file, :renamed_file, :deleted_file attr_accessor :too_large + # The maximum size of a diff to display. + DIFF_SIZE_LIMIT = 102400 # 100 KB + + # The maximum size before a diff is collapsed. + DIFF_COLLAPSE_LIMIT = 10240 # 10 KB + class << self def between(repo, head, base, options = {}, *paths) # Only show what is new in the source branch compared to the target branch, not the other way around. # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2) # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B" @@ -156,16 +162,16 @@ filtered_opts end end - def initialize(raw_diff) + def initialize(raw_diff, collapse: false) case raw_diff when Hash - init_from_hash(raw_diff) + init_from_hash(raw_diff, collapse: collapse) when Rugged::Patch, Rugged::Diff::Delta - init_from_rugged(raw_diff) + init_from_rugged(raw_diff, collapse: collapse) when nil raise "Nil as raw diff passed" else raise "Invalid raw diff type: #{raw_diff.class}" end @@ -195,16 +201,20 @@ @line_count ||= Util.count_lines(@diff) end def too_large? if @too_large.nil? - @too_large = @diff.bytesize >= 102400 # 100 KB + @too_large = @diff.bytesize >= DIFF_SIZE_LIMIT else @too_large end end + def collapsible? + @diff.bytesize >= DIFF_COLLAPSE_LIMIT + end + def prune_large_diff! @diff = '' @line_count = 0 @too_large = true end @@ -212,25 +222,21 @@ def collapsed? return @collapsed if defined?(@collapsed) false end - def collapsible? - @diff.bytesize >= 10240 # 10 KB - end - def prune_collapsed_diff! @diff = '' @line_count = 0 @collapsed = true end private - def init_from_rugged(rugged) + def init_from_rugged(rugged, collapse: false) if rugged.is_a?(Rugged::Patch) - @diff = encode!(strip_diff_headers(rugged.to_s)) + init_from_rugged_patch(rugged, collapse: collapse) d = rugged.delta else d = rugged end @@ -241,15 +247,49 @@ @new_file = d.added? @renamed_file = d.renamed? @deleted_file = d.deleted? end - def init_from_hash(hash) + def init_from_rugged_patch(patch, collapse: false) + # Don't bother initializing diffs that are too large. If a diff is + # binary we're not going to display anything so we skip the size check. + unless patch.delta.binary? + diff_size = patch_size(patch) + + if diff_size >= DIFF_SIZE_LIMIT + prune_large_diff! + return + elsif collapse && diff_size >= DIFF_COLLAPSE_LIMIT + prune_collapsed_diff! + return + end + end + + @diff = encode!(strip_diff_headers(patch.to_s)) + end + + def init_from_hash(hash, collapse: false) raw_diff = hash.symbolize_keys serialize_keys.each do |key| send(:"#{key}=", raw_diff[key.to_sym]) end + + prune_large_diff! if too_large? + prune_collapsed_diff! if collapse && collapsible? + end + + # Returns the size of a diff without taking any diff markers into account. + def patch_size(patch) + size = 0 + + patch.each_hunk do |hunk| + hunk.each_line do |line| + size += line.content.bytesize + end + end + + size end # Strip out the information at the beginning of the patch's text to match # Grit's output def strip_diff_headers(diff_text)