From 9fda629a347cb43d8f5871f101192187fcdeeea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Thu, 5 Oct 2017 20:22:24 -0300 Subject: Encapsulate git operations for conflict resolution into lib --- lib/gitlab/conflict/file_collection.rb | 62 +++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb index 90f83e0f810..4fedfe8691a 100644 --- a/lib/gitlab/conflict/file_collection.rb +++ b/lib/gitlab/conflict/file_collection.rb @@ -2,8 +2,9 @@ module Gitlab module Conflict class FileCollection ConflictSideMissing = Class.new(StandardError) + MissingFiles = Class.new(ResolutionError) - attr_reader :merge_request, :our_commit, :their_commit, :project + attr_reader :merge_request, :our_commit, :their_commit, :project, :read_only delegate :repository, to: :project @@ -13,22 +14,41 @@ module Gitlab # the time because this fetches a ref into the source project, which # isn't needed for reading. def for_resolution(merge_request) - project = merge_request.source_project - - new(merge_request, project).tap do |file_collection| - project - .repository - .with_repo_branch_commit(merge_request.target_project.repository.raw_repository, merge_request.target_branch) do - - yield file_collection - end - end + new(merge_request, merge_request.source_project, false) end # We don't need to do `with_repo_branch_commit` here, because the target # project always fetches source refs when creating merge request diffs. def read_only(merge_request) - new(merge_request, merge_request.target_project) + new(merge_request, merge_request.target_project, true) + end + end + + def resolve(user, commit_message, files) + raise "can't resolve a read-only Conflict File Collection" if read_only + + repository.with_repo_branch_commit(merge_request.target_project.repository.raw, merge_request.target_branch) do + rugged = repository.rugged + + files.each do |file_params| + conflict_file = file_for_path(file_params[:old_path], file_params[:new_path]) + + write_resolved_file_to_index(merge_index, rugged, conflict_file, file_params) + end + + unless merge_index.conflicts.empty? + missing_files = merge_index.conflicts.map { |file| file[:ours][:path] } + + raise MissingFiles, "Missing resolutions for the following files: #{missing_files.join(', ')}" + end + + commit_params = { + message: commit_message || default_commit_message, + parents: [our_commit, their_commit].map(&:oid), + tree: merge_index.write_tree(rugged) + } + + repository.resolve_conflicts(user, merge_request.source_branch, commit_params) end end @@ -75,11 +95,27 @@ EOM private - def initialize(merge_request, project) + def write_resolved_file_to_index(merge_index, rugged, file, params) + if params[:sections] + new_file = file.resolve_lines(params[:sections]).map(&:text).join("\n") + + new_file << "\n" if file.our_blob.data.ends_with?("\n") + elsif params[:content] + new_file = file.resolve_content(params[:content]) + end + + our_path = file.our_path + + merge_index.add(path: our_path, oid: rugged.write(new_file, :blob), mode: file.our_mode) + merge_index.conflict_remove(our_path) + end + + def initialize(merge_request, project, read_only) @merge_request = merge_request @our_commit = merge_request.source_branch_head.raw.rugged_commit @their_commit = merge_request.target_branch_head.raw.rugged_commit @project = project + @read_only = read_only end end end -- cgit v1.2.1 From f72598b659871a3d4e8ef1905918067522ba2a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Fri, 6 Oct 2017 19:42:56 -0300 Subject: Move Gitlab::Diff::LineCode to module Gitlab::Git --- lib/api/commits.rb | 2 +- lib/api/v3/commits.rb | 2 +- lib/github/representation/comment.rb | 2 +- lib/gitlab/bitbucket_import/importer.rb | 2 +- lib/gitlab/conflict/file.rb | 2 +- lib/gitlab/diff/file.rb | 2 +- lib/gitlab/diff/line_code.rb | 9 --------- lib/gitlab/git/diff_line_code.rb | 9 +++++++++ lib/gitlab/github_import/comment_formatter.rb | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) delete mode 100644 lib/gitlab/diff/line_code.rb create mode 100644 lib/gitlab/git/diff_line_code.rb (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 4af37a2ad1d..e2d50b4e0a6 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -186,7 +186,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb index 345cb7e7c11..042f4338d53 100644 --- a/lib/api/v3/commits.rb +++ b/lib/api/v3/commits.rb @@ -173,7 +173,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/github/representation/comment.rb b/lib/github/representation/comment.rb index 1b5be91461b..b87a11672ed 100644 --- a/lib/github/representation/comment.rb +++ b/lib/github/representation/comment.rb @@ -23,7 +23,7 @@ module Github private def generate_line_code(line) - Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) end def on_diff? diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index d1979bb7ed3..f613d8e8179 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -241,7 +241,7 @@ module Gitlab end def generate_line_code(pr_comment) - Gitlab::Diff::LineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) + Gitlab::Git::DiffLineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) end def pull_request_comment_attributes(comment) diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 98dfe900044..52f8fe27f3b 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -163,7 +163,7 @@ module Gitlab end def line_code(line) - Gitlab::Diff::LineCode.generate(our_path, line.new_pos, line.old_pos) + Gitlab::Git::DiffLineCode.generate(our_path, line.new_pos, line.old_pos) end def create_match_line(line) diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 599c3c5deab..bc2c25c9cb6 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -49,7 +49,7 @@ module Gitlab def line_code(line) return if line.meta? - Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) end def line_for_line_code(code) diff --git a/lib/gitlab/diff/line_code.rb b/lib/gitlab/diff/line_code.rb deleted file mode 100644 index f3578ab3d35..00000000000 --- a/lib/gitlab/diff/line_code.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Gitlab - module Diff - class LineCode - def self.generate(file_path, new_line_position, old_line_position) - "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" - end - end - end -end diff --git a/lib/gitlab/git/diff_line_code.rb b/lib/gitlab/git/diff_line_code.rb new file mode 100644 index 00000000000..aab963ba928 --- /dev/null +++ b/lib/gitlab/git/diff_line_code.rb @@ -0,0 +1,9 @@ +module Gitlab + module Git + class DiffLineCode + def self.generate(file_path, new_line_position, old_line_position) + "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" + end + end + end +end diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb index e21922070c1..6490cd7002d 100644 --- a/lib/gitlab/github_import/comment_formatter.rb +++ b/lib/gitlab/github_import/comment_formatter.rb @@ -38,7 +38,7 @@ module Gitlab end def generate_line_code(line) - Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) end def on_diff? -- cgit v1.2.1 From 9cc15172deaa4582c5fd956cc163539041d018b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Fri, 6 Oct 2017 20:47:06 -0300 Subject: Clean hierarchy of calls between models and Gitalb::Git for blob search --- lib/gitlab/git/repository.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a6b2d189f18..b705c92d686 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1092,6 +1092,10 @@ module Gitlab popen(args, @path).last.zero? end + def blob_at(sha, path) + Gitlab::Git::Blob.find(self, sha, path) unless Gitlab::Git.blank_ref?(sha) + end + def gitaly_repository Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository) end -- cgit v1.2.1 From 3fcab51ebb0f3156b5d732d050b292cd3e081262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Fri, 6 Oct 2017 22:41:23 -0300 Subject: Refactor conflict resolution to contain git ops within Gitlab::Git This prepares the codebase for a Gitaly migration. See https://gitlab.com/gitlab-org/gitaly/issues/553 --- lib/gitlab/conflict/file.rb | 84 ++++++-------------------- lib/gitlab/conflict/file_collection.rb | 102 ++++++-------------------------- lib/gitlab/conflict/parser.rb | 74 ----------------------- lib/gitlab/conflict/resolution_error.rb | 5 -- lib/gitlab/git/conflict_file.rb | 84 ++++++++++++++++++++++++++ lib/gitlab/git/conflict_parser.rb | 89 ++++++++++++++++++++++++++++ lib/gitlab/git/merge.rb | 89 ++++++++++++++++++++++++++++ lib/gitlab/git/repository.rb | 14 +++++ 8 files changed, 314 insertions(+), 227 deletions(-) delete mode 100644 lib/gitlab/conflict/parser.rb delete mode 100644 lib/gitlab/conflict/resolution_error.rb create mode 100644 lib/gitlab/git/conflict_file.rb create mode 100644 lib/gitlab/git/conflict_parser.rb create mode 100644 lib/gitlab/git/merge.rb (limited to 'lib') diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 52f8fe27f3b..2d8a21f4905 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -4,82 +4,26 @@ module Gitlab include Gitlab::Routing include IconsHelper - MissingResolution = Class.new(ResolutionError) - CONTEXT_LINES = 3 - attr_reader :merge_file_result, :their_path, :our_path, :our_mode, :merge_request, :repository + attr_reader :merge_request, :raw + + delegate :type, :content, :their_path, :our_path, :our_mode, :our_blob, :repository, to: :raw - def initialize(merge_file_result, conflict, merge_request:) - @merge_file_result = merge_file_result - @their_path = conflict[:theirs][:path] - @our_path = conflict[:ours][:path] - @our_mode = conflict[:ours][:mode] + def initialize(raw, merge_request:) + @raw = raw @merge_request = merge_request - @repository = merge_request.project.repository @match_line_headers = {} end - def content - merge_file_result[:data] - end - - def our_blob - @our_blob ||= repository.blob_at(merge_request.diff_refs.head_sha, our_path) - end - - def type - lines unless @type - - @type.inquiry - end - - # Array of Gitlab::Diff::Line objects def lines return @lines if defined?(@lines) - begin - @type = 'text' - @lines = Gitlab::Conflict::Parser.new.parse(content, - our_path: our_path, - their_path: their_path, - parent_file: self) - rescue Gitlab::Conflict::Parser::ParserError - @type = 'text-editor' - @lines = nil - end + @lines = raw.lines.nil? ? nil : map_raw_lines(raw.lines) end def resolve_lines(resolution) - section_id = nil - - lines.map do |line| - unless line.type - section_id = nil - next line - end - - section_id ||= line_code(line) - - case resolution[section_id] - when 'head' - next unless line.type == 'new' - when 'origin' - next unless line.type == 'old' - else - raise MissingResolution, "Missing resolution for section ID: #{section_id}" - end - - line - end.compact - end - - def resolve_content(resolution) - if resolution == content - raise MissingResolution, "Resolved content has no changes for file #{our_path}" - end - - resolution + map_raw_lines(raw.resolve_lines(resolution)) end def highlight_lines! @@ -227,9 +171,9 @@ module Gitlab new_path: our_path) end - # Don't try to print merge_request or repository. + # Don't try to print merge_request. def inspect - instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode, :type].map do |instance_variable| + instance_variables = [:content, :their_path, :our_path, :our_mode, :type].map do |instance_variable| value = instance_variable_get("@#{instance_variable}") "#{instance_variable}=\"#{value}\"" @@ -237,6 +181,16 @@ module Gitlab "#<#{self.class} #{instance_variables.join(' ')}>" end + + private + + def map_raw_lines(raw_lines) + raw_lines.map do |raw_line| + Gitlab::Diff::Line.new(raw_line[:full_line], raw_line[:type], + raw_line[:line_obj_index], raw_line[:line_old], + raw_line[:line_new], parent_file: self) + end + end end end end diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb index 4fedfe8691a..573a953b2aa 100644 --- a/lib/gitlab/conflict/file_collection.rb +++ b/lib/gitlab/conflict/file_collection.rb @@ -1,68 +1,29 @@ module Gitlab module Conflict class FileCollection - ConflictSideMissing = Class.new(StandardError) - MissingFiles = Class.new(ResolutionError) - - attr_reader :merge_request, :our_commit, :their_commit, :project, :read_only - - delegate :repository, to: :project - - class << self - # We can only write when getting the merge index from the source - # project, because we will write to that project. We don't use this all - # the time because this fetches a ref into the source project, which - # isn't needed for reading. - def for_resolution(merge_request) - new(merge_request, merge_request.source_project, false) - end - - # We don't need to do `with_repo_branch_commit` here, because the target - # project always fetches source refs when creating merge request diffs. - def read_only(merge_request) - new(merge_request, merge_request.target_project, true) - end + attr_reader :merge_request, :merge + + def initialize(merge_request) + source_repo = merge_request.source_project.repository.raw + our_commit = merge_request.source_branch_head.raw + their_commit = merge_request.target_branch_head.raw + target_repo = merge_request.target_project.repository.raw + @merge = Gitlab::Git::Merge.new(source_repo, our_commit, target_repo, their_commit) + @merge_request = merge_request end def resolve(user, commit_message, files) - raise "can't resolve a read-only Conflict File Collection" if read_only - - repository.with_repo_branch_commit(merge_request.target_project.repository.raw, merge_request.target_branch) do - rugged = repository.rugged - - files.each do |file_params| - conflict_file = file_for_path(file_params[:old_path], file_params[:new_path]) - - write_resolved_file_to_index(merge_index, rugged, conflict_file, file_params) - end - - unless merge_index.conflicts.empty? - missing_files = merge_index.conflicts.map { |file| file[:ours][:path] } - - raise MissingFiles, "Missing resolutions for the following files: #{missing_files.join(', ')}" - end - - commit_params = { - message: commit_message || default_commit_message, - parents: [our_commit, their_commit].map(&:oid), - tree: merge_index.write_tree(rugged) - } - - repository.resolve_conflicts(user, merge_request.source_branch, commit_params) - end - end - - def merge_index - @merge_index ||= repository.rugged.merge_commits(our_commit, their_commit) + args = { + source_branch: merge_request.source_branch, + target_branch: merge_request.target_branch, + commit_message: commit_message || default_commit_message + } + merge.resolve_conflicts(user, files, args) end def files - @files ||= merge_index.conflicts.map do |conflict| - raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours] - - Gitlab::Conflict::File.new(merge_index.merge_file(conflict[:ours][:path]), - conflict, - merge_request: merge_request) + @files ||= merge.conflicts.map do |conflict_file| + Gitlab::Conflict::File.new(conflict_file, merge_request: merge_request) end end @@ -81,8 +42,8 @@ module Gitlab end def default_commit_message - conflict_filenames = merge_index.conflicts.map do |conflict| - "# #{conflict[:ours][:path]}" + conflict_filenames = files.map do |conflict| + "# #{conflict.our_path}" end < 200.kilobytes - - text.force_encoding('UTF-8') - - raise UnsupportedEncoding unless text.valid_encoding? - end - - def validate_delimiter!(condition) - raise UnexpectedDelimiter unless condition - end - end - end -end diff --git a/lib/gitlab/conflict/resolution_error.rb b/lib/gitlab/conflict/resolution_error.rb deleted file mode 100644 index 0b61256b35a..00000000000 --- a/lib/gitlab/conflict/resolution_error.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Gitlab - module Conflict - ResolutionError = Class.new(StandardError) - end -end diff --git a/lib/gitlab/git/conflict_file.rb b/lib/gitlab/git/conflict_file.rb new file mode 100644 index 00000000000..95a1a9bbe5b --- /dev/null +++ b/lib/gitlab/git/conflict_file.rb @@ -0,0 +1,84 @@ +module Gitlab + module Git + class ConflictFile + attr_reader :content, :their_path, :our_path, :our_mode, :repository + + def initialize(repository, commit_oid, conflict, content) + @repository = repository + @commit_oid = commit_oid + @their_path = conflict[:theirs][:path] + @our_path = conflict[:ours][:path] + @our_mode = conflict[:ours][:mode] + @content = content + end + + def lines + return @lines if defined?(@lines) + + begin + @type = 'text' + @lines = Gitlab::Git::ConflictParser.parse(content, + our_path: our_path, + their_path: their_path) + rescue Gitlab::Git::ConflictParser::ParserError + @type = 'text-editor' + @lines = nil + end + end + + def type + lines unless @type + + @type.inquiry + end + + def our_blob + # REFACTOR NOTE: the source of `commit_oid` used to be + # `merge_request.diff_refs.head_sha`. Instead of passing this value + # around the new lib structure, I decided to use `@commit_oid` which is + # equivalent to `merge_request.source_branch_head.raw.rugged_commit.oid`. + # That is what `merge_request.diff_refs.head_sha` is equivalent to when + # `merge_request` is not persisted (see `MergeRequest#diff_head_commit`). + # I think using the same oid is more consistent anyways, but if Conflicts + # start breaking, the change described above is a good place to look at. + @our_blob ||= repository.blob_at(@commit_oid, our_path) + end + + def line_code(line) + Gitlab::Git::DiffLineCode.generate(our_path, line[:line_new], line[:line_old]) + end + + def resolve_lines(resolution) + section_id = nil + + lines.map do |line| + unless line[:type] + section_id = nil + next line + end + + section_id ||= line_code(line) + + case resolution[section_id] + when 'head' + next unless line[:type] == 'new' + when 'origin' + next unless line[:type] == 'old' + else + raise Gitlab::Git::Merge::ResolutionError, "Missing resolution for section ID: #{section_id}" + end + + line + end.compact + end + + def resolve_content(resolution) + if resolution == content + raise Gitlab::Git::Merge::ResolutionError, "Resolved content has no changes for file #{our_path}" + end + + resolution + end + end + end +end diff --git a/lib/gitlab/git/conflict_parser.rb b/lib/gitlab/git/conflict_parser.rb new file mode 100644 index 00000000000..90b03848aee --- /dev/null +++ b/lib/gitlab/git/conflict_parser.rb @@ -0,0 +1,89 @@ +module Gitlab + module Git + class ConflictParser + UnresolvableError = Class.new(StandardError) + UnmergeableFile = Class.new(UnresolvableError) + UnsupportedEncoding = Class.new(UnresolvableError) + + # Recoverable errors - the conflict can be resolved in an editor, but not with + # sections. + ParserError = Class.new(StandardError) + UnexpectedDelimiter = Class.new(ParserError) + MissingEndDelimiter = Class.new(ParserError) + + class << self + def parse(text, our_path:, their_path:, parent_file: nil) + validate_text!(text) + + line_obj_index = 0 + line_old = 1 + line_new = 1 + type = nil + lines = [] + conflict_start = "<<<<<<< #{our_path}" + conflict_middle = '=======' + conflict_end = ">>>>>>> #{their_path}" + + text.each_line.map do |line| + full_line = line.delete("\n") + + if full_line == conflict_start + validate_delimiter!(type.nil?) + + type = 'new' + elsif full_line == conflict_middle + validate_delimiter!(type == 'new') + + type = 'old' + elsif full_line == conflict_end + validate_delimiter!(type == 'old') + + type = nil + elsif line[0] == '\\' + type = 'nonewline' + lines << { + full_line: full_line, + type: type, + line_obj_index: line_obj_index, + line_old: line_old, + line_new: line_new + } + else + lines << { + full_line: full_line, + type: type, + line_obj_index: line_obj_index, + line_old: line_old, + line_new: line_new + } + + line_old += 1 if type != 'new' + line_new += 1 if type != 'old' + + line_obj_index += 1 + end + end + + raise MissingEndDelimiter unless type.nil? + + lines + end + + private + + def validate_text!(text) + raise UnmergeableFile if text.blank? # Typically a binary file + raise UnmergeableFile if text.length > 200.kilobytes + + text.force_encoding('UTF-8') + + raise UnsupportedEncoding unless text.valid_encoding? + end + + def validate_delimiter!(condition) + raise UnexpectedDelimiter unless condition + end + end + end + end +end diff --git a/lib/gitlab/git/merge.rb b/lib/gitlab/git/merge.rb new file mode 100644 index 00000000000..3a0205c17f4 --- /dev/null +++ b/lib/gitlab/git/merge.rb @@ -0,0 +1,89 @@ +module Gitlab + module Git + class Merge + ConflictSideMissing = Class.new(StandardError) + ResolutionError = Class.new(StandardError) + + def initialize(repository, our_commit, target_repository, their_commit) + @repository = repository + @our_commit = our_commit.rugged_commit + @target_repository = target_repository + @their_commit = their_commit.rugged_commit + end + + def conflicts + @conflicts ||= begin + target_index = @target_repository.rugged.merge_commits(@our_commit, @their_commit) + + # We don't need to do `with_repo_branch_commit` here, because the target + # project always fetches source refs when creating merge request diffs. + target_index.conflicts.map do |conflict| + raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours] + + Gitlab::Git::ConflictFile.new( + @target_repository, + @our_commit.oid, + conflict, + target_index.merge_file(conflict[:ours][:path])[:data] + ) + end + end + end + + def resolve_conflicts(user, files, source_branch:, target_branch:, commit_message:) + @repository.with_repo_branch_commit(@target_repository, target_branch) do + files.each do |file_params| + conflict_file = conflict_for_path(file_params[:old_path], file_params[:new_path]) + + write_resolved_file_to_index(conflict_file, file_params) + end + + unless index.conflicts.empty? + missing_files = index.conflicts.map { |file| file[:ours][:path] } + + raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}" + end + + commit_params = { + message: commit_message, + parents: [@our_commit, @their_commit].map(&:oid) + } + + @repository.commit_index(user, source_branch, index, commit_params) + end + end + + def conflict_for_path(old_path, new_path) + conflicts.find do |conflict| + conflict.their_path == old_path && conflict.our_path == new_path + end + end + + private + + # We can only write when getting the merge index from the source + # project, because we will write to that project. We don't use this all + # the time because this fetches a ref into the source project, which + # isn't needed for reading. + def index + @index ||= @repository.rugged.merge_commits(@our_commit, @their_commit) + end + + def write_resolved_file_to_index(file, params) + if params[:sections] + resolved_lines = file.resolve_lines(params[:sections]) + new_file = resolved_lines.map { |line| line[:full_line] }.join("\n") + + new_file << "\n" if file.our_blob.data.ends_with?("\n") + elsif params[:content] + new_file = file.resolve_content(params[:content]) + end + + our_path = file.our_path + + index.add(path: our_path, oid: @repository.rugged.write(new_file, :blob), mode: file.our_mode) + index.conflict_remove(our_path) + end + end + end +end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index b705c92d686..0eae8913c49 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1096,6 +1096,20 @@ module Gitlab Gitlab::Git::Blob.find(self, sha, path) unless Gitlab::Git.blank_ref?(sha) end + def commit_index(user, branch_name, index, options) + committer = user_to_committer(user) + + OperationService.new(user, self).with_branch(branch_name) do + commit_params = options.merge( + tree: index.write_tree(rugged), + author: committer, + committer: committer + ) + + create_commit(commit_params) + end + end + def gitaly_repository Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository) end -- cgit v1.2.1 From faa9bd402d3521b3f7b4cc2583f8ef1b3cceb821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Mon, 9 Oct 2017 16:40:37 -0300 Subject: Create a Gitlab::Git submodule for conlict-related files Rename classes to (hopefully) clearer names while we're doing that. --- lib/api/commits.rb | 2 +- lib/api/v3/commits.rb | 2 +- lib/github/representation/comment.rb | 2 +- lib/gitlab/bitbucket_import/importer.rb | 2 +- lib/gitlab/conflict/file.rb | 7 ++- lib/gitlab/conflict/file_collection.rb | 8 +-- lib/gitlab/diff/file.rb | 2 +- lib/gitlab/git/conflict/file.rb | 86 +++++++++++++++++++++++++ lib/gitlab/git/conflict/line_code.rb | 11 ++++ lib/gitlab/git/conflict/parser.rb | 91 +++++++++++++++++++++++++++ lib/gitlab/git/conflict/resolver.rb | 91 +++++++++++++++++++++++++++ lib/gitlab/git/conflict_file.rb | 84 ------------------------- lib/gitlab/git/conflict_parser.rb | 89 -------------------------- lib/gitlab/git/diff_line_code.rb | 9 --- lib/gitlab/git/merge.rb | 89 -------------------------- lib/gitlab/github_import/comment_formatter.rb | 2 +- 16 files changed, 294 insertions(+), 283 deletions(-) create mode 100644 lib/gitlab/git/conflict/file.rb create mode 100644 lib/gitlab/git/conflict/line_code.rb create mode 100644 lib/gitlab/git/conflict/parser.rb create mode 100644 lib/gitlab/git/conflict/resolver.rb delete mode 100644 lib/gitlab/git/conflict_file.rb delete mode 100644 lib/gitlab/git/conflict_parser.rb delete mode 100644 lib/gitlab/git/diff_line_code.rb delete mode 100644 lib/gitlab/git/merge.rb (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index e2d50b4e0a6..6ad97f2deb2 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -186,7 +186,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb index 042f4338d53..cbb192d5dfc 100644 --- a/lib/api/v3/commits.rb +++ b/lib/api/v3/commits.rb @@ -173,7 +173,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Git::DiffLineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/github/representation/comment.rb b/lib/github/representation/comment.rb index b87a11672ed..0cb871630fd 100644 --- a/lib/github/representation/comment.rb +++ b/lib/github/representation/comment.rb @@ -23,7 +23,7 @@ module Github private def generate_line_code(line) - Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) end def on_diff? diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index f613d8e8179..38ba5b97ed0 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -241,7 +241,7 @@ module Gitlab end def generate_line_code(pr_comment) - Gitlab::Git::DiffLineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) + Gitlab::Git::Conflict::LineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) end def pull_request_comment_attributes(comment) diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 2d8a21f4905..3392388a45f 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -6,7 +6,10 @@ module Gitlab CONTEXT_LINES = 3 - attr_reader :merge_request, :raw + attr_reader :merge_request + + # 'raw' holds the Gitlab::Git::Conflict::File that this instance wraps + attr_reader :raw delegate :type, :content, :their_path, :our_path, :our_mode, :our_blob, :repository, to: :raw @@ -107,7 +110,7 @@ module Gitlab end def line_code(line) - Gitlab::Git::DiffLineCode.generate(our_path, line.new_pos, line.old_pos) + Gitlab::Git::Conflict::LineCode.generate(our_path, line.new_pos, line.old_pos) end def create_match_line(line) diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb index 573a953b2aa..fb28e80ff73 100644 --- a/lib/gitlab/conflict/file_collection.rb +++ b/lib/gitlab/conflict/file_collection.rb @@ -1,14 +1,14 @@ module Gitlab module Conflict class FileCollection - attr_reader :merge_request, :merge + attr_reader :merge_request, :resolver def initialize(merge_request) source_repo = merge_request.source_project.repository.raw our_commit = merge_request.source_branch_head.raw their_commit = merge_request.target_branch_head.raw target_repo = merge_request.target_project.repository.raw - @merge = Gitlab::Git::Merge.new(source_repo, our_commit, target_repo, their_commit) + @resolver = Gitlab::Git::Conflict::Resolver.new(source_repo, our_commit, target_repo, their_commit) @merge_request = merge_request end @@ -18,11 +18,11 @@ module Gitlab target_branch: merge_request.target_branch, commit_message: commit_message || default_commit_message } - merge.resolve_conflicts(user, files, args) + resolver.resolve_conflicts(user, files, args) end def files - @files ||= merge.conflicts.map do |conflict_file| + @files ||= resolver.conflicts.map do |conflict_file| Gitlab::Conflict::File.new(conflict_file, merge_request: merge_request) end end diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index bc2c25c9cb6..3f8d2041c29 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -49,7 +49,7 @@ module Gitlab def line_code(line) return if line.meta? - Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) end def line_for_line_code(code) diff --git a/lib/gitlab/git/conflict/file.rb b/lib/gitlab/git/conflict/file.rb new file mode 100644 index 00000000000..b2bc653904d --- /dev/null +++ b/lib/gitlab/git/conflict/file.rb @@ -0,0 +1,86 @@ +module Gitlab + module Git + module Conflict + class File + attr_reader :content, :their_path, :our_path, :our_mode, :repository + + def initialize(repository, commit_oid, conflict, content) + @repository = repository + @commit_oid = commit_oid + @their_path = conflict[:theirs][:path] + @our_path = conflict[:ours][:path] + @our_mode = conflict[:ours][:mode] + @content = content + end + + def lines + return @lines if defined?(@lines) + + begin + @type = 'text' + @lines = Gitlab::Git::Conflict::Parser.parse(content, + our_path: our_path, + their_path: their_path) + rescue Gitlab::Git::Conflict::Parser::ParserError + @type = 'text-editor' + @lines = nil + end + end + + def type + lines unless @type + + @type.inquiry + end + + def our_blob + # REFACTOR NOTE: the source of `commit_oid` used to be + # `merge_request.diff_refs.head_sha`. Instead of passing this value + # around the new lib structure, I decided to use `@commit_oid` which is + # equivalent to `merge_request.source_branch_head.raw.rugged_commit.oid`. + # That is what `merge_request.diff_refs.head_sha` is equivalent to when + # `merge_request` is not persisted (see `MergeRequest#diff_head_commit`). + # I think using the same oid is more consistent anyways, but if Conflicts + # start breaking, the change described above is a good place to look at. + @our_blob ||= repository.blob_at(@commit_oid, our_path) + end + + def line_code(line) + Gitlab::Git::Conflict::LineCode.generate(our_path, line[:line_new], line[:line_old]) + end + + def resolve_lines(resolution) + section_id = nil + + lines.map do |line| + unless line[:type] + section_id = nil + next line + end + + section_id ||= line_code(line) + + case resolution[section_id] + when 'head' + next unless line[:type] == 'new' + when 'origin' + next unless line[:type] == 'old' + else + raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Missing resolution for section ID: #{section_id}" + end + + line + end.compact + end + + def resolve_content(resolution) + if resolution == content + raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Resolved content has no changes for file #{our_path}" + end + + resolution + end + end + end + end +end diff --git a/lib/gitlab/git/conflict/line_code.rb b/lib/gitlab/git/conflict/line_code.rb new file mode 100644 index 00000000000..bdbb4c9cb83 --- /dev/null +++ b/lib/gitlab/git/conflict/line_code.rb @@ -0,0 +1,11 @@ +module Gitlab + module Git + module Conflict + class LineCode + def self.generate(file_path, new_line_position, old_line_position) + "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" + end + end + end + end +end diff --git a/lib/gitlab/git/conflict/parser.rb b/lib/gitlab/git/conflict/parser.rb new file mode 100644 index 00000000000..3effa9d2d31 --- /dev/null +++ b/lib/gitlab/git/conflict/parser.rb @@ -0,0 +1,91 @@ +module Gitlab + module Git + module Conflict + class Parser + UnresolvableError = Class.new(StandardError) + UnmergeableFile = Class.new(UnresolvableError) + UnsupportedEncoding = Class.new(UnresolvableError) + + # Recoverable errors - the conflict can be resolved in an editor, but not with + # sections. + ParserError = Class.new(StandardError) + UnexpectedDelimiter = Class.new(ParserError) + MissingEndDelimiter = Class.new(ParserError) + + class << self + def parse(text, our_path:, their_path:, parent_file: nil) + validate_text!(text) + + line_obj_index = 0 + line_old = 1 + line_new = 1 + type = nil + lines = [] + conflict_start = "<<<<<<< #{our_path}" + conflict_middle = '=======' + conflict_end = ">>>>>>> #{their_path}" + + text.each_line.map do |line| + full_line = line.delete("\n") + + if full_line == conflict_start + validate_delimiter!(type.nil?) + + type = 'new' + elsif full_line == conflict_middle + validate_delimiter!(type == 'new') + + type = 'old' + elsif full_line == conflict_end + validate_delimiter!(type == 'old') + + type = nil + elsif line[0] == '\\' + type = 'nonewline' + lines << { + full_line: full_line, + type: type, + line_obj_index: line_obj_index, + line_old: line_old, + line_new: line_new + } + else + lines << { + full_line: full_line, + type: type, + line_obj_index: line_obj_index, + line_old: line_old, + line_new: line_new + } + + line_old += 1 if type != 'new' + line_new += 1 if type != 'old' + + line_obj_index += 1 + end + end + + raise MissingEndDelimiter unless type.nil? + + lines + end + + private + + def validate_text!(text) + raise UnmergeableFile if text.blank? # Typically a binary file + raise UnmergeableFile if text.length > 200.kilobytes + + text.force_encoding('UTF-8') + + raise UnsupportedEncoding unless text.valid_encoding? + end + + def validate_delimiter!(condition) + raise UnexpectedDelimiter unless condition + end + end + end + end + end +end diff --git a/lib/gitlab/git/conflict/resolver.rb b/lib/gitlab/git/conflict/resolver.rb new file mode 100644 index 00000000000..df509c5f4ce --- /dev/null +++ b/lib/gitlab/git/conflict/resolver.rb @@ -0,0 +1,91 @@ +module Gitlab + module Git + module Conflict + class Resolver + ConflictSideMissing = Class.new(StandardError) + ResolutionError = Class.new(StandardError) + + def initialize(repository, our_commit, target_repository, their_commit) + @repository = repository + @our_commit = our_commit.rugged_commit + @target_repository = target_repository + @their_commit = their_commit.rugged_commit + end + + def conflicts + @conflicts ||= begin + target_index = @target_repository.rugged.merge_commits(@our_commit, @their_commit) + + # We don't need to do `with_repo_branch_commit` here, because the target + # project always fetches source refs when creating merge request diffs. + target_index.conflicts.map do |conflict| + raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours] + + Gitlab::Git::Conflict::File.new( + @target_repository, + @our_commit.oid, + conflict, + target_index.merge_file(conflict[:ours][:path])[:data] + ) + end + end + end + + def resolve_conflicts(user, files, source_branch:, target_branch:, commit_message:) + @repository.with_repo_branch_commit(@target_repository, target_branch) do + files.each do |file_params| + conflict_file = conflict_for_path(file_params[:old_path], file_params[:new_path]) + + write_resolved_file_to_index(conflict_file, file_params) + end + + unless index.conflicts.empty? + missing_files = index.conflicts.map { |file| file[:ours][:path] } + + raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}" + end + + commit_params = { + message: commit_message, + parents: [@our_commit, @their_commit].map(&:oid) + } + + @repository.commit_index(user, source_branch, index, commit_params) + end + end + + def conflict_for_path(old_path, new_path) + conflicts.find do |conflict| + conflict.their_path == old_path && conflict.our_path == new_path + end + end + + private + + # We can only write when getting the merge index from the source + # project, because we will write to that project. We don't use this all + # the time because this fetches a ref into the source project, which + # isn't needed for reading. + def index + @index ||= @repository.rugged.merge_commits(@our_commit, @their_commit) + end + + def write_resolved_file_to_index(file, params) + if params[:sections] + resolved_lines = file.resolve_lines(params[:sections]) + new_file = resolved_lines.map { |line| line[:full_line] }.join("\n") + + new_file << "\n" if file.our_blob.data.ends_with?("\n") + elsif params[:content] + new_file = file.resolve_content(params[:content]) + end + + our_path = file.our_path + + index.add(path: our_path, oid: @repository.rugged.write(new_file, :blob), mode: file.our_mode) + index.conflict_remove(our_path) + end + end + end + end +end diff --git a/lib/gitlab/git/conflict_file.rb b/lib/gitlab/git/conflict_file.rb deleted file mode 100644 index 95a1a9bbe5b..00000000000 --- a/lib/gitlab/git/conflict_file.rb +++ /dev/null @@ -1,84 +0,0 @@ -module Gitlab - module Git - class ConflictFile - attr_reader :content, :their_path, :our_path, :our_mode, :repository - - def initialize(repository, commit_oid, conflict, content) - @repository = repository - @commit_oid = commit_oid - @their_path = conflict[:theirs][:path] - @our_path = conflict[:ours][:path] - @our_mode = conflict[:ours][:mode] - @content = content - end - - def lines - return @lines if defined?(@lines) - - begin - @type = 'text' - @lines = Gitlab::Git::ConflictParser.parse(content, - our_path: our_path, - their_path: their_path) - rescue Gitlab::Git::ConflictParser::ParserError - @type = 'text-editor' - @lines = nil - end - end - - def type - lines unless @type - - @type.inquiry - end - - def our_blob - # REFACTOR NOTE: the source of `commit_oid` used to be - # `merge_request.diff_refs.head_sha`. Instead of passing this value - # around the new lib structure, I decided to use `@commit_oid` which is - # equivalent to `merge_request.source_branch_head.raw.rugged_commit.oid`. - # That is what `merge_request.diff_refs.head_sha` is equivalent to when - # `merge_request` is not persisted (see `MergeRequest#diff_head_commit`). - # I think using the same oid is more consistent anyways, but if Conflicts - # start breaking, the change described above is a good place to look at. - @our_blob ||= repository.blob_at(@commit_oid, our_path) - end - - def line_code(line) - Gitlab::Git::DiffLineCode.generate(our_path, line[:line_new], line[:line_old]) - end - - def resolve_lines(resolution) - section_id = nil - - lines.map do |line| - unless line[:type] - section_id = nil - next line - end - - section_id ||= line_code(line) - - case resolution[section_id] - when 'head' - next unless line[:type] == 'new' - when 'origin' - next unless line[:type] == 'old' - else - raise Gitlab::Git::Merge::ResolutionError, "Missing resolution for section ID: #{section_id}" - end - - line - end.compact - end - - def resolve_content(resolution) - if resolution == content - raise Gitlab::Git::Merge::ResolutionError, "Resolved content has no changes for file #{our_path}" - end - - resolution - end - end - end -end diff --git a/lib/gitlab/git/conflict_parser.rb b/lib/gitlab/git/conflict_parser.rb deleted file mode 100644 index 90b03848aee..00000000000 --- a/lib/gitlab/git/conflict_parser.rb +++ /dev/null @@ -1,89 +0,0 @@ -module Gitlab - module Git - class ConflictParser - UnresolvableError = Class.new(StandardError) - UnmergeableFile = Class.new(UnresolvableError) - UnsupportedEncoding = Class.new(UnresolvableError) - - # Recoverable errors - the conflict can be resolved in an editor, but not with - # sections. - ParserError = Class.new(StandardError) - UnexpectedDelimiter = Class.new(ParserError) - MissingEndDelimiter = Class.new(ParserError) - - class << self - def parse(text, our_path:, their_path:, parent_file: nil) - validate_text!(text) - - line_obj_index = 0 - line_old = 1 - line_new = 1 - type = nil - lines = [] - conflict_start = "<<<<<<< #{our_path}" - conflict_middle = '=======' - conflict_end = ">>>>>>> #{their_path}" - - text.each_line.map do |line| - full_line = line.delete("\n") - - if full_line == conflict_start - validate_delimiter!(type.nil?) - - type = 'new' - elsif full_line == conflict_middle - validate_delimiter!(type == 'new') - - type = 'old' - elsif full_line == conflict_end - validate_delimiter!(type == 'old') - - type = nil - elsif line[0] == '\\' - type = 'nonewline' - lines << { - full_line: full_line, - type: type, - line_obj_index: line_obj_index, - line_old: line_old, - line_new: line_new - } - else - lines << { - full_line: full_line, - type: type, - line_obj_index: line_obj_index, - line_old: line_old, - line_new: line_new - } - - line_old += 1 if type != 'new' - line_new += 1 if type != 'old' - - line_obj_index += 1 - end - end - - raise MissingEndDelimiter unless type.nil? - - lines - end - - private - - def validate_text!(text) - raise UnmergeableFile if text.blank? # Typically a binary file - raise UnmergeableFile if text.length > 200.kilobytes - - text.force_encoding('UTF-8') - - raise UnsupportedEncoding unless text.valid_encoding? - end - - def validate_delimiter!(condition) - raise UnexpectedDelimiter unless condition - end - end - end - end -end diff --git a/lib/gitlab/git/diff_line_code.rb b/lib/gitlab/git/diff_line_code.rb deleted file mode 100644 index aab963ba928..00000000000 --- a/lib/gitlab/git/diff_line_code.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Gitlab - module Git - class DiffLineCode - def self.generate(file_path, new_line_position, old_line_position) - "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" - end - end - end -end diff --git a/lib/gitlab/git/merge.rb b/lib/gitlab/git/merge.rb deleted file mode 100644 index 3a0205c17f4..00000000000 --- a/lib/gitlab/git/merge.rb +++ /dev/null @@ -1,89 +0,0 @@ -module Gitlab - module Git - class Merge - ConflictSideMissing = Class.new(StandardError) - ResolutionError = Class.new(StandardError) - - def initialize(repository, our_commit, target_repository, their_commit) - @repository = repository - @our_commit = our_commit.rugged_commit - @target_repository = target_repository - @their_commit = their_commit.rugged_commit - end - - def conflicts - @conflicts ||= begin - target_index = @target_repository.rugged.merge_commits(@our_commit, @their_commit) - - # We don't need to do `with_repo_branch_commit` here, because the target - # project always fetches source refs when creating merge request diffs. - target_index.conflicts.map do |conflict| - raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours] - - Gitlab::Git::ConflictFile.new( - @target_repository, - @our_commit.oid, - conflict, - target_index.merge_file(conflict[:ours][:path])[:data] - ) - end - end - end - - def resolve_conflicts(user, files, source_branch:, target_branch:, commit_message:) - @repository.with_repo_branch_commit(@target_repository, target_branch) do - files.each do |file_params| - conflict_file = conflict_for_path(file_params[:old_path], file_params[:new_path]) - - write_resolved_file_to_index(conflict_file, file_params) - end - - unless index.conflicts.empty? - missing_files = index.conflicts.map { |file| file[:ours][:path] } - - raise ResolutionError, "Missing resolutions for the following files: #{missing_files.join(', ')}" - end - - commit_params = { - message: commit_message, - parents: [@our_commit, @their_commit].map(&:oid) - } - - @repository.commit_index(user, source_branch, index, commit_params) - end - end - - def conflict_for_path(old_path, new_path) - conflicts.find do |conflict| - conflict.their_path == old_path && conflict.our_path == new_path - end - end - - private - - # We can only write when getting the merge index from the source - # project, because we will write to that project. We don't use this all - # the time because this fetches a ref into the source project, which - # isn't needed for reading. - def index - @index ||= @repository.rugged.merge_commits(@our_commit, @their_commit) - end - - def write_resolved_file_to_index(file, params) - if params[:sections] - resolved_lines = file.resolve_lines(params[:sections]) - new_file = resolved_lines.map { |line| line[:full_line] }.join("\n") - - new_file << "\n" if file.our_blob.data.ends_with?("\n") - elsif params[:content] - new_file = file.resolve_content(params[:content]) - end - - our_path = file.our_path - - index.add(path: our_path, oid: @repository.rugged.write(new_file, :blob), mode: file.our_mode) - index.conflict_remove(our_path) - end - end - end -end diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb index 6490cd7002d..f8757507b78 100644 --- a/lib/gitlab/github_import/comment_formatter.rb +++ b/lib/gitlab/github_import/comment_formatter.rb @@ -38,7 +38,7 @@ module Gitlab end def generate_line_code(line) - Gitlab::Git::DiffLineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) end def on_diff? -- cgit v1.2.1 From 9fdde3693b3b49e929b7c80ccbec4abe412edb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Tue, 10 Oct 2017 14:44:14 -0300 Subject: Move line code generation into Gitlab::Git Having a distinct class just for that was a bit overkill --- lib/api/commits.rb | 2 +- lib/api/v3/commits.rb | 2 +- lib/github/representation/comment.rb | 2 +- lib/gitlab/bitbucket_import/importer.rb | 2 +- lib/gitlab/conflict/file.rb | 13 +------------ lib/gitlab/diff/file.rb | 2 +- lib/gitlab/git.rb | 4 ++++ lib/gitlab/git/conflict/file.rb | 6 +++--- lib/gitlab/git/conflict/line_code.rb | 11 ----------- lib/gitlab/github_import/comment_formatter.rb | 2 +- 10 files changed, 14 insertions(+), 32 deletions(-) delete mode 100644 lib/gitlab/git/conflict/line_code.rb (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 6ad97f2deb2..62565e2d522 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -186,7 +186,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git.diff_line_code(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb index cbb192d5dfc..bd5c6b34d12 100644 --- a/lib/api/v3/commits.rb +++ b/lib/api/v3/commits.rb @@ -173,7 +173,7 @@ module API lines.each do |line| next unless line.new_pos == params[:line] && line.type == params[:line_type] - break opts[:line_code] = Gitlab::Git::Conflict::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + break opts[:line_code] = Gitlab::Git.diff_line_code(diff.new_path, line.new_pos, line.old_pos) end break if opts[:line_code] diff --git a/lib/github/representation/comment.rb b/lib/github/representation/comment.rb index 0cb871630fd..83bf0b5310d 100644 --- a/lib/github/representation/comment.rb +++ b/lib/github/representation/comment.rb @@ -23,7 +23,7 @@ module Github private def generate_line_code(line) - Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git.diff_line_code(file_path, line.new_pos, line.old_pos) end def on_diff? diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index 38ba5b97ed0..033ecd15749 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -241,7 +241,7 @@ module Gitlab end def generate_line_code(pr_comment) - Gitlab::Git::Conflict::LineCode.generate(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) + Gitlab::Git.diff_line_code(pr_comment.file_path, pr_comment.new_pos, pr_comment.old_pos) end def pull_request_comment_attributes(comment) diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 3392388a45f..2a0cb640a14 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -110,7 +110,7 @@ module Gitlab end def line_code(line) - Gitlab::Git::Conflict::LineCode.generate(our_path, line.new_pos, line.old_pos) + Gitlab::Git.diff_line_code(our_path, line.new_pos, line.old_pos) end def create_match_line(line) @@ -174,17 +174,6 @@ module Gitlab new_path: our_path) end - # Don't try to print merge_request. - def inspect - instance_variables = [:content, :their_path, :our_path, :our_mode, :type].map do |instance_variable| - value = instance_variable_get("@#{instance_variable}") - - "#{instance_variable}=\"#{value}\"" - end - - "#<#{self.class} #{instance_variables.join(' ')}>" - end - private def map_raw_lines(raw_lines) diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 3f8d2041c29..ea5891a028a 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -49,7 +49,7 @@ module Gitlab def line_code(line) return if line.meta? - Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git.diff_line_code(file_path, line.new_pos, line.old_pos) end def line_for_line_code(code) diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index c78fe63f9b5..1f31cdbc96d 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -66,6 +66,10 @@ module Gitlab end end end + + def diff_line_code(file_path, new_line_position, old_line_position) + "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" + end end end end diff --git a/lib/gitlab/git/conflict/file.rb b/lib/gitlab/git/conflict/file.rb index b2bc653904d..fc1595f1faf 100644 --- a/lib/gitlab/git/conflict/file.rb +++ b/lib/gitlab/git/conflict/file.rb @@ -19,8 +19,8 @@ module Gitlab begin @type = 'text' @lines = Gitlab::Git::Conflict::Parser.parse(content, - our_path: our_path, - their_path: their_path) + our_path: our_path, + their_path: their_path) rescue Gitlab::Git::Conflict::Parser::ParserError @type = 'text-editor' @lines = nil @@ -46,7 +46,7 @@ module Gitlab end def line_code(line) - Gitlab::Git::Conflict::LineCode.generate(our_path, line[:line_new], line[:line_old]) + Gitlab::Git.diff_line_code(our_path, line[:line_new], line[:line_old]) end def resolve_lines(resolution) diff --git a/lib/gitlab/git/conflict/line_code.rb b/lib/gitlab/git/conflict/line_code.rb deleted file mode 100644 index bdbb4c9cb83..00000000000 --- a/lib/gitlab/git/conflict/line_code.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Gitlab - module Git - module Conflict - class LineCode - def self.generate(file_path, new_line_position, old_line_position) - "#{Digest::SHA1.hexdigest(file_path)}_#{old_line_position}_#{new_line_position}" - end - end - end - end -end diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb index f8757507b78..8911b81ec9a 100644 --- a/lib/gitlab/github_import/comment_formatter.rb +++ b/lib/gitlab/github_import/comment_formatter.rb @@ -38,7 +38,7 @@ module Gitlab end def generate_line_code(line) - Gitlab::Git::Conflict::LineCode.generate(file_path, line.new_pos, line.old_pos) + Gitlab::Git.diff_line_code(file_path, line.new_pos, line.old_pos) end def on_diff? -- cgit v1.2.1