debian-mirror-gitlab/lib/gitlab/diff/position.rb

199 lines
4.9 KiB
Ruby
Raw Normal View History

2019-02-15 15:39:39 +05:30
# frozen_string_literal: true
2018-03-17 18:26:18 +05:30
# Defines a specific location, identified by paths line numbers and image coordinates,
2016-08-24 12:49:21 +05:30
# within a specific diff, identified by start, head and base commit ids.
module Gitlab
module Diff
class Position
2018-03-17 18:26:18 +05:30
attr_accessor :formatter
delegate :old_path,
:new_path,
2020-06-23 00:09:42 +05:30
:file_identifier_hash,
2018-03-17 18:26:18 +05:30
:base_sha,
:start_sha,
:head_sha,
:old_line,
:new_line,
2018-10-15 14:42:47 +05:30
:width,
:height,
:x,
:y,
2021-03-08 18:12:59 +05:30
:line_range,
2018-03-17 18:26:18 +05:30
:position_type, to: :formatter
# A position can belong to a text line or to an image coordinate
# it depends of the position_type argument.
# Text position will have: new_line and old_line
# Image position will have: width, height, x, y
2016-08-24 12:49:21 +05:30
def initialize(attrs = {})
2018-03-17 18:26:18 +05:30
@formatter = get_formatter_class(attrs[:position_type]).new(attrs)
2016-08-24 12:49:21 +05:30
end
# `Gitlab::Diff::Position` objects are stored as serialized attributes in
# `DiffNote`, which use YAML to encode and decode objects.
# `#init_with` and `#encode_with` can be used to customize the en/decoding
# behavior. In this case, we override these to prevent memoized instance
# variables like `@diff_file` and `@diff_line` from being serialized.
def init_with(coder)
initialize(coder['attributes'])
self
end
def encode_with(coder)
2018-03-17 18:26:18 +05:30
coder['attributes'] = formatter.to_h
2016-08-24 12:49:21 +05:30
end
def key
2018-03-17 18:26:18 +05:30
formatter.key
2016-08-24 12:49:21 +05:30
end
def ==(other)
2018-03-17 18:26:18 +05:30
other.is_a?(self.class) &&
other.diff_refs == diff_refs &&
other.old_path == old_path &&
other.new_path == new_path &&
other.formatter == formatter
2016-08-24 12:49:21 +05:30
end
def to_h
2018-03-17 18:26:18 +05:30
formatter.to_h
2016-08-24 12:49:21 +05:30
end
def inspect
%(#<#{self.class}:#{object_id} #{to_h}>)
end
def complete?
2018-03-17 18:26:18 +05:30
file_path.present? && formatter.complete? && diff_refs.complete?
2016-08-24 12:49:21 +05:30
end
def to_json(opts = nil)
2020-05-24 23:13:21 +05:30
Gitlab::Json.generate(formatter.to_h, opts)
2016-08-24 12:49:21 +05:30
end
2018-11-20 20:47:30 +05:30
def as_json(opts = nil)
to_h.as_json(opts)
end
2016-08-24 12:49:21 +05:30
def type
2018-03-17 18:26:18 +05:30
formatter.line_age
2016-08-24 12:49:21 +05:30
end
2019-12-21 20:55:43 +05:30
def unfoldable?
on_text? && unchanged?
end
2016-08-24 12:49:21 +05:30
def unchanged?
type.nil?
end
def added?
type == 'new'
end
def removed?
type == 'old'
end
def paths
[old_path, new_path].compact.uniq
end
def file_path
new_path.presence || old_path
end
def diff_refs
@diff_refs ||= DiffRefs.new(base_sha: base_sha, start_sha: start_sha, head_sha: head_sha)
end
2018-12-13 13:39:08 +05:30
def unfolded_diff?(repository)
diff_file(repository)&.unfolded?
end
2016-08-24 12:49:21 +05:30
def diff_file(repository)
2018-03-17 18:26:18 +05:30
return @diff_file if defined?(@diff_file)
@diff_file = begin
2018-12-05 23:21:45 +05:30
key = {
project_id: repository.project.id,
start_sha: start_sha,
head_sha: head_sha,
path: file_path
}
2019-12-21 20:55:43 +05:30
# Takes action when creating diff notes (multiple calls are
# submitted to this method).
2018-12-05 23:21:45 +05:30
Gitlab::SafeRequestStore.fetch(key) { find_diff_file(repository) }
2016-08-24 12:49:21 +05:30
end
2019-12-21 20:55:43 +05:30
# We need to unfold diff lines according to the position in order
# to correctly calculate the line code and trace position changes.
@diff_file&.tap { |file| file.unfold_diff_lines(self) }
2016-08-24 12:49:21 +05:30
end
2018-12-05 23:21:45 +05:30
def diff_options
{ paths: paths, expanded: true, include_stats: false }
end
2016-08-24 12:49:21 +05:30
def diff_line(repository)
2017-09-10 17:25:29 +05:30
@diff_line ||= diff_file(repository)&.line_for_position(self)
2016-08-24 12:49:21 +05:30
end
def line_code(repository)
2017-09-10 17:25:29 +05:30
@line_code ||= diff_file(repository)&.line_code_for_position(self)
2016-08-24 12:49:21 +05:30
end
2019-09-30 21:07:59 +05:30
def file_hash
@file_hash ||= Digest::SHA1.hexdigest(file_path)
end
2019-09-04 21:01:54 +05:30
def on_image?
position_type == 'image'
end
def on_text?
position_type == 'text'
end
2020-06-23 00:09:42 +05:30
def find_diff_file_from(diffable)
diff_files = diffable.diffs(diff_options).diff_files
if Feature.enabled?(:file_identifier_hash) && file_identifier_hash.present?
diff_files.find { |df| df.file_identifier_hash == file_identifier_hash }
else
diff_files.first
end
end
2021-03-08 18:12:59 +05:30
def multiline?
return unless on_text? && line_range
line_range['start'] != line_range['end']
end
2016-08-24 12:49:21 +05:30
private
def find_diff_file(repository)
2017-09-10 17:25:29 +05:30
return unless diff_refs.complete?
2018-03-17 18:26:18 +05:30
return unless comparison = diff_refs.compare_in(repository.project)
2020-06-23 00:09:42 +05:30
find_diff_file_from(comparison)
2018-03-17 18:26:18 +05:30
end
2016-08-24 12:49:21 +05:30
2018-03-17 18:26:18 +05:30
def get_formatter_class(type)
type ||= "text"
case type
when 'image'
Gitlab::Diff::Formatters::ImageFormatter
else
Gitlab::Diff::Formatters::TextFormatter
end
2016-08-24 12:49:21 +05:30
end
end
end
end