import poplib
import email.parser
import config
import logging
logger = logging.getLogger('pop3bot')

def mkmailbox(debug=0):
    username = config.username
    password = config.password

    mailbox = poplib.POP3_SSL('pop.googlemail.com', '995') 
    mailbox.set_debuglevel(debug)

    mailbox.user(username)
    mailbox.pass_(password)

    return mailbox

def mail_generator(mailbox):
    """ RETRieves the contents of mails, yields those
        and DELEtes them before the next mail is RETRieved """
    nmails, octets = mailbox.stat()
    for i in range(1,nmails+1):
        # use TOP rather than REPR; gmail (sometimes?) interprets REPR'd
        # messages as read and does not report them again (sigh)
        yield "\n".join(mailbox.top(i, 1000)[1])
        mailbox.dele(i)

def message_generator(mailbox):
    p = email.parser.Parser()
    for mail in mail_generator(mailbox):
        mail = p.parsestr(mail)
        # if mail is multipart-mime (probably not from gerrit)
        # mail.get_payload() is a list rather than a string
        # and mail.get_payload(decode=True) returns None

        m = mail
        while isinstance(m.get_payload(), list):
            m = m.get_payload()[0]

        yield mail, m.get_payload(decode=True)

def gerritmail_generator(mailbox):
    for message, contents in message_generator(mailbox):
        mi = dict(message.items())
        subject = mi.get('Subject', 'Unknown')
        sender = mi.get('From', 'Unknown')

        gerrit_data = dict((k,v) for (k,v) in message.items() if k.startswith('X-Gerrit'))
        gerrit_data.update(dict(line.split(": ", 1) for line in contents.split('\n') if (line.startswith("Gerrit-") and ": " in line)))

        print subject, sender, gerrit_data.get('X-Gerrit-Change-Id')

        if gerrit_data:
            yield gerrit_data
        else:
            print "Skipping; Contents: "
            print contents

import gerrit_rest
g = gerrit_rest.GerritREST('https://gerrit.wikimedia.org/r')

def get_changeset(changeid, o=['CURRENT_REVISION', 'CURRENT_FILES', 'DETAILED_ACCOUNTS']):
        matchingchanges = g.changes(changeid, n=1, o=o)
        if matchingchanges:
            return matchingchanges[0]
        else:
            return None

def new_changeset_generator(mailbox):
    for mail in gerritmail_generator(mailbox):
        mt = mail.get('X-Gerrit-MessageType', '')
        ps = mail.get('Gerrit-PatchSet', '')
        commit = mail['X-Gerrit-Commit']

        if mt != 'newchange':
            print "skipping message (%s)" % mt
            continue
        if ps != '1':
            print "skipping PS%s" % ps
            continue
        print "(getting ", commit, ")"
        matchingchange = get_changeset(commit)
        if matchingchange:
            yield matchingchange
        else:
            print "Could not find matching change for %s" % commit

def filter_reviewers(reviewers, owner_name, changeset_number):
    if owner_name.lower() == u'l10n-bot':
        logger.debug('Skipping l10n-bot')
        return

    i = 0
    for (reviewer, modulo) in reviewers:
        if reviewer.lower() == owner_name.lower():
            logger.debug('Skipping owner %r' % reviewer)
            continue

        if ((changeset_number + i) % modulo == 0):
            yield reviewer
        else:
            logger.debug('Skipping %r due to modulo')

from add_reviewer import ReviewerFactory, add_reviewers
RF = ReviewerFactory()

def get_reviewers_for_changeset(changeset):
    owner = changeset['owner']['name']

    changes = changeset['revisions'].values()[0]['files']
    changedfiles = [k for (k,v) in changes.items()]
    try:
        addedfiles = [k for (k,v) in changes.items() if 'status' in v and v['status'] == 'A']
    except Exception, e:
        print e, repr(changes.items())
        addedfiles = []

    project = changeset['project']
    number = changeset['_number']

    print ""
    print "Processing changeset ", changeset['change_id'], changeset['subject'], 'by', owner
    for f in changedfiles:
        if f in addedfiles:
            print "A",
        else:
            print "u",
        print f

    if changeset['status'] in [u'ABANDONED', u'MERGED']:
        print "Changeset was ", changeset['status'], "; not adding reviewers"
        return []

    reviewers = filter_reviewers(RF.reviewer_generator(project, changedfiles, addedfiles), owner, number)

    return reviewers

def main():
    mailbox = mkmailbox(0)
    nmails, octets = mailbox.stat()

    print "%i e-mails to process (%i kB)" % (nmails, octets/1024)

    try:
        for j,changeset in enumerate(new_changeset_generator(mailbox)):
            reviewers = get_reviewers_for_changeset(changeset)
            add_reviewers(changeset['id'], reviewers)
    finally:
        # flush succesfully processed emails
        mailbox.quit()

if __name__ == "__main__":
    main()

@@ -1,12 +1,23 @@
+import sys%0A
 import popli
@@ -67,16 +67,33 @@
 logging%0A
+import traceback%0A
 logger =
@@ -3540,24 +3540,37 @@
 '%5D%5B'name'%5D%0A%0A
+    try:%0A    
     changes 
@@ -3615,16 +3615,20 @@
 files'%5D%0A
+    
     chan
@@ -3671,25 +3671,16 @@
 tems()%5D%0A
-    try:%0A
         
@@ -3819,24 +3819,18 @@
 (changes
-.items()
+et
 )%0A      
@@ -3822,32 +3822,47 @@
 angeset)%0A       
+ changedfiles =
  addedfiles = %5B%5D
@@ -4678,16 +4678,37 @@
 lbox)):%0A
+            try:%0A    
         
@@ -4774,16 +4774,20 @@
         
+    
 add_revi
@@ -4820,16 +4820,261 @@
 iewers)%0A
+            except Exception as e:%0A                sys.stdout.write(repr(changeset) + %22%5Cn caused exception:%22)%0A                traceback.print_exc()%0A                sys.stderr.write(repr(changeset) + %22%5Cn caused exception:%22)%0A                raise%0A
     fina

Add more detailed logging on failure