summaryrefslogtreecommitdiff
path: root/lib/gitlab/diff/file.rb
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2018-01-03 14:18:13 +0000
committerSean McGivern <sean@gitlab.com>2018-01-04 14:33:12 +0000
commit528b5eeb761f627bb1972fa8a25a09dc1cea4556 (patch)
tree4b32a5e10e331b252599fdad40e44996ab5e5421 /lib/gitlab/diff/file.rb
parente5a9b9a14d32d890dea20403c977dfd569eb3e17 (diff)
downloadgitlab-ce-528b5eeb761f627bb1972fa8a25a09dc1cea4556.tar.gz
Old merge requests can have diffs without corresponding blobs. (This also may be possible for commit diffs in corrupt repositories.) We can't use the `&.` operator on the blobs, because the blob objects are never nil, but `BatchLoader` instances that delegate to `Blob`. We can't use `Object#try`, because `Blob` doesn't inherit from `Object`. `BatchLoader` provides a `__sync` method that returns the delegated object, but using `itself` also works because it's forwarded, and will work for non-`BatchLoader` instances too. So the simplest solution is to just use that with the `&.` operator.
Diffstat (limited to 'lib/gitlab/diff/file.rb')
-rw-r--r--lib/gitlab/diff/file.rb31
1 files changed, 23 insertions, 8 deletions
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index cd490aaa291..34b070dd375 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -116,8 +116,10 @@ module Gitlab
new_content_sha || old_content_sha
end
+ # Use #itself to check the value wrapped by a BatchLoader instance, rather
+ # than if the BatchLoader instance itself is falsey.
def blob
- new_blob || old_blob
+ new_blob&.itself || old_blob&.itself
end
attr_writer :highlighted_diff_lines
@@ -173,7 +175,7 @@ module Gitlab
end
def binary?
- has_binary_notice? || old_blob&.binary? || new_blob&.binary?
+ has_binary_notice? || try_blobs(:binary?)
end
def text?
@@ -181,15 +183,15 @@ module Gitlab
end
def external_storage_error?
- old_blob&.external_storage_error? || new_blob&.external_storage_error?
+ try_blobs(:external_storage_error?)
end
def stored_externally?
- old_blob&.stored_externally? || new_blob&.stored_externally?
+ try_blobs(:stored_externally?)
end
def external_storage
- old_blob&.external_storage || new_blob&.external_storage
+ try_blobs(:external_storage)
end
def content_changed?
@@ -204,15 +206,15 @@ module Gitlab
end
def size
- [old_blob&.size, new_blob&.size].compact.sum
+ valid_blobs.map(&:size).sum
end
def raw_size
- [old_blob&.raw_size, new_blob&.raw_size].compact.sum
+ valid_blobs.map(&:raw_size).sum
end
def raw_binary?
- old_blob&.raw_binary? || new_blob&.raw_binary?
+ try_blobs(:raw_binary?)
end
def raw_text?
@@ -235,6 +237,19 @@ module Gitlab
private
+ # The blob instances are instances of BatchLoader, which means calling
+ # &. directly on them won't work. Object#try also won't work, because Blob
+ # doesn't inherit from Object, but from BasicObject (via SimpleDelegator).
+ def try_blobs(meth)
+ old_blob&.itself&.public_send(meth) || new_blob&.itself&.public_send(meth)
+ end
+
+ # We can't use #compact for the same reason we can't use &., but calling
+ # #nil? explicitly does work because it is proxied to the blob itself.
+ def valid_blobs
+ [old_blob, new_blob].reject(&:nil?)
+ end
+
def text_position_properties(line)
{ old_line: line.old_line, new_line: line.new_line }
end