def main(): version = '0.0.1' program_name = 'gathergit' parser = argparse.ArgumentParser(prog=program_name, description='A description') # general args parser.add_argument('-V', action='version', version='%(prog)s {version}'.format(version=version)) parser.add_argument('--confdir', action='store', dest='confdir', help='directory to search for configuration files (default: config/)', default='config/') parser.add_argument('--all', action='store_true', dest='sync_all', help='Initialize, update and synchronize ALL repositories', default=False) parser_results = parser.parse_args() confdir = parser_results.confdir sync_all = parser_results.sync_all # config parsing cfg_parser = ConfigParser(confdir) config = cfg_parser.dump() # logging logconfig = config.get('settings', {}).get('logging', {}) logger = Helper().create_logger(program_name, logconfig) # let's start working now logger.debug('Starting new instance of %s', program_name) logger.debug('Raw configuration: %s', config) # collecting deployment configuration deployments = {} repolists = {} repoindex = Repoindex() for deployment_name, deployment_settings in config.get('deployments', {}).items(): repos = deployment_settings.get('repos') if repos is None: continue deployments[deployment_name] = {'target': deployment_settings.get('target'), 'defaults': deployment_settings.get('defaults', {})} if deployment_name not in repolists.keys(): repolists[deployment_name] = {} repolists[deployment_name].update(repos) # updating caches for deployment_name, repolist in Helper.sorted_dict(repolists).items(): for repoid, repo_settings in Helper.sorted_dict(repolist).items(): repo_name = repo_settings.get('name', repoid) repo_defaults = repo_settings.get('defaults', {}) branches = repo_settings.get('branches') if branches is None: logger.info('Skipping repo %s of deployment definition %s, is doesn\'t have any branches defined', repo_name, deployment_name) continue # adding repo to repoindex repo = Repo() repo['name'] = repo_name repo['defaults'] = repo_defaults repo['target'] = deployments[deployment_name].get('target') repo.add_branches(branches, deployments[deployment_name]) repoindex.add_repo(deployment_name, repoid, repo) cache_name = repoindex[deployment_name][repoid].get('defaults').get('cache') cache_settings = config.get('settings').get('caches').get(cache_name) cache = Cache(name=cache_name, settings=cache_settings) cache.init() updated_refs = cache.update(repoindex[deployment_name][repoid]) if updated_refs: repoindex[deployment_name][repoid]['updates'] = {'updated_refs': updated_refs, 'cache': cache} elif sync_all: repoindex[deployment_name][repoid]['updates'] = {'cache': cache} repoindex.sync_repos(sync_all) # Everything is done, closing now logger.debug('Shutting down..')
def main(): program_name = 'tabellarius' allowed_log_levels = ['DEBUG', 'ERROR', 'INFO'] if python_version[0] < 3: print('Your need to use Python 3 to run {0}! Your version: {1}'.format(program_name, python_version)) parser = ArgumentParser(prog=program_name, description='A mail-sorting tool that is less annoying') # General args parser.add_argument('-V', action='version', version='%(prog)s {version}'.format(version=__version__)) parser.add_argument('-t', '--test', action='store_true', dest='test', help='Run in test mode, run read-only IMAP commands only (WARNING: Bare Implementation!)', default=None) parser.add_argument('-l', '--loglevel', action='store', dest='log_level', help='Override log level setting ({0})'.format(', '.join(allowed_log_levels)), default='') parser.add_argument('--gpg-homedir', action='store', dest='gpg_homedir', help='Override gpg home dir setting (default: ~/.gnupg/)', default='~/.gnupg/') parser.add_argument('--sleep', action='store', dest='imap_sleep_time', help='Sleep time between IMAP parsing for e-mails (default: 2)', type=int, default=2) parser.add_argument('--confdir', action='store', dest='confdir', help='Directory to search for configuration files (default: config/)', default='config/', required=True) parser_results = parser.parse_args() confdir = parser_results.confdir test = parser_results.test log_level = parser_results.log_level.upper() if log_level and log_level not in allowed_log_levels: print('LOG_LEVEL {0} is not supported, supported log levels are: {1}'.format(log_level, ', '.join(allowed_log_levels))) exit(127) gpg_homedir = parser_results.gpg_homedir imap_sleep_time = parser_results.imap_sleep_time # Config Parsing cfg_parser = ConfigParser(confdir) config = cfg_parser.dump() if test is not None: config['settings']['test'] = test # Logging logconfig = config.get('settings', {}).get('logging', {}) if log_level: logconfig['root']['level'] = log_level logger = Helper().create_logger(program_name, logconfig) # Let's start working now logger.debug('Starting new instance of %s', program_name) logger.debug('Raw configuration: %s', config) # Setup gnupg if necessary for acc, acc_settings in config.get('accounts').items(): if 'password_enc' in acc_settings: import gnupg gpg_homedir = config.get('settings').get('gpg_homedir', gpg_homedir) gpg = gnupg.GPG(homedir=gpg_homedir, use_agent=config.get('settings').get('gpg_use_agent', False), binary=config.get('settings').get('gpg_binary', 'gpg2')) gpg.encoding = 'utf-8' # Initialize connection pools imap_pool = {} for acc_id, acc_settings in sorted(config.get('accounts').items()): # Check whether we got a plaintext password acc_password = acc_settings.get('password') if not acc_password: # Switch to GPG-encrypted password enc_password = None # Shall we use gpg-agent or use Python's getpass to retreive the plain text password if config.get('settings').get('gpg_use_agent', False): enc_password = gpg.decrypt(message=acc_settings.get('password_enc')) if not enc_password.ok: logger.error('%s: Failed to decrypt GPG message: %s', acc_settings.get('username'), enc_password.status) logger.debug('%s: GPG error: %s', acc_settings.get('username'), enc_password.stderr) exit(1) acc_password = str(enc_password) else: acc_password = getpass('Please enter the IMAP password for {0} ({1}): '.format(acc_id, acc_settings.get('username'))) logger.info('%s: Setting up IMAP connection', acc_settings.get('username')) imap_pool[acc_id] = IMAP(logger=logger, server=acc_settings.get('server'), port=acc_settings.get('port', 143), starttls=acc_settings.get('starttls', True), imaps=acc_settings.get('imaps', False), tlsverify=acc_settings.get('tlsverify', True), username=acc_settings.get('username'), password=acc_password, test=test) connect = imap_pool[acc_id].connect() if not connect.code: logger.error('%s: Failed to login, please check your account credentials: %s', acc_settings.get('username'), connect.data) exit(127) else: logger.info('%s: Sucessfully logged in!', acc_settings.get('username')) logger.info('Entering mail-sorting loop') while True: for acc_id, acc_settings in sorted(config.get('accounts').items()): pre_inbox = acc_settings.get('pre_inbox', 'PreInbox') pre_inbox_search = acc_settings.get('pre_inbox_search', 'ALL') sort_mailbox = acc_settings.get('sort_mailbox', None) try: if not imap_pool[acc_id].mailbox_exists(pre_inbox).data: imap_pool[acc_id].logger.info('%s: Destination mailbox %s doesn\'t exist, creating it for you', acc_settings.get('username'), pre_inbox) result = imap_pool[acc_id].create_mailbox(mailbox=pre_inbox) if not result.code: imap_pool[acc_id].logger.error('%s: Failed to create the mailbox %s: %s', acc_settings.get('username'), pre_inbox, result.data) return result mail_uids = imap_pool[acc_id].search_mails(mailbox=pre_inbox, criteria=pre_inbox_search, autocreate_mailbox=True).data if not mail_uids: logger.debug('%s: No mails found to sort', acc_settings.get('username')) continue mails = imap_pool[acc_id].fetch_mails(uids=mail_uids, mailbox=pre_inbox).data mails_without_match = [] for uid, mail in mails.items(): match = False if mail.get_header('message-id') is None: logger.error('Mail with uid={} and subject=\'{}\' doesn\'t have a message-id! Abort..'.format( uid, mail.get_header('subject'))) exit(1) for filter_name, filter_settings in Helper().sort_dict(config.get('filters').get(acc_id)).items(): mail_filter = MailFilter(logger=logger, imap=imap_pool[acc_id], mail=mail, config=filter_settings, mailbox=pre_inbox) match = mail_filter.check_rules_match() if match: break if match: continue if sort_mailbox: mails_without_match.append(uid) else: imap_pool[acc_id].set_mailflags(uids=[uid], mailbox=pre_inbox, flags=acc_settings.get('unmatched_mail_flags', ['\FLAGGED'])) if sort_mailbox and mails_without_match: logger.info('%s: Moving mails that did not match any filter to %s', acc_settings.get('username'), sort_mailbox) for uid in mails_without_match: mail = mails[uid] imap_pool[acc_id].move_mail(message_ids=[mail.get_header('message-id')], source=pre_inbox, destination=sort_mailbox, set_flags=[]) #except IMAPClient.Error as e: # logger.error('%s: Catching exception: %s. This is bad and I am sad. Going to sleep for a few seconds and trying again..', # acc_settings.get('username'), e) # sleep(10) except Exception as e: trace_info = exc_info() logger.error('%s: Catching unknown exception: %s. Showing stack trace and going to die..', acc_settings.get('username'), e) print_exception(*trace_info) del trace_info exit(1) logger.debug('All accounts checked, going to sleep for %s seconds before checking again..', imap_sleep_time) sleep(imap_sleep_time)