summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/models/safe_diffs.rb5
-rw-r--r--app/models/safe_diffs/base.rb55
-rw-r--r--app/models/safe_diffs/commit.rb10
-rw-r--r--app/models/safe_diffs/compare.rb10
-rw-r--r--app/models/safe_diffs/merge_request.rb52
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