diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/merge_request.rb | 2 | ||||
-rw-r--r-- | app/models/safe_diffs.rb | 5 | ||||
-rw-r--r-- | app/models/safe_diffs/base.rb | 55 | ||||
-rw-r--r-- | app/models/safe_diffs/commit.rb | 10 | ||||
-rw-r--r-- | app/models/safe_diffs/compare.rb | 10 | ||||
-rw-r--r-- | app/models/safe_diffs/merge_request.rb | 52 |
6 files changed, 134 insertions, 0 deletions
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index a99c4ba52a4..774851cc90f 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -313,6 +313,8 @@ class MergeRequest < ActiveRecord::Base merge_request_diff.reload_content + MergeRequests::MergeRequestDiffCacheService.new.execute(self) + new_diff_refs = self.diff_refs update_diff_notes_positions( diff --git a/app/models/safe_diffs.rb b/app/models/safe_diffs.rb new file mode 100644 index 00000000000..8ca9ec4cc39 --- /dev/null +++ b/app/models/safe_diffs.rb @@ -0,0 +1,5 @@ +module SafeDiffs + def self.default_options + ::Commit.max_diff_options.merge(ignore_whitespace_change: false, no_collapse: false) + end +end diff --git a/app/models/safe_diffs/base.rb b/app/models/safe_diffs/base.rb new file mode 100644 index 00000000000..dfc4708e293 --- /dev/null +++ b/app/models/safe_diffs/base.rb @@ -0,0 +1,55 @@ +module SafeDiffs + class Base + attr_reader :project, :diff_options, :diff_view, :diff_refs + + delegate :count, :real_size, to: :diff_files + + def initialize(diffs, project:, diff_options:, diff_refs: nil) + @diffs = diffs + @project = project + @diff_options = diff_options + @diff_refs = diff_refs + end + + def diff_files + @diff_files ||= begin + diffs = @diffs.decorate! do |diff| + Gitlab::Diff::File.new(diff, diff_refs: @diff_refs, repository: @project.repository) + end + + highlight!(diffs) + diffs + end + end + + private + + def highlight!(diff_files) + if cacheable? + cache_highlight!(diff_files) + else + diff_files.each { |diff_file| highlight_diff_file!(diff_file) } + end + end + + def cacheable? + false + end + + def cache_highlight! + raise NotImplementedError + end + + def highlight_diff_file_from_cache!(diff_file, cache_diff_lines) + diff_file.diff_lines = cache_diff_lines.map do |line| + Gitlab::Diff::Line.init_from_hash(line) + end + end + + def highlight_diff_file!(diff_file) + diff_file.diff_lines = Gitlab::Diff::Highlight.new(diff_file, repository: diff_file.repository).highlight + diff_file.highlighted_diff_lines = diff_file.diff_lines # To be used on parallel diff + diff_file + end + end +end diff --git a/app/models/safe_diffs/commit.rb b/app/models/safe_diffs/commit.rb new file mode 100644 index 00000000000..338878f32e0 --- /dev/null +++ b/app/models/safe_diffs/commit.rb @@ -0,0 +1,10 @@ +module SafeDiffs + class Commit < Base + def initialize(commit, diff_options:) + super(commit.diffs(diff_options), + project: commit.project, + diff_options: diff_options, + diff_refs: commit.diff_refs) + end + end +end diff --git a/app/models/safe_diffs/compare.rb b/app/models/safe_diffs/compare.rb new file mode 100644 index 00000000000..6b64b81137d --- /dev/null +++ b/app/models/safe_diffs/compare.rb @@ -0,0 +1,10 @@ +module SafeDiffs + class Compare < Base + def initialize(compare, project:, diff_options:, diff_refs: nil) + super(compare.diffs(diff_options), + project: project, + diff_options: diff_options, + diff_refs: diff_refs) + end + end +end diff --git a/app/models/safe_diffs/merge_request.rb b/app/models/safe_diffs/merge_request.rb new file mode 100644 index 00000000000..111b9a54f91 --- /dev/null +++ b/app/models/safe_diffs/merge_request.rb @@ -0,0 +1,52 @@ +module SafeDiffs + class MergeRequest < Base + def initialize(merge_request, diff_options:) + @merge_request = merge_request + + super(merge_request.diffs(diff_options), + project: merge_request.project, + diff_options: diff_options, + diff_refs: merge_request.diff_refs) + end + + private + + # + # If we find the highlighted diff files lines on the cache we replace existing diff_files lines (no highlighted) + # for the highlighted ones, so we just skip their execution. + # If the highlighted diff files lines are not cached we calculate and cache them. + # + # The content of the cache is and Hash where the key correspond to the file_path and the values are Arrays of + # hashes than represent serialized diff lines. + # + def cache_highlight!(diff_files) + highlighted_cache = Rails.cache.read(cache_key) || {} + highlighted_cache_was_empty = highlighted_cache.empty? + + diff_files.each do |diff_file| + file_path = diff_file.file_path + + if highlighted_cache[file_path] + highlight_diff_file_from_cache!(diff_file, highlighted_cache[file_path]) + else + highlight_diff_file!(diff_file) + highlighted_cache[file_path] = diff_file.diff_lines.map(&:to_hash) + end + end + + if highlighted_cache_was_empty + Rails.cache.write(cache_key, highlighted_cache) + end + + diff_files + end + + def cacheable? + @merge_request.merge_request_diff.present? + end + + def cache_key + [@merge_request.merge_request_diff, 'highlighted-safe-diff-files', diff_options] + end + end +end |