#!/usr/bin/python from bin import django_setup, add_logging_arguments import email import logging import imaplib django_setup() # must be called to get sys.path and django settings in place from django.db import IntegrityError from django.conf import settings from django.utils.module_loading import import_string from patchwork import parser from patchwork.models import Patch, State import patch_matcher log = logging.getLogger('import_emails') def find_old_revisions(patch): log.debug('looking for old versions of patch %d', patch.id) it = patch_matcher.get_patches_matching( patch.project, [patch.submitter], patch.name, patch.diff) for p in it: # skip ourself if p.id != patch.id: yield p def process_message(msg): msg = email.message_from_string(msg) log.info('subject: %s', msg.get('Subject')) p = None try: p = parser.parse_mail(msg) except IntegrityError as e: log.info(e) if p: log.info('saved mail: %d', p.id) for patch in Patch.objects.filter(msgid=p.msgid): for old in find_old_revisions(patch): log.info('marking patch %d as superseded by %d', old.id, patch.id) old.state = State.objects.get(name='Superseded') old.save() return p def move_message(mail, uid, folder): # put in proper folder and move out of inbox status, _ = mail.uid('copy', uid, folder) assert status == 'OK' status, _ = mail.uid('store', uid, '+FLAGS', r'(\Deleted)') assert status == 'OK' def process_inbox(mail, max_messages=0): status, _ = mail.select('inbox') assert status == 'OK' status, uids = mail.uid('search', None, 'ALL') assert status == 'OK' uids = uids[0].split() if max_messages > 0: uids = uids[:max_messages] log.info('processing %d messages', len(uids)) added = processed = 0 for uid in uids: try: log.info('processing message: %s', uid) status, data = mail.uid('fetch', uid, '(RFC822)') assert status == 'OK' if process_message(data[0][1]): added += 1 move_message(mail, uid, 'processed') processed += 1 except Exception: log.exception('Unknown error for %s, moving to retry folder', uid) move_message(mail, uid, 'retry') break log.info('processed %d messages, added %d', processed, added) def get_monkey_patcher(): p = getattr(settings, 'PARSEMAIL_MONKEY_PATCHER', None) if p: return import_string(p) if __name__ == '__main__': import argparse arg_parser = argparse.ArgumentParser( description='Check configured inbox for new patches to import') arg_parser.add_argument('--num-emails', type=int, default=80, help='''Maximum number of emails to analyze. default=%(default)d''') add_logging_arguments(arg_parser) args = arg_parser.parse_args() parser.logger = log mail = imaplib.IMAP4_SSL(settings.IMAP_SERVER) status, _ = mail.login(settings.IMAP_USER, settings.IMAP_PASS) assert status == 'OK' monkey_patcher = get_monkey_patcher() if monkey_patcher: with monkey_patcher(parser): process_inbox(mail, args.num_emails) else: process_inbox(mail, args.num_emails)