Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/patchwork.rb63
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