# Path: patchwork/parser.py
# def hash_patch(str):
#     # normalise spaces
#     str = str.replace('\r', '')
#     str = str.strip() + '\n'
# 
#     prefixes = ['-', '+', ' ']
#     hash = hashlib.sha1()
# 
#     for line in str.split('\n'):
# 
#         if len(line) <= 0:
#             continue
# 
#         hunk_match = _hunk_re.match(line)
#         filename_match = _filename_re.match(line)
# 
#         if filename_match:
#             # normalise -p1 top-directories
#             if filename_match.group(1) == '---':
#                 filename = 'a/'
#             else:
#                 filename = 'b/'
#             filename += '/'.join(filename_match.group(2).split('/')[1:])
# 
#             line = filename_match.group(1) + ' ' + filename
# 
#         elif hunk_match:
#             # remove line numbers, but leave line counts
#             def fn(x):
#                 if not x:
#                     return 1
#                 return int(x)
#             line_nos = list(map(fn, hunk_match.groups()))
#             line = '@@ -%d +%d @@' % tuple(line_nos)
# 
#         elif line[0] in prefixes:
#             # if we have a +, - or context line, leave as-is
#             pass
# 
#         else:
#             # other lines are ignored
#             continue
# 
#         hash.update((line + '\n').encode('utf-8'))
# 
#     return hash
# 
# def extract_tags(content, tags):
#     counts = Counter()
# 
#     for tag in tags:
#         regex = re.compile(tag.pattern, re.MULTILINE | re.IGNORECASE)
#         counts[tag] = len(regex.findall(content))
# 
#     return counts


from collections import Counter, OrderedDict
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.six.moves import filter
from patchwork.fields import HashField
from patchwork.parser import hash_patch, extract_tags
import datetime
import jsonfield
import random
import re
import patchwork.threadlocalrequest as threadlocalrequest
import django.dispatch

    def answers(self):
        """Retrieves the answers (ie all comments but the commit message)"""
        return Comment.objects.filter(Q(patch=self) & ~Q(msgid=self.msgid))

    def comments(self):
        """Retrieves all comments of this patch ie. the commit message and the
           answers"""
        return Comment.objects.filter(patch=self)

    def series(self):
        try:
            rev = SeriesRevisionPatch.objects.filter(patch=self)[0].revision
            return rev.series
        except Exception:
            return None

    def _set_tag(self, tag, count):
        if count == 0:
            self.patchtag_set.filter(tag=tag).delete()
            return
        (patchtag, _) = PatchTag.objects.get_or_create(patch=self, tag=tag)
        if patchtag.count != count:
            patchtag.count = count
            patchtag.save()

    def refresh_tag_counts(self):
        tags = self.project.tags
        counter = Counter()
        for comment in self.comment_set.all():

# Path: patchwork/parser.py
# def hash_patch(str):
#     # normalise spaces
#     str = str.replace('\r', '')
#     str = str.strip() + '\n'
# 
#     prefixes = ['-', '+', ' ']
#     hash = hashlib.sha1()
# 
#     for line in str.split('\n'):
# 
#         if len(line) <= 0:
#             continue
# 
#         hunk_match = _hunk_re.match(line)
#         filename_match = _filename_re.match(line)
# 
#         if filename_match:
#             # normalise -p1 top-directories
#             if filename_match.group(1) == '---':
#                 filename = 'a/'
#             else:
#                 filename = 'b/'
#             filename += '/'.join(filename_match.group(2).split('/')[1:])
# 
#             line = filename_match.group(1) + ' ' + filename
# 
#         elif hunk_match:
#             # remove line numbers, but leave line counts
#             def fn(x):
#                 if not x:
#                     return 1
#                 return int(x)
#             line_nos = list(map(fn, hunk_match.groups()))
#             line = '@@ -%d +%d @@' % tuple(line_nos)
# 
#         elif line[0] in prefixes:
#             # if we have a +, - or context line, leave as-is
#             pass
# 
#         else:
#             # other lines are ignored
#             continue
# 
#         hash.update((line + '\n').encode('utf-8'))
# 
#     return hash
# 
# def extract_tags(content, tags):
#     counts = Counter()
# 
#     for tag in tags:
#         regex = re.compile(tag.pattern, re.MULTILINE | re.IGNORECASE)
#         counts[tag] = len(regex.findall(content))
# 
#     return counts


# Path: patchwork/models.py
from collections import Counter, OrderedDict
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.six.moves import filter
from patchwork.fields import HashField
from patchwork.parser import hash_patch, extract_tags
import datetime
import jsonfield
import random
import re
import patchwork.threadlocalrequest as threadlocalrequest
import django.dispatch


    def answers(self):
        """Retrieves the answers (ie all comments but the commit message)"""
        return Comment.objects.filter(Q(patch=self) & ~Q(msgid=self.msgid))

    def comments(self):
        """Retrieves all comments of this patch ie. the commit message and the
           answers"""
        return Comment.objects.filter(patch=self)

    def series(self):
        try:
            rev = SeriesRevisionPatch.objects.filter(patch=self)[0].revision
            return rev.series
        except Exception:
            return None

    def _set_tag(self, tag, count):
        if count == 0:
            self.patchtag_set.filter(tag=tag).delete()
            return
        (patchtag, _) = PatchTag.objects.get_or_create(patch=self, tag=tag)
        if patchtag.count != count:
            patchtag.count = count
            patchtag.save()

    def refresh_tag_counts(self):
        tags = self.project.tags
        counter = Counter()
        for comment in self.comment_set.all():

            counter = counter + extract_tags(comment.content, tags)