diff options
Diffstat (limited to 'lib/patchwork.rb')
-rw-r--r-- | lib/patchwork.rb | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/lib/patchwork.rb b/lib/patchwork.rb index a005a40..383698f 100644 --- a/lib/patchwork.rb +++ b/lib/patchwork.rb @@ -16,6 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. #++ +require 'digest/sha1' require 'xmlrpc/client' module Patchwork @@ -24,6 +25,7 @@ module Patchwork config = GitoriousConfig["patchwork"][repository.project.slug] return unless config["repositories"].include? repository.name + git = repository.git.git server = XMLRPC::Client.new2(config["url"]) patchwork = XMLRPC::Client::Proxy.new(server, "", [], :call, "") @@ -38,12 +40,12 @@ module Patchwork events.each do |event| commit_id = event.commit_details[:id] - summary = event.commit_details[:message].split("\n")[0] + patch_hash = hash_patch(git.show(commit_id)) begin - patch_id = find_patch patchwork, project_id, summary, find_state_ids + patch_id = find_patch patchwork, project_id, patch_hash, find_state_ids if patch_id.nil? - logger.info "No matching patch for commit #{commit_id} found on Patchwork" + logger.info "No (single) matching patch for commit #{commit_id} found on Patchwork" next end update_patch patchwork, patch_id, commit_id, set_state_id @@ -64,9 +66,10 @@ module Patchwork entry['id'] end - def find_patch(patchwork, project_id, summary, find_state_ids) - patches = patchwork.patch_list "project_id"=>project_id, "name__icontains"=>summary - matches = patches.select { |entry| /^(\[.*\])? *(.*) *$/.match(entry['name'])[2] == summary && find_state_ids.include?(entry['state_id']) } + def find_patch(patchwork, project_id, hash, find_state_ids) + patches = patchwork.patch_list "project_id"=>project_id, "hash"=>hash + matches = patches.select { |entry| find_state_ids.include?(entry['state_id']) } + logger.info("Found multiple matches: #{matches}") if matches.size > 1 return nil if matches.size != 1 matches[0]['id'] end @@ -82,4 +85,52 @@ module Patchwork raise "Failed to update patch \##{patch_id} from commit #{commit_id}" end end + + _HUNK_PATTERN = /^\@\@ -\d+(?:,(\d+))? \+\d+(?:,(\d+))? \@\@/ + _FILENAME_PATTERN = /^(---|\+\+\+) (\S+)/ + def hash_patch(patch) + # logic taken from Patchwork + patch = patch.gsub(/\r/, '').strip! + "\n" + hash = Digest::SHA1.new + found_first_hunk = false + hunk_header = '' + + patch.split("\n").each do |line| + next if line.empty? + if filename_match = _FILENAME_PATTERN.match(line) + # normalise -p1 top-directories + filename = if filename_match[1] == '---' + 'a/' + else + 'b/' + end + filename += filename_match[2].split('/')[1..-1].join('/') + line = filename_match[1] + ' ' + filename + hunk_header += line + "\n" + + elsif hunk_match = _HUNK_PATTERN.match(line) + if !found_first_hunk + hash = Digest::SHA1.new.update(hunk_header) + found_first_hunk = true + end + # remove line numbers, but leave line counts + line_nos = hunk_match[1..-1].each { |x| x ? x.to_i : 1 } + line = '@@ -%d +%d @@' % line_nos + + elsif not found_first_hunk + hunk_header = '' + next + + elsif not line =~ /^[ +-]/ + # if we have a +, - or context line, leave as-is + # other lines are ignored + next + end + + hash.update(line + "\n") + end + + hash.hexdigest + end + end |