debian-mirror-gitlab/lib/gitlab/tree_summary.rb

165 lines
4.6 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2018-11-20 20:47:30 +05:30
module Gitlab
class TreeSummary
include ::Gitlab::Utils::StrongMemoize
2020-05-24 23:13:21 +05:30
include ::MarkupHelper
CACHE_EXPIRE_IN = 1.hour
MAX_OFFSET = 2**31
2018-11-20 20:47:30 +05:30
2020-05-24 23:13:21 +05:30
attr_reader :commit, :project, :path, :offset, :limit, :user
2018-11-20 20:47:30 +05:30
attr_reader :resolved_commits
private :resolved_commits
2020-05-24 23:13:21 +05:30
def initialize(commit, project, user, params = {})
2018-11-20 20:47:30 +05:30
@commit = commit
@project = project
2020-05-24 23:13:21 +05:30
@user = user
2018-11-20 20:47:30 +05:30
@path = params.fetch(:path, nil).presence
2020-05-24 23:13:21 +05:30
@offset = [params.fetch(:offset, 0).to_i, MAX_OFFSET].min
2018-11-20 20:47:30 +05:30
@limit = (params.fetch(:limit, 25) || 25).to_i
# Ensure that if multiple tree entries share the same last commit, they share
# a ::Commit instance. This prevents us from rendering the same commit title
# multiple times
@resolved_commits = {}
end
# Creates a summary of the tree entries for a commit, within the window of
# entries defined by the offset and limit parameters. This consists of two
# return values:
#
# - An Array of Hashes containing the following keys:
# - file_name: The full path of the tree entry
# - type: One of :blob, :tree, or :submodule
# - commit: The last ::Commit to touch this entry in the tree
# - commit_path: URI of the commit in the web interface
# - An Array of the unique ::Commit objects in the first value
def summarize
summary = contents
.tap { |summary| fill_last_commits!(summary) }
[summary, commits]
end
2020-05-24 23:13:21 +05:30
def fetch_logs
2021-02-11 23:33:58 +05:30
logs, _ = summarize
2020-05-24 23:13:21 +05:30
2021-02-11 23:33:58 +05:30
new_offset = next_offset if more?
2020-05-24 23:13:21 +05:30
2021-02-11 23:33:58 +05:30
[logs.as_json, new_offset]
2020-05-24 23:13:21 +05:30
end
2018-11-20 20:47:30 +05:30
# Does the tree contain more entries after the given offset + limit?
def more?
all_contents[next_offset].present?
end
# The offset of the next batch of tree entries. If more? returns false, this
# batch will be empty
def next_offset
[all_contents.size + 1, offset + limit].min
end
private
def contents
2021-02-11 23:33:58 +05:30
all_contents[offset, limit] || []
2018-11-20 20:47:30 +05:30
end
def commits
resolved_commits.values
end
def repository
project.repository
end
2021-02-11 23:33:58 +05:30
# Ensure the path is in "path/" format
def ensured_path
File.join(*[path, ""]) if path
2018-11-20 20:47:30 +05:30
end
2021-02-11 23:33:58 +05:30
def entry_path(entry)
File.join(*[path, entry[:file_name]].compact).force_encoding(Encoding::ASCII_8BIT)
2018-11-20 20:47:30 +05:30
end
def fill_last_commits!(entries)
2021-02-11 23:33:58 +05:30
commits_hsh = fetch_last_cached_commits_list
2020-05-24 23:13:21 +05:30
prerender_commit_full_titles!(commits_hsh.values)
2018-11-20 20:47:30 +05:30
2018-12-05 23:21:45 +05:30
entries.each do |entry|
path_key = entry_path(entry)
commit = cache_commit(commits_hsh[path_key])
2018-11-20 20:47:30 +05:30
2018-12-05 23:21:45 +05:30
if commit
entry[:commit] = commit
entry[:commit_path] = commit_path(commit)
2020-05-24 23:13:21 +05:30
entry[:commit_title_html] = markdown_field(commit, :full_title)
2018-11-20 20:47:30 +05:30
end
end
end
2021-02-11 23:33:58 +05:30
def fetch_last_cached_commits_list
2021-04-17 20:07:23 +05:30
cache_key = ['projects', project.id, 'last_commits', commit.id, ensured_path, offset, limit]
2021-02-11 23:33:58 +05:30
commits = Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRE_IN) do
repository
.list_last_commits_for_tree(commit.id, ensured_path, offset: offset, limit: limit, literal_pathspec: true)
2021-04-17 20:07:23 +05:30
.transform_values! { |commit| commit_to_hash(commit) }
2021-02-11 23:33:58 +05:30
end
commits.transform_values! { |value| Commit.from_hash(value, project) }
end
2018-12-05 23:21:45 +05:30
def cache_commit(commit)
2019-07-07 11:18:12 +05:30
return unless commit.present?
2018-11-20 20:47:30 +05:30
2018-12-05 23:21:45 +05:30
resolved_commits[commit.id] ||= commit
2018-11-20 20:47:30 +05:30
end
2021-04-17 20:07:23 +05:30
def commit_to_hash(commit)
commit.to_hash.tap do |hash|
hash[:message] = hash[:message].to_s.truncate_bytes(1.kilobyte, omission: '...')
end
end
2018-11-20 20:47:30 +05:30
def commit_path(commit)
Gitlab::Routing.url_helpers.project_commit_path(project, commit)
end
def all_contents
2021-02-11 23:33:58 +05:30
strong_memoize(:all_contents) { cached_contents }
end
def cached_contents
cache_key = ['projects', project.id, 'content', commit.id, path]
Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRE_IN) do
2018-11-20 20:47:30 +05:30
[
*tree.trees,
*tree.blobs,
*tree.submodules
2021-02-11 23:33:58 +05:30
].map { |entry| { file_name: entry.name, type: entry.type } }
2018-11-20 20:47:30 +05:30
end
end
def tree
strong_memoize(:tree) { repository.tree(commit.id, path) }
end
2020-05-24 23:13:21 +05:30
def prerender_commit_full_titles!(commits)
# Preload commit authors as they are used in rendering
commits.each(&:lazy_author)
renderer = Banzai::ObjectRenderer.new(user: user, default_project: project)
renderer.render(commits, :full_title)
end
2018-11-20 20:47:30 +05:30
end
end
2020-05-24 23:13:21 +05:30
2021-06-08 01:23:25 +05:30
Gitlab::TreeSummary.prepend_mod_with('Gitlab::TreeSummary')