2018-11-09 18:39:43 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-10-13 13:11:53 +00:00
|
|
|
require 'stringio'
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module GitalyClient
|
|
|
|
class WikiService
|
2017-12-26 18:53:31 +00:00
|
|
|
include Gitlab::EncodingHelper
|
|
|
|
|
2017-10-13 13:11:53 +00:00
|
|
|
MAX_MSG_SIZE = 128.kilobytes.freeze
|
|
|
|
|
|
|
|
def initialize(repository)
|
|
|
|
@gitaly_repo = repository.gitaly_repository
|
|
|
|
@repository = repository
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_page(name, format, content, commit_details)
|
|
|
|
request = Gitaly::WikiWritePageRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2017-12-26 18:53:31 +00:00
|
|
|
name: encode_binary(name),
|
2017-10-13 13:11:53 +00:00
|
|
|
format: format.to_s,
|
2017-10-31 10:38:15 +00:00
|
|
|
commit_details: gitaly_commit_details(commit_details)
|
2017-10-13 13:11:53 +00:00
|
|
|
)
|
|
|
|
|
2019-03-28 19:05:27 +00:00
|
|
|
strio = binary_io(content)
|
2017-10-13 13:11:53 +00:00
|
|
|
|
|
|
|
enum = Enumerator.new do |y|
|
|
|
|
until strio.eof?
|
2017-12-06 17:28:27 +00:00
|
|
|
request.content = strio.read(MAX_MSG_SIZE)
|
2017-10-13 13:11:53 +00:00
|
|
|
|
|
|
|
y.yield request
|
|
|
|
|
|
|
|
request = Gitaly::WikiWritePageRequest.new
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-19 18:06:18 +00:00
|
|
|
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_write_page, enum, timeout: GitalyClient.medium_timeout)
|
2017-10-13 13:11:53 +00:00
|
|
|
if error = response.duplicate_error.presence
|
|
|
|
raise Gitlab::Git::Wiki::DuplicatePageError, error
|
|
|
|
end
|
|
|
|
end
|
2017-10-31 10:38:15 +00:00
|
|
|
|
2017-11-02 14:08:39 +00:00
|
|
|
def update_page(page_path, title, format, content, commit_details)
|
|
|
|
request = Gitaly::WikiUpdatePageRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2017-12-26 18:53:31 +00:00
|
|
|
page_path: encode_binary(page_path),
|
|
|
|
title: encode_binary(title),
|
2017-11-02 14:08:39 +00:00
|
|
|
format: format.to_s,
|
|
|
|
commit_details: gitaly_commit_details(commit_details)
|
|
|
|
)
|
|
|
|
|
2019-03-28 19:05:27 +00:00
|
|
|
strio = binary_io(content)
|
2017-11-02 14:08:39 +00:00
|
|
|
|
|
|
|
enum = Enumerator.new do |y|
|
|
|
|
until strio.eof?
|
2017-12-06 17:28:27 +00:00
|
|
|
request.content = strio.read(MAX_MSG_SIZE)
|
2017-11-02 14:08:39 +00:00
|
|
|
|
|
|
|
y.yield request
|
|
|
|
|
|
|
|
request = Gitaly::WikiUpdatePageRequest.new
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-19 18:06:18 +00:00
|
|
|
GitalyClient.call(@repository.storage, :wiki_service, :wiki_update_page, enum, timeout: GitalyClient.medium_timeout)
|
2017-11-02 14:08:39 +00:00
|
|
|
end
|
|
|
|
|
2017-10-31 10:38:15 +00:00
|
|
|
def delete_page(page_path, commit_details)
|
|
|
|
request = Gitaly::WikiDeletePageRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2017-12-26 18:53:31 +00:00
|
|
|
page_path: encode_binary(page_path),
|
2017-10-31 10:38:15 +00:00
|
|
|
commit_details: gitaly_commit_details(commit_details)
|
|
|
|
)
|
|
|
|
|
2018-07-05 16:05:24 +00:00
|
|
|
GitalyClient.call(@repository.storage, :wiki_service, :wiki_delete_page, request, timeout: GitalyClient.medium_timeout)
|
2017-10-31 10:38:15 +00:00
|
|
|
end
|
|
|
|
|
2017-10-19 14:18:26 +00:00
|
|
|
def find_page(title:, version: nil, dir: nil)
|
|
|
|
request = Gitaly::WikiFindPageRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2017-12-26 18:53:31 +00:00
|
|
|
title: encode_binary(title),
|
|
|
|
revision: encode_binary(version),
|
|
|
|
directory: encode_binary(dir)
|
2017-10-19 14:18:26 +00:00
|
|
|
)
|
|
|
|
|
2018-07-05 16:05:24 +00:00
|
|
|
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_page, request, timeout: GitalyClient.fast_timeout)
|
2017-10-19 14:18:26 +00:00
|
|
|
|
2017-11-09 23:27:00 +00:00
|
|
|
wiki_page_from_iterator(response)
|
|
|
|
end
|
2017-10-19 14:18:26 +00:00
|
|
|
|
2019-04-25 04:19:07 +00:00
|
|
|
def list_all_pages(limit: 0, sort: nil, direction_desc: false)
|
|
|
|
sort_value = Gitaly::WikiListPagesRequest::SortBy.resolve(sort.to_s.upcase.to_sym)
|
|
|
|
|
|
|
|
params = { repository: @gitaly_repo, limit: limit, direction_desc: direction_desc }
|
|
|
|
params[:sort] = sort_value if sort_value
|
|
|
|
|
|
|
|
request = Gitaly::WikiListPagesRequest.new(params)
|
|
|
|
stream = GitalyClient.call(@repository.storage, :wiki_service, :wiki_list_pages, request, timeout: GitalyClient.medium_timeout)
|
|
|
|
stream.each_with_object([]) do |message, pages|
|
|
|
|
page = message.page
|
|
|
|
|
|
|
|
next unless page
|
|
|
|
|
|
|
|
wiki_page = GitalyClient::WikiPage.new(page.to_h)
|
|
|
|
version = new_wiki_page_version(page.version)
|
|
|
|
|
|
|
|
pages << [wiki_page, version]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def load_all_pages(limit: 0, sort: nil, direction_desc: false)
|
2019-04-04 16:28:56 +00:00
|
|
|
sort_value = Gitaly::WikiGetAllPagesRequest::SortBy.resolve(sort.to_s.upcase.to_sym)
|
|
|
|
|
|
|
|
params = { repository: @gitaly_repo, limit: limit, direction_desc: direction_desc }
|
|
|
|
params[:sort] = sort_value if sort_value
|
|
|
|
|
|
|
|
request = Gitaly::WikiGetAllPagesRequest.new(params)
|
2018-07-05 16:05:24 +00:00
|
|
|
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_all_pages, request, timeout: GitalyClient.medium_timeout)
|
2019-04-25 04:19:07 +00:00
|
|
|
|
2017-11-09 23:27:00 +00:00
|
|
|
pages = []
|
2017-10-19 14:18:26 +00:00
|
|
|
|
2017-11-09 23:27:00 +00:00
|
|
|
loop do
|
|
|
|
page, version = wiki_page_from_iterator(response) { |message| message.end_of_page }
|
|
|
|
|
|
|
|
break unless page && version
|
2017-11-14 09:02:39 +00:00
|
|
|
|
2017-11-09 23:27:00 +00:00
|
|
|
pages << [page, version]
|
2017-10-19 14:18:26 +00:00
|
|
|
end
|
|
|
|
|
2017-11-09 23:27:00 +00:00
|
|
|
pages
|
2017-10-19 14:18:26 +00:00
|
|
|
end
|
|
|
|
|
2018-01-02 08:23:39 +00:00
|
|
|
# options:
|
|
|
|
# :page - The Integer page number.
|
|
|
|
# :per_page - The number of items per page.
|
|
|
|
# :limit - Total number of items to return.
|
|
|
|
def page_versions(page_path, options)
|
|
|
|
request = Gitaly::WikiGetPageVersionsRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2018-01-16 10:12:08 +00:00
|
|
|
page_path: encode_binary(page_path),
|
|
|
|
page: options[:page] || 1,
|
2018-10-02 03:21:46 +00:00
|
|
|
per_page: options[:per_page] || Gitlab::Git::Wiki::DEFAULT_PAGINATION
|
2018-01-02 08:23:39 +00:00
|
|
|
)
|
|
|
|
|
2018-07-05 16:05:24 +00:00
|
|
|
stream = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_page_versions, request, timeout: GitalyClient.medium_timeout)
|
2018-01-02 08:23:39 +00:00
|
|
|
|
|
|
|
versions = []
|
|
|
|
stream.each do |message|
|
|
|
|
message.versions.each do |version|
|
2018-01-16 10:12:08 +00:00
|
|
|
versions << new_wiki_page_version(version)
|
2018-01-02 08:23:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
versions
|
|
|
|
end
|
|
|
|
|
2017-10-23 20:12:11 +00:00
|
|
|
def find_file(name, revision)
|
|
|
|
request = Gitaly::WikiFindFileRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2017-12-26 18:53:31 +00:00
|
|
|
name: encode_binary(name),
|
|
|
|
revision: encode_binary(revision)
|
2017-10-23 20:12:11 +00:00
|
|
|
)
|
|
|
|
|
2018-07-05 16:05:24 +00:00
|
|
|
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_file, request, timeout: GitalyClient.fast_timeout)
|
2017-10-23 20:12:11 +00:00
|
|
|
wiki_file = nil
|
|
|
|
|
|
|
|
response.each do |message|
|
2018-04-11 14:08:23 +00:00
|
|
|
next unless message.name.present? || wiki_file
|
2017-10-23 20:12:11 +00:00
|
|
|
|
|
|
|
if wiki_file
|
2018-11-09 18:39:43 +00:00
|
|
|
wiki_file.raw_data = "#{wiki_file.raw_data}#{message.raw_data}"
|
2017-10-23 20:12:11 +00:00
|
|
|
else
|
|
|
|
wiki_file = GitalyClient::WikiFile.new(message.to_h)
|
|
|
|
# All gRPC strings in a response are frozen, so we get
|
|
|
|
# an unfrozen version here so appending in the else clause below doesn't blow up.
|
|
|
|
wiki_file.raw_data = wiki_file.raw_data.dup
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
wiki_file
|
|
|
|
end
|
|
|
|
|
2018-01-25 15:24:11 +00:00
|
|
|
def get_formatted_data(title:, dir: nil, version: nil)
|
|
|
|
request = Gitaly::WikiGetFormattedDataRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
title: encode_binary(title),
|
|
|
|
revision: encode_binary(version),
|
|
|
|
directory: encode_binary(dir)
|
|
|
|
)
|
|
|
|
|
2019-09-19 18:06:18 +00:00
|
|
|
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_formatted_data, request, timeout: GitalyClient.medium_timeout)
|
2018-11-09 18:39:43 +00:00
|
|
|
response.reduce([]) { |memo, msg| memo << msg.data }.join
|
2018-01-25 15:24:11 +00:00
|
|
|
end
|
|
|
|
|
2017-10-31 10:38:15 +00:00
|
|
|
private
|
|
|
|
|
2018-01-02 08:23:39 +00:00
|
|
|
# If a block is given and the yielded value is truthy, iteration will be
|
2017-11-09 23:27:00 +00:00
|
|
|
# stopped early at that point; else the iterator is consumed entirely.
|
|
|
|
# The iterator is traversed with `next` to allow resuming the iteration.
|
|
|
|
def wiki_page_from_iterator(iterator)
|
|
|
|
wiki_page = version = nil
|
|
|
|
|
|
|
|
while message = iterator.next
|
|
|
|
break if block_given? && yield(message)
|
|
|
|
|
|
|
|
page = message.page
|
|
|
|
next unless page
|
|
|
|
|
|
|
|
if wiki_page
|
|
|
|
wiki_page.raw_data << page.raw_data
|
|
|
|
else
|
|
|
|
wiki_page = GitalyClient::WikiPage.new(page.to_h)
|
|
|
|
|
2018-01-02 08:23:39 +00:00
|
|
|
version = new_wiki_page_version(page.version)
|
2017-11-09 23:27:00 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
[wiki_page, version]
|
|
|
|
rescue StopIteration
|
|
|
|
[wiki_page, version]
|
|
|
|
end
|
|
|
|
|
2018-01-02 08:23:39 +00:00
|
|
|
def new_wiki_page_version(version)
|
|
|
|
Gitlab::Git::WikiPageVersion.new(
|
|
|
|
Gitlab::Git::Commit.decorate(@repository, version.commit),
|
|
|
|
version.format
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2017-10-31 10:38:15 +00:00
|
|
|
def gitaly_commit_details(commit_details)
|
|
|
|
Gitaly::WikiCommitDetails.new(
|
2018-04-18 17:50:56 +00:00
|
|
|
user_id: commit_details.user_id,
|
|
|
|
user_name: encode_binary(commit_details.username),
|
2017-12-26 18:53:31 +00:00
|
|
|
name: encode_binary(commit_details.name),
|
|
|
|
email: encode_binary(commit_details.email),
|
|
|
|
message: encode_binary(commit_details.message)
|
2017-10-31 10:38:15 +00:00
|
|
|
)
|
|
|
|
end
|
2017-10-13 13:11:53 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|