diff options
author | Jacob Vosmaer (GitLab) <jacob@gitlab.com> | 2018-06-06 13:05:07 +0300 |
---|---|---|
committer | Kim Carlbäcker <kim.carlbacker@gmail.com> | 2018-06-06 13:05:07 +0300 |
commit | 0177b095c77a1a98ea99e6448fe7947b905d21dc (patch) | |
tree | 940b064e62f0151b9455a0bb6232107259ce7afa | |
parent | 2398283314be7645320050dbe47b2141f3166c60 (diff) |
Vendor gitlab_git at 930ad88a87b0814173989
17 files changed, 308 insertions, 203 deletions
diff --git a/changelogs/unreleased/vendor-gitlab-git-20180606.yml b/changelogs/unreleased/vendor-gitlab-git-20180606.yml new file mode 100644 index 000000000..035fd9a46 --- /dev/null +++ b/changelogs/unreleased/vendor-gitlab-git-20180606.yml @@ -0,0 +1,5 @@ +--- +title: Vendor gitlab_git at 930ad88a87b0814173989 +merge_request: 752 +author: +type: other diff --git a/ruby/lib/gitlab/git.rb b/ruby/lib/gitlab/git.rb index 80516553a..fd984d3db 100644 --- a/ruby/lib/gitlab/git.rb +++ b/ruby/lib/gitlab/git.rb @@ -45,6 +45,7 @@ end require_relative 'git/gitaly_remote_repository.rb' require_relative 'git/repository.rb' require_relative 'git/gitlab_projects.rb' +require_relative 'git/commit.rb' class String # Because we are not rendering HTML, this is a no-op in gitaly-ruby. diff --git a/ruby/lib/gitlab/git/commit.rb b/ruby/lib/gitlab/git/commit.rb new file mode 100644 index 000000000..3bd736ecd --- /dev/null +++ b/ruby/lib/gitlab/git/commit.rb @@ -0,0 +1,9 @@ +module Gitlab + module Git + class Commit + def to_diff + rugged_diff_from_parent.patch + end + end + end +end diff --git a/ruby/spec/lib/gitaly_server/utils_spec.rb b/ruby/spec/lib/gitaly_server/utils_spec.rb index 9e00411db..5a457f48c 100644 --- a/ruby/spec/lib/gitaly_server/utils_spec.rb +++ b/ruby/spec/lib/gitaly_server/utils_spec.rb @@ -47,7 +47,7 @@ describe GitalyServer::Utils do repo = Rugged::Repository.new(TEST_REPO_PATH) rugged_tag = repo.tags.first full_message = "subject\n\n" + ("a" * 100 * 1024) - gitlab_tag = Gitlab::Git::Tag.new(repo, rugged_tag.name, rugged_tag.target.oid, rugged_tag.target, full_message) + gitlab_tag = Gitlab::Git::Tag.new(repo, name: rugged_tag.name, target: rugged_tag.target.oid, target_commit: rugged_tag.target, message: full_message) limit = 10 * 1024 allow_any_instance_of(Gitlab::Config::Git).to receive(:max_commit_or_tag_message_size).and_return(limit) diff --git a/ruby/vendor/gitlab_git/REVISION b/ruby/vendor/gitlab_git/REVISION index 4a85a6d1c..a5f63575a 100644 --- a/ruby/vendor/gitlab_git/REVISION +++ b/ruby/vendor/gitlab_git/REVISION @@ -1 +1 @@ -3fcb9c115d776feba3f71fb58359a3935edfda9b +930ad88a87b0814173989aaccc6dc8af00d1bf65 diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/blame.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/blame.rb index 6d6ed065f..4158d50cd 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/blame.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/blame.rb @@ -15,10 +15,7 @@ module Gitlab def each @blames.each do |blame| - yield( - Gitlab::Git::Commit.new(@repo, blame.commit), - blame.line - ) + yield(blame.commit, blame.line) end end @@ -60,9 +57,8 @@ module Gitlab end end - # load all commits in single call - commits.keys.each do |key| - commits[key] = @repo.lookup(key) + Gitlab::Git::Commit.batch_by_oid(@repo, commits.keys).each do |commit| + commits[commit.sha] = commit end # get it together diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/blob.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/blob.rb index eabcf46cf..156d077a6 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/blob.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/blob.rb @@ -62,6 +62,12 @@ module Gitlab end end + # Returns an array of Blob instances just with the metadata, that means + # the data attribute has no content. + def batch_metadata(repository, blob_references) + batch(repository, blob_references, blob_size_limit: 0) + end + # Find LFS blobs given an array of sha ids # Returns array of Gitlab::Git::Blob # Does not guarantee blob data will be set @@ -98,25 +104,22 @@ module Gitlab # file.rb # oid: 4a # # - # Blob.find_entry_by_path(repo, '1a', 'app/file.rb') # => '4a' + # Blob.find_entry_by_path(repo, '1a', 'blog', 'app', 'file.rb') # => '4a' # - def find_entry_by_path(repository, root_id, path) + def find_entry_by_path(repository, root_id, *path_parts) root_tree = repository.lookup(root_id) - # Strip leading slashes - path[%r{^/*}] = '' - path_arr = path.split('/') entry = root_tree.find do |entry| - entry[:name] == path_arr[0] + entry[:name] == path_parts[0] end return nil unless entry - if path_arr.size > 1 + if path_parts.size > 1 return nil unless entry[:type] == :tree - path_arr.shift - find_entry_by_path(repository, entry[:oid], path_arr.join('/')) + path_parts.shift + find_entry_by_path(repository, entry[:oid], *path_parts) else [:blob, :commit].include?(entry[:type]) ? entry : nil end @@ -179,10 +182,13 @@ module Gitlab def find_by_rugged(repository, sha, path, limit:) return unless path + # Strip any leading / characters from the path + path = path.sub(%r{\A/*}, '') + rugged_commit = repository.lookup(sha) root_tree = rugged_commit.tree - blob_entry = find_entry_by_path(repository, root_tree.oid, path) + blob_entry = find_entry_by_path(repository, root_tree.oid, *path.split('/')) return nil unless blob_entry diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/commit.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/commit.rb index fabcd46c8..89f761dd5 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/commit.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/commit.rb @@ -6,6 +6,7 @@ module Gitlab attr_accessor :raw_commit, :head + MAX_COMMIT_MESSAGE_DISPLAY_SIZE = 10.megabytes MIN_SHA_LENGTH = 7 SERIALIZE_KEYS = [ :id, :message, :parent_ids, @@ -63,9 +64,7 @@ module Gitlab if is_enabled repo.gitaly_commit_client.find_commit(commit_id) else - obj = repo.rev_parse_target(commit_id) - - obj.is_a?(Rugged::Commit) ? obj : nil + rugged_find(repo, commit_id) end end @@ -76,6 +75,12 @@ module Gitlab nil end + def rugged_find(repo, commit_id) + obj = repo.rev_parse_target(commit_id) + + obj.is_a?(Rugged::Commit) ? obj : nil + end + # Get last commit for HEAD # # Ex. @@ -297,11 +302,40 @@ module Gitlab nil end end + + def get_message(repository, commit_id) + BatchLoader.for({ repository: repository, commit_id: commit_id }).batch do |items, loader| + items_by_repo = items.group_by { |i| i[:repository] } + + items_by_repo.each do |repo, items| + commit_ids = items.map { |i| i[:commit_id] } + + messages = get_messages(repository, commit_ids) + + messages.each do |commit_sha, message| + loader.call({ repository: repository, commit_id: commit_sha }, message) + end + end + end + end + + def get_messages(repository, commit_ids) + repository.gitaly_migrate(:commit_messages) do |is_enabled| + if is_enabled + repository.gitaly_commit_client.get_commit_messages(commit_ids) + else + commit_ids.map { |id| [id, rugged_find(repository, id).message] }.to_h + end + end + end end def initialize(repository, raw_commit, head = nil) raise "Nil as raw commit passed" unless raw_commit + @repository = repository + @head = head + case raw_commit when Hash init_from_hash(raw_commit) @@ -312,9 +346,6 @@ module Gitlab else raise "Invalid raw commit type: #{raw_commit.class}" end - - @repository = repository - @head = head end def sha @@ -342,21 +373,6 @@ module Gitlab parent_ids.first end - # Shows the diff between the commit's parent and the commit. - # - # Cuts out the header and stats from #to_patch and returns only the diff. - # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324 - def to_diff - Gitlab::GitalyClient.migrate(:commit_patch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| - if is_enabled - @repository.gitaly_commit_client.patch(id) - else - rugged_diff_from_parent.patch - end - end - end - # Returns a diff object for the changes from this commit's first parent. # If there is no parent, then the diff is between this commit and an # empty repo. See Repository#diff for keys allowed in the +options+ @@ -432,16 +448,6 @@ module Gitlab Gitlab::Git::CommitStats.new(@repository, self) end - def to_patch(options = {}) - begin - rugged_commit.to_mbox(options) - rescue Rugged::InvalidError => ex - if ex.message =~ /commit \w+ is a merge commit/i - 'Patch format is not currently supported for merge commits.' - end - end - end - # Get ref names collection # # Ex. @@ -543,7 +549,7 @@ module Gitlab # TODO: Once gitaly "takes over" Rugged consider separating the # subject from the message to make it clearer when there's one # available but not the other. - @message = (commit.body.presence || commit.subject).dup + @message = message_from_gitaly_body @authored_date = Time.at(commit.author.date.seconds).utc @author_name = commit.author.name.dup @author_email = commit.author.email.dup @@ -595,6 +601,25 @@ module Gitlab def refs(repo) repo.refs_hash[id] end + + def message_from_gitaly_body + return @raw_commit.subject.dup if @raw_commit.body_size.zero? + return @raw_commit.body.dup if full_body_fetched_from_gitaly? + + if @raw_commit.body_size > MAX_COMMIT_MESSAGE_DISPLAY_SIZE + "#{@raw_commit.subject}\n\n--commit message is too big".strip + else + fetch_body_from_gitaly + end + end + + def full_body_fetched_from_gitaly? + @raw_commit.body.bytesize == @raw_commit.body_size + end + + def fetch_body_from_gitaly + self.class.get_message(@repository, id) + end end end end diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/gitlab_projects.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/gitlab_projects.rb index 099709620..00c943fdb 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/gitlab_projects.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/gitlab_projects.rb @@ -53,7 +53,7 @@ module Gitlab # Import project via git clone --bare # URL must be publicly cloneable def import_project(source, timeout) - Gitlab::GitalyClient.migrate(:import_repository) do |is_enabled| + Gitlab::GitalyClient.migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_import_repository(source) else @@ -63,7 +63,8 @@ module Gitlab end def fork_repository(new_shard_name, new_repository_relative_path) - Gitlab::GitalyClient.migrate(:fork_repository) do |is_enabled| + Gitlab::GitalyClient.migrate(:fork_repository, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_fork_repository(new_shard_name, new_repository_relative_path) else diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/path_helper.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/path_helper.rb index 155cf52f0..57b82a37d 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/path_helper.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/path_helper.rb @@ -6,7 +6,7 @@ module Gitlab class << self def normalize_path(filename) # Strip all leading slashes so that //foo -> foo - filename[%r{^/*}] = '' + filename = filename.sub(%r{\A/*}, '') # Expand relative paths (e.g. foo/../bar) filename = Pathname.new(filename) diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/raw_diff_change.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/raw_diff_change.rb index 92f6c45ce..98de93280 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/raw_diff_change.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/raw_diff_change.rb @@ -6,7 +6,15 @@ module Gitlab attr_reader :blob_id, :blob_size, :old_path, :new_path, :operation def initialize(raw_change) - parse(raw_change) + if raw_change.is_a?(Gitaly::GetRawChangesResponse::RawChange) + @blob_id = raw_change.blob_id + @blob_size = raw_change.size + @old_path = raw_change.old_path.presence + @new_path = raw_change.new_path.presence + @operation = raw_change.operation&.downcase || :unknown + else + parse(raw_change) + end end private @@ -20,13 +28,14 @@ module Gitlab # 85bc2f9753afd5f4fc5d7c75f74f8d526f26b4f3 107 R060\tfiles/js/commit.js.coffee\tfiles/js/commit.coffee def parse(raw_change) @blob_id, @blob_size, @raw_operation, raw_paths = raw_change.split(' ', 4) + @blob_size = @blob_size.to_i @operation = extract_operation @old_path, @new_path = extract_paths(raw_paths) end def extract_paths(file_path) case operation - when :renamed + when :copied, :renamed file_path.split(/\t/) when :deleted [file_path, nil] diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/repository.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/repository.rb index de0044fc1..d1b13ca23 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/repository.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/repository.rb @@ -20,6 +20,9 @@ module Gitlab GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE ].freeze SEARCH_CONTEXT_LINES = 3 + # In https://gitlab.com/gitlab-org/gitaly/merge_requests/698 + # We copied these two prefixes into gitaly-go, so don't change these + # or things will break! (REBASE_WORKTREE_PREFIX and SQUASH_WORKTREE_PREFIX) REBASE_WORKTREE_PREFIX = 'rebase'.freeze SQUASH_WORKTREE_PREFIX = 'squash'.freeze GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'.freeze @@ -27,6 +30,7 @@ module Gitlab EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'.freeze NoRepository = Class.new(StandardError) + InvalidRepository = Class.new(StandardError) InvalidBlobName = Class.new(StandardError) InvalidRef = Class.new(StandardError) GitError = Class.new(StandardError) @@ -105,7 +109,7 @@ module Gitlab end def ==(other) - path == other.path + [storage, relative_path] == [other.storage, other.relative_path] end def path @@ -391,33 +395,29 @@ module Gitlab nil end - def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:) + def archive_metadata(ref, storage_path, project_path, format = "tar.gz", append_sha:) ref ||= root_ref commit = Gitlab::Git::Commit.find(self, ref) return {} if commit.nil? - prefix = archive_prefix(ref, commit.id, append_sha: append_sha) + prefix = archive_prefix(ref, commit.id, project_path, append_sha: append_sha) { - 'RepoPath' => path, 'ArchivePrefix' => prefix, 'ArchivePath' => archive_file_path(storage_path, commit.id, prefix, format), - 'CommitId' => commit.id + 'CommitId' => commit.id, + 'GitalyRepository' => gitaly_repository.to_h } end # This is both the filename of the archive (missing the extension) and the # name of the top-level member of the archive under which all files go - # - # FIXME: The generated prefix is incorrect for projects with hashed - # storage enabled - def archive_prefix(ref, sha, append_sha:) + def archive_prefix(ref, sha, project_path, append_sha:) append_sha = (ref != sha) if append_sha.nil? - project_name = self.name.chomp('.git') formatted_ref = ref.tr('/', '-') - prefix_segments = [project_name, formatted_ref] + prefix_segments = [project_path, formatted_ref] prefix_segments << sha if append_sha prefix_segments.join('-') @@ -578,19 +578,36 @@ module Gitlab # old_rev and new_rev are commit ID's # the result of this method is an array of Gitlab::Git::RawDiffChange def raw_changes_between(old_rev, new_rev) - result = [] + @raw_changes_between ||= {} - circuit_breaker.perform do - Open3.pipeline_r(git_diff_cmd(old_rev, new_rev), format_git_cat_file_script, git_cat_file_cmd) do |last_stdout, wait_threads| - last_stdout.each_line { |line| result << ::Gitlab::Git::RawDiffChange.new(line.chomp!) } + @raw_changes_between[[old_rev, new_rev]] ||= begin + return [] if new_rev.blank? || new_rev == Gitlab::Git::BLANK_SHA + + gitaly_migrate(:raw_changes_between) do |is_enabled| + if is_enabled + gitaly_repository_client.raw_changes_between(old_rev, new_rev) + .each_with_object([]) do |msg, arr| + msg.raw_changes.each { |change| arr << ::Gitlab::Git::RawDiffChange.new(change) } + end + else + result = [] - if wait_threads.any? { |waiter| !waiter.value&.success? } - raise ::Gitlab::Git::Repository::GitError, "Unabled to obtain changes between #{old_rev} and #{new_rev}" + circuit_breaker.perform do + Open3.pipeline_r(git_diff_cmd(old_rev, new_rev), format_git_cat_file_script, git_cat_file_cmd) do |last_stdout, wait_threads| + last_stdout.each_line { |line| result << ::Gitlab::Git::RawDiffChange.new(line.chomp!) } + + if wait_threads.any? { |waiter| !waiter.value&.success? } + raise ::Gitlab::Git::Repository::GitError, "Unabled to obtain changes between #{old_rev} and #{new_rev}" + end + end + end + + result end end end - - result + rescue ArgumentError => e + raise Gitlab::Git::Repository::GitError.new(e) end # Returns the SHA of the most recent common ancestor of +from+ and +to+ @@ -755,13 +772,9 @@ module Gitlab end def add_branch(branch_name, user:, target:) - gitaly_migrate(:operation_user_create_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| - if is_enabled - gitaly_add_branch(branch_name, user, target) - else - rugged_add_branch(branch_name, user, target) - end - end + gitaly_operation_client.user_create_branch(branch_name, user, target) + rescue GRPC::FailedPrecondition => ex + raise InvalidRef, ex end def add_tag(tag_name, user:, target:, message: nil) @@ -1031,7 +1044,7 @@ module Gitlab return @info_attributes if @info_attributes content = - gitaly_migrate(:get_info_attributes) do |is_enabled| + gitaly_migrate(:get_info_attributes, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_repository_client.info_attributes else @@ -1168,15 +1181,17 @@ module Gitlab end def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:) - with_repo_branch_commit(source_repository, source_branch_name) do |commit| - break unless commit - - Gitlab::Git::Compare.new( - self, - target_branch_name, - commit.sha, - straight: straight - ) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + with_repo_branch_commit(source_repository, source_branch_name) do |commit| + break unless commit + + Gitlab::Git::Compare.new( + self, + target_branch_name, + commit.sha, + straight: straight + ) + end end end @@ -1317,7 +1332,7 @@ module Gitlab end def squash_in_progress?(squash_id) - gitaly_migrate(:squash_in_progress) do |is_enabled| + gitaly_migrate(:squash_in_progress, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_repository_client.squash_in_progress?(squash_id) else @@ -1378,6 +1393,11 @@ module Gitlab def write_config(full_path:) return unless full_path.present? + # This guard avoids Gitaly log/error spam + unless exists? + raise NoRepository, 'repository does not exist' + end + gitaly_migrate(:write_config) do |is_enabled| if is_enabled gitaly_repository_client.write_config(full_path: full_path) @@ -1438,7 +1458,7 @@ module Gitlab gitaly_repository_client.cleanup if is_enabled && exists? end rescue Gitlab::Git::CommandError => e # Don't fail if we can't cleanup - Rails.logger.error("Unable to clean repository on storage #{storage} with path #{path}: #{e.message}") + Rails.logger.error("Unable to clean repository on storage #{storage} with relative path #{relative_path}: #{e.message}") Gitlab::Metrics.counter( :failed_repository_cleanup_total, 'Number of failed repository cleanup events' @@ -1446,34 +1466,29 @@ module Gitlab end def branch_names_contains_sha(sha) - gitaly_migrate(:branch_names_contains_sha, - status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| - if is_enabled - gitaly_ref_client.branch_names_contains_sha(sha) - else - refs_contains_sha('refs/heads/', sha) - end - end + gitaly_ref_client.branch_names_contains_sha(sha) end def tag_names_contains_sha(sha) - gitaly_migrate(:tag_names_contains_sha, - status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| - if is_enabled - gitaly_ref_client.tag_names_contains_sha(sha) - else - refs_contains_sha('refs/tags/', sha) - end - end + gitaly_ref_client.tag_names_contains_sha(sha) end def search_files_by_content(query, ref) return [] if empty? || query.blank? - offset = 2 - args = %W(grep -i -I -n -z --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref}) + safe_query = Regexp.escape(query) + ref ||= root_ref + + gitaly_migrate(:search_files_by_content) do |is_enabled| + if is_enabled + gitaly_repository_client.search_files_by_content(ref, safe_query) + else + offset = 2 + args = %W(grep -i -I -n -z --before-context #{offset} --after-context #{offset} -E -e #{safe_query} #{ref}) - run_git(args).first.scrub.split(/^--\n/) + run_git(args).first.scrub.split(/^--\n/) + end + end end def can_be_merged?(source_sha, target_branch) @@ -1488,12 +1503,19 @@ module Gitlab def search_files_by_name(query, ref) safe_query = Regexp.escape(query.sub(%r{^/*}, "")) + ref ||= root_ref return [] if empty? || safe_query.blank? - args = %W(ls-tree -r --name-status --full-tree #{ref || root_ref} -- #{safe_query}) + gitaly_migrate(:search_files_by_name) do |is_enabled| + if is_enabled + gitaly_repository_client.search_files_by_name(ref, safe_query) + else + args = %W(ls-tree -r --name-status --full-tree #{ref} -- #{safe_query}) - run_git(args).first.lines.map(&:strip) + run_git(args).first.lines.map(&:strip) + end + end end def find_commits_by_message(query, ref, path, limit, offset) @@ -1569,13 +1591,12 @@ module Gitlab end def checksum - gitaly_migrate(:calculate_checksum) do |is_enabled| - if is_enabled - gitaly_repository_client.calculate_checksum - else - calculate_checksum_by_shelling_out - end - end + # The exists? RPC is much cheaper, so we perform this request first + raise NoRepository, "Repository does not exists" unless exists? + + gitaly_repository_client.calculate_checksum + rescue GRPC::NotFound + raise NoRepository # Guard against data races. end private @@ -1598,27 +1619,6 @@ module Gitlab end end - def refs_contains_sha(refs_prefix, sha) - refs_prefix << "/" unless refs_prefix.ends_with?('/') - - # By forcing the output to %(refname) each line wiht a ref will start with - # the ref prefix. All other lines can be discarded. - args = %W(for-each-ref --contains=#{sha} --format=%(refname) #{refs_prefix}) - names, code = run_git(args) - - return [] unless code.zero? - - refs = [] - left_slice_count = refs_prefix.length - names.lines.each do |line| - next unless line.start_with?(refs_prefix) - - refs << encode_utf8(line.rstrip[left_slice_count..-1]) - end - - refs - end - def rugged_write_config(full_path:) rugged.config['gitlab.fullpath'] = full_path end @@ -1670,10 +1670,14 @@ module Gitlab end end + # This function is duplicated in Gitaly-Go, don't change it! + # https://gitlab.com/gitlab-org/gitaly/merge_requests/698 def fresh_worktree?(path) File.exist?(path) && !clean_stuck_worktree(path) end + # This function is duplicated in Gitaly-Go, don't change it! + # https://gitlab.com/gitlab-org/gitaly/merge_requests/698 def clean_stuck_worktree(path) return false unless File.mtime(path) < 15.minutes.ago @@ -1961,7 +1965,12 @@ module Gitlab end target_commit = Gitlab::Git::Commit.find(self, ref.target) - Gitlab::Git::Tag.new(self, ref.name, ref.target, target_commit, message) + Gitlab::Git::Tag.new(self, { + name: ref.name, + target: ref.target, + target_commit: target_commit, + message: message + }) end.sort_by(&:name) end @@ -2206,22 +2215,6 @@ module Gitlab end end - def gitaly_add_branch(branch_name, user, target) - gitaly_operation_client.user_create_branch(branch_name, user, target) - rescue GRPC::FailedPrecondition => ex - raise InvalidRef, ex - end - - def rugged_add_branch(branch_name, user, target) - target_object = Ref.dereference_object(lookup(target)) - raise InvalidRef.new("target not found: #{target}") unless target_object - - OperationService.new(user, self).add_branch(branch_name, target_object.oid) - find_branch(branch_name) - rescue Rugged::ReferenceError => ex - raise InvalidRef, ex - end - def rugged_cherry_pick(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:) OperationService.new(user, self).with_branch( branch_name, @@ -2377,7 +2370,7 @@ module Gitlab end def gitaly_delete_refs(*ref_names) - gitaly_ref_client.delete_refs(refs: ref_names) + gitaly_ref_client.delete_refs(refs: ref_names) if ref_names.any? end def rugged_remove_remote(remote_name) @@ -2507,34 +2500,6 @@ module Gitlab rev_parse_target(ref).oid end - def calculate_checksum_by_shelling_out - raise NoRepository unless exists? - - args = %W(--git-dir=#{path} show-ref --heads --tags) - output, status = run_git(args) - - if status.nil? || !status.zero? - # Empty repositories return with a non-zero status and an empty output. - return EMPTY_REPOSITORY_CHECKSUM if output&.empty? - - raise ChecksumError, output - end - - refs = output.split("\n") - - result = refs.inject(nil) do |checksum, ref| - value = Digest::SHA1.hexdigest(ref).hex - - if checksum.nil? - value - else - checksum ^ value - end - end - - result.to_s(16) - end - def build_git_cmd(*args) object_directories = alternate_object_directories.join(File::PATH_SEPARATOR) diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/repository_mirroring.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/repository_mirroring.rb index 8a01f92e2..e35ea5762 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/repository_mirroring.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/repository_mirroring.rb @@ -35,7 +35,11 @@ module Gitlab next if name =~ /\^\{\}\Z/ target_commit = Gitlab::Git::Commit.find(self, target) - Gitlab::Git::Tag.new(self, name, target, target_commit) + Gitlab::Git::Tag.new(self, { + name: name, + target: target, + target_commit: target_commit + }) end.compact end diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/storage/checker.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/storage/checker.rb index 2f611cef3..391f0d705 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/storage/checker.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/storage/checker.rb @@ -35,7 +35,7 @@ module Gitlab def initialize(storage, logger = Rails.logger) @storage = storage config = Gitlab.config.repositories.storages[@storage] - @storage_path = config.legacy_disk_path + @storage_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { config.legacy_disk_path } @logger = logger @hostname = Gitlab::Environment.hostname diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/storage/circuit_breaker.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/storage/circuit_breaker.rb index e35054466..62427ac9c 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/storage/circuit_breaker.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/storage/circuit_breaker.rb @@ -22,13 +22,14 @@ module Gitlab def self.build(storage, hostname = Gitlab::Environment.hostname) config = Gitlab.config.repositories.storages[storage] - - if !config.present? - NullCircuitBreaker.new(storage, hostname, error: Misconfiguration.new("Storage '#{storage}' is not configured")) - elsif !config.legacy_disk_path.present? - NullCircuitBreaker.new(storage, hostname, error: Misconfiguration.new("Path for storage '#{storage}' is not configured")) - else - new(storage, hostname) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + if !config.present? + NullCircuitBreaker.new(storage, hostname, error: Misconfiguration.new("Storage '#{storage}' is not configured")) + elsif !config.legacy_disk_path.present? + NullCircuitBreaker.new(storage, hostname, error: Misconfiguration.new("Path for storage '#{storage}' is not configured")) + else + new(storage, hostname) + end end end diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/tag.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/tag.rb index 8a8f7b051..e44284572 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/tag.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/tag.rb @@ -1,17 +1,99 @@ module Gitlab module Git class Tag < Ref - attr_reader :object_sha + extend Gitlab::EncodingHelper + + attr_reader :object_sha, :repository + + MAX_TAG_MESSAGE_DISPLAY_SIZE = 10.megabytes + SERIALIZE_KEYS = %i[name target target_commit message].freeze + + attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator + + class << self + def get_message(repository, tag_id) + BatchLoader.for({ repository: repository, tag_id: tag_id }).batch do |items, loader| + items_by_repo = items.group_by { |i| i[:repository] } + + items_by_repo.each do |repo, items| + tag_ids = items.map { |i| i[:tag_id] } + + messages = get_messages(repository, tag_ids) + + messages.each do |id, message| + loader.call({ repository: repository, tag_id: id }, message) + end + end + end + end + + def get_messages(repository, tag_ids) + repository.gitaly_migrate(:tag_messages) do |is_enabled| + if is_enabled + repository.gitaly_ref_client.get_tag_messages(tag_ids) + else + tag_ids.map do |id| + tag = repository.rugged.lookup(id) + message = tag.is_a?(Rugged::Commit) ? "" : tag.message + + [id, message] + end.to_h + end + end + end + end + + def initialize(repository, raw_tag) + @repository = repository + @raw_tag = raw_tag + + case raw_tag + when Hash + init_from_hash + when Gitaly::Tag + init_from_gitaly + end - def initialize(repository, name, target, target_commit, message = nil) super(repository, name, target, target_commit) + end + + def init_from_hash + raw_tag = @raw_tag.symbolize_keys + + SERIALIZE_KEYS.each do |key| + send("#{key}=", raw_tag[key]) # rubocop:disable GitlabSecurity/PublicSend + end + end + + def init_from_gitaly + @name = encode!(@raw_tag.name.dup) + @target = @raw_tag.id + @message = message_from_gitaly_tag - @message = message + if @raw_tag.target_commit.present? + @target_commit = Gitlab::Git::Commit.decorate(repository, @raw_tag.target_commit) + end end def message encode! @message end + + private + + def message_from_gitaly_tag + return @raw_tag.message.dup if full_message_fetched_from_gitaly? + + if @raw_tag.message_size > MAX_TAG_MESSAGE_DISPLAY_SIZE + '--tag message is too big' + else + self.class.get_message(@repository, target) + end + end + + def full_message_fetched_from_gitaly? + @raw_tag.message.bytesize == @raw_tag.message_size + end end end end diff --git a/ruby/vendor/gitlab_git/lib/gitlab/git/wiki.rb b/ruby/vendor/gitlab_git/lib/gitlab/git/wiki.rb index 84a26fe4a..1ab8c4e02 100644 --- a/ruby/vendor/gitlab_git/lib/gitlab/git/wiki.rb +++ b/ruby/vendor/gitlab_git/lib/gitlab/git/wiki.rb @@ -67,7 +67,8 @@ module Gitlab end def page(title:, version: nil, dir: nil) - @repository.gitaly_migrate(:wiki_find_page) do |is_enabled| + @repository.gitaly_migrate(:wiki_find_page, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_find_page(title: title, version: version, dir: dir) else @@ -130,7 +131,7 @@ module Gitlab def page_formatted_data(title:, dir: nil, version: nil) version = version&.id - @repository.gitaly_migrate(:wiki_page_formatted_data) do |is_enabled| + @repository.gitaly_migrate(:wiki_page_formatted_data, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| if is_enabled gitaly_wiki_client.get_formatted_data(title: title, dir: dir, version: version) else |