# Path: pypasta/MAINTAINERS.py
# def load_maintainers(config, versions):
#     def __load_maintainers(ret, config, versions):
#         if ret is None:
#             ret = dict()
# 
#         # Only load what's not yet cached
#         versions -= ret.keys()
# 
#         if len(versions) == 0:
#             return ret, False
# 
#         global _repo
#         _repo = config.repo
#         p = Pool(processes=cpu_count())
#         function = partial(_load_maintainer,
#                            d_cluster = config.d_maintainers_cluster,
#                            project_name = config.project_name)
# 
#         for tag, maintainers in tqdm(p.imap_unordered(function, versions),
#                                      total=len(versions), desc='MAINTAINERS'):
#             ret[tag] = maintainers
# 
#         p.close()
#         p.join()
#         _repo = None
# 
#         return ret, True
# 
#     log.info('Loading/Updating MAINTAINERS...')
#     maintainers_version = load_pkl_and_update(config.f_maintainers_pkl,
#                                               __load_maintainers, config,
#                                               versions)
#     return maintainers_version
# 
# Path: pypasta/Util.py
# def get_first_upstream(repo, cluster, commit):
#     upstream = cluster.get_upstream(commit)
#     if not upstream:
#         return None
#     return min(upstream, key=lambda x: repo[x].committer.date)
# 
# def load_pkl_and_update(filename, update_command, *params):
#     ret = None
#     if os.path.isfile(filename):
#         ret = pickle.load(open(filename, 'rb'))
# 
#     if len(params) == 0:
#         ret, changed = update_command(ret)
#     else:
#         ret, changed = update_command(ret, *params)
# 
#     if changed:
#         pickle.dump(ret, open(filename, 'wb'))
# 
#     return ret
# 
# def mail_parse_date(date_str, assume_epoch=False):
#     try:
#         date = email.utils.parsedate_to_datetime(date_str)
#     except Exception:
#         date = None
# 
#     if not date:
#         try:
#             date = dateparser.parse(date_str)
#         except Exception:
#             date = None
# 
#     if not date:
#         date = datetime.datetime.utcfromtimestamp(0)
# 
#     if date.tzinfo is None:
#         date = date.replace(tzinfo=datetime.timezone.utc)
# 
#     return date


import csv
import email
import re
from anytree import LevelOrderIter
from enum import Enum
from logging import getLogger
from multiprocessing import Pool, cpu_count
from .MAINTAINERS import load_maintainers
from .Util import get_first_upstream, load_pkl_and_update, mail_parse_date
    from .BuildrootMailCharacteristics import BuildrootMailCharacteristics
    from .DPDKMailCharacteristics import DPDKMailCharacteristics
    from .GitMailCharacteristics import GitMailCharacteristics
    from .JailhouseMailCharacteristics import JailhouseMailCharacteristics
    from .LinuxMailCharacteristics import LinuxMailCharacteristics
    from .OpenembeddedMailCharacteristics import OpenembeddedMailCharacteristics
    from .QemuMailCharacteristics import QemuMailCharacteristics
    from .UBootMailCharacteristics import UBootMailCharacteristics
    from .XenMailCharacteristics import XenMailCharacteristics
        self._analyse_series()

        # By default, assume type 'other'
        self.type = PatchType.OTHER

        self.is_from_bot = self._is_from_bot()

        if self.is_patch:
            self.patch = repo[message_id]
            # We must only analyse foreign responses of patches if the patch is
            # the first patch in a thread. Otherwise, we might not be able to
            # determine the original author of a thread. Reason: That mail
            # might be missing.
            if self.is_first_patch_in_thread:
                self.has_foreign_response = self._has_foreign_response(repo)
            elif self.type == PatchType.OTHER:
                self.type = PatchType.NOT_FIRST

            self.process_mail = True in [process in self.subject for process
                                         in self.PROCESSES]
            if self.process_mail:
                self.type = PatchType.PROCESS

            self.patches_project = self._patches_project()
            if not self.patches_project:
                self.type = PatchType.NOT_PROJECT
            # Even if the patch does not patch Linux, we can assign it to a
            # appropriate version
            self.version = repo.patch_get_version(self.patch)


# Path: pypasta/MAINTAINERS.py
# def load_maintainers(config, versions):
#     def __load_maintainers(ret, config, versions):
#         if ret is None:
#             ret = dict()
# 
#         # Only load what's not yet cached
#         versions -= ret.keys()
# 
#         if len(versions) == 0:
#             return ret, False
# 
#         global _repo
#         _repo = config.repo
#         p = Pool(processes=cpu_count())
#         function = partial(_load_maintainer,
#                            d_cluster = config.d_maintainers_cluster,
#                            project_name = config.project_name)
# 
#         for tag, maintainers in tqdm(p.imap_unordered(function, versions),
#                                      total=len(versions), desc='MAINTAINERS'):
#             ret[tag] = maintainers
# 
#         p.close()
#         p.join()
#         _repo = None
# 
#         return ret, True
# 
#     log.info('Loading/Updating MAINTAINERS...')
#     maintainers_version = load_pkl_and_update(config.f_maintainers_pkl,
#                                               __load_maintainers, config,
#                                               versions)
#     return maintainers_version
# 
# Path: pypasta/Util.py
# def get_first_upstream(repo, cluster, commit):
#     upstream = cluster.get_upstream(commit)
#     if not upstream:
#         return None
#     return min(upstream, key=lambda x: repo[x].committer.date)
# 
# def load_pkl_and_update(filename, update_command, *params):
#     ret = None
#     if os.path.isfile(filename):
#         ret = pickle.load(open(filename, 'rb'))
# 
#     if len(params) == 0:
#         ret, changed = update_command(ret)
#     else:
#         ret, changed = update_command(ret, *params)
# 
#     if changed:
#         pickle.dump(ret, open(filename, 'wb'))
# 
#     return ret
# 
# def mail_parse_date(date_str, assume_epoch=False):
#     try:
#         date = email.utils.parsedate_to_datetime(date_str)
#     except Exception:
#         date = None
# 
#     if not date:
#         try:
#             date = dateparser.parse(date_str)
#         except Exception:
#             date = None
# 
#     if not date:
#         date = datetime.datetime.utcfromtimestamp(0)
# 
#     if date.tzinfo is None:
#         date = date.replace(tzinfo=datetime.timezone.utc)
# 
#     return date


# Path: pypasta/MailCharacteristics.py
import csv
import email
import re
from anytree import LevelOrderIter
from enum import Enum
from logging import getLogger
from multiprocessing import Pool, cpu_count
from .MAINTAINERS import load_maintainers
from .Util import get_first_upstream, load_pkl_and_update, mail_parse_date
    from .BuildrootMailCharacteristics import BuildrootMailCharacteristics
    from .DPDKMailCharacteristics import DPDKMailCharacteristics
    from .GitMailCharacteristics import GitMailCharacteristics
    from .JailhouseMailCharacteristics import JailhouseMailCharacteristics
    from .LinuxMailCharacteristics import LinuxMailCharacteristics
    from .OpenembeddedMailCharacteristics import OpenembeddedMailCharacteristics
    from .QemuMailCharacteristics import QemuMailCharacteristics
    from .UBootMailCharacteristics import UBootMailCharacteristics
    from .XenMailCharacteristics import XenMailCharacteristics

        self._analyse_series()

        # By default, assume type 'other'
        self.type = PatchType.OTHER

        self.is_from_bot = self._is_from_bot()

        if self.is_patch:
            self.patch = repo[message_id]
            # We must only analyse foreign responses of patches if the patch is
            # the first patch in a thread. Otherwise, we might not be able to
            # determine the original author of a thread. Reason: That mail
            # might be missing.
            if self.is_first_patch_in_thread:
                self.has_foreign_response = self._has_foreign_response(repo)
            elif self.type == PatchType.OTHER:
                self.type = PatchType.NOT_FIRST

            self.process_mail = True in [process in self.subject for process
                                         in self.PROCESSES]
            if self.process_mail:
                self.type = PatchType.PROCESS

            self.patches_project = self._patches_project()
            if not self.patches_project:
                self.type = PatchType.NOT_PROJECT
            # Even if the patch does not patch Linux, we can assign it to a
            # appropriate version
            self.version = repo.patch_get_version(self.patch)


            self.first_upstream = get_first_upstream(repo, clustering,