From 1e945c24f59d3e92ef18f456b60aa10210a3113c Mon Sep 17 00:00:00 2001 From: Ansgar Burchardt Date: Mon, 13 Aug 2012 14:24:34 +0200 Subject: [PATCH] rewrite code for sending mails about processed uploads --- dak/process_policy.py | 97 +++++++++----------------- dak/process_upload.py | 120 +++++++------------------------- daklib/announce.py | 154 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 163 deletions(-) create mode 100644 daklib/announce.py diff --git a/dak/process_policy.py b/dak/process_policy.py index 5992cdd5..61c4ef39 100755 --- a/dak/process_policy.py +++ b/dak/process_policy.py @@ -45,7 +45,8 @@ from daklib.dak_exceptions import CantOpenError, AlreadyLockedError, CantGetLock from daklib.config import Config from daklib.archive import ArchiveTransaction from daklib.urgencylog import UrgencyLog -from daklib.textutils import fix_maintainer + +import daklib.announce # Globals Options = None @@ -155,25 +156,8 @@ def comment_accept(upload, srcqueue, comments, transaction): if not Options['No-Action']: Logger.log(["Policy Queue ACCEPT", srcqueue.queue_name, changesname]) - # Send announcement - if upload.source is not None: - subst = subst_for_upload(upload) - announce = ", ".join(upload.target_suite.announce or []) - tracking = cnf.get('Dinstall::TrackingServer') - if tracking and upload.source is not None: - announce = '{0}\nBcc: {1}@{2}'.format(announce, upload.changes.source, tracking) - subst['__ANNOUNCE_LIST_ADDRESS__'] = announce - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.announce')) - utils.send_mail(message) - - # TODO: code duplication. Similar code is in process-upload. - if cnf.find_b('Dinstall::CloseBugs') and upload.changes.closes is not None and upload.source is not None: - for bugnum in upload.changes.closes: - subst['__BUG_NUMBER__'] = bugnum - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.bug-close')) - utils.send_mail(message) - - del subst['__BUG_NUMBER__'] + pu = get_processed_upload(upload) + daklib.announce.announce_accept(upload) # TODO: code duplication. Similar code is in process-upload. # Move .changes to done @@ -190,9 +174,9 @@ def comment_accept(upload, srcqueue, comments, transaction): @try_or_reject def comment_reject(*args): - real_comment_reject(*args) + real_comment_reject(*args, manual=True) -def real_comment_reject(upload, srcqueue, comments, transaction, notify=True): +def real_comment_reject(upload, srcqueue, comments, transaction, notify=True, manual=False): cnf = Config() fs = transaction.fs @@ -231,19 +215,18 @@ def real_comment_reject(upload, srcqueue, comments, transaction, notify=True): ### Send mail notification if notify: - subst = subst_for_upload(upload) - subst['__MANUAL_REJECT_MESSAGE__'] = '' - subst['__REJECT_MESSAGE__'] = comments + rejected_by = None + reason = comments # Try to use From: from comment file if there is one. # This is not very elegant... match = re.match(r"\AFrom: ([^\n]+)\n\n", comments) if match: - subst['__REJECTOR_ADDRESS__'] = match.group(1) - subst['__REJECT_MESSAGE__'] = '\n'.join(comments.splitlines()[2:]) + rejected_by = match.group(1) + reason = '\n'.join(comments.splitlines()[2:]) - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'queue.rejected')) - utils.send_mail(message) + pu = get_processed_upload(upload) + daklib.announce.announce_reject(pu, reason, rejected_by) print " REJECT" if not Options["No-Action"]: @@ -274,46 +257,28 @@ def remove_upload(upload, transaction): ################################################################################ -def subst_for_upload(upload): - # TODO: similar code in process-upload - cnf = Config() +def get_processed_upload(upload): + pu = daklib.announce.ProcessedUpload() - maintainer_field = upload.changes.changedby or upload.changes.maintainer - if upload.source is not None: - addresses = utils.mail_addresses_for_upload(upload.changes.maintainer, maintainer_field, upload.changes.fingerprint) - else: - addresses = utils.mail_addresses_for_upload(upload.changes.maintainer, upload.changes.maintainer, upload.changes.fingerprint) + pu.maintainer = upload.changes.maintainer + pu.changed_by = upload.changes.changedby + pu.fingerprint = upload.changes.fingerprint + + pu.suites = [] + pu.from_policy_suites = [ upload.target_suite ] changes_path = os.path.join(upload.policy_queue.path, upload.changes.changesname) - changes_contents = open(changes_path, 'r').read() - - bcc = 'X-DAK: dak process-policy' - if 'Dinstall::Bcc' in cnf: - bcc = '{0}\nBcc: {1}'.format(bcc, cnf['Dinstall::Bcc']) - - subst = { - '__DISTRO__': cnf['Dinstall::MyDistribution'], - '__ADMIN_ADDRESS__': cnf['Dinstall::MyAdminAddress'], - - '__CHANGES_FILENAME__': upload.changes.changesname, - '__SOURCE__': upload.changes.source, - '__VERSION__': upload.changes.version, - '__ARCHITECTURE__': upload.changes.architecture, - '__MAINTAINER__': maintainer_field, - '__MAINTAINER_FROM__': fix_maintainer(maintainer_field)[1], - '__MAINTAINER_TO__': ", ".join(addresses), - '__CC__': 'X-DAK-Rejection: manual or automatic', - '__REJECTOR_ADDRESS__': cnf['Dinstall::MyEmailAddress'], - '__BCC__': bcc, - '__BUG_SERVER__': cnf.get('Dinstall::BugServer'), - '__FILE_CONTENTS__': changes_contents, - } - - override_maintainer = cnf.get('Dinstall::OverrideMaintainer') - if override_maintainer: - subst['__MAINTAINER_TO__'] = override_maintainer - - return subst + pu.changes = open(changes_path, 'r').read() + pu.changes_filename = upload.changes.changesname + pu.sourceful = upload.source is not None + pu.source = upload.changes.source + pu.version = upload.changes.version + pu.architecture = upload.changes.architecture + pu.bugs = upload.changes.closes + + pu.program = "process-policy" + + return pu ################################################################################ diff --git a/dak/process_upload.py b/dak/process_upload.py index 1dbde576..bf5cda59 100755 --- a/dak/process_upload.py +++ b/dak/process_upload.py @@ -176,9 +176,9 @@ from daklib.urgencylog import UrgencyLog from daklib.summarystats import SummaryStats from daklib.config import Config import daklib.utils as utils -from daklib.textutils import fix_maintainer from daklib.regexes import * +import daklib.announce import daklib.archive import daklib.checks import daklib.upload @@ -228,64 +228,30 @@ def try_or_reject(function): return wrapper -def subst_for_upload(upload): - cnf = Config() - +def get_processed_upload(upload): changes = upload.changes control = upload.changes.changes - if upload.final_suites is None or len(upload.final_suites) == 0: - suite_name = '(unknown)' - else: - suite_names = [] - for suite in upload.final_suites: - if suite.policy_queue: - suite_names.append("{0}->{1}".format(suite.suite_name, suite.policy_queue.queue_name)) - else: - suite_names.append(suite.suite_name) - suite_name = ','.join(suite_names) - - maintainer_field = control.get('Maintainer', cnf['Dinstall::MyEmailAddress']) - changed_by_field = control.get('Changed-By', maintainer_field) - maintainer = fix_maintainer(changed_by_field) - if upload.changes.source is not None: - addresses = utils.mail_addresses_for_upload(maintainer_field, changed_by_field, changes.primary_fingerprint) - else: - addresses = utils.mail_addresses_for_upload(maintainer_field, maintainer_field, changes.primary_fingerprint) - - # debian-{devel-,}-changes@lists.debian.org toggles writes access based on this header - bcc = 'X-DAK: dak process-upload' - if 'Dinstall::Bcc' in cnf: - bcc = '{0}\nBcc: {1}'.format(bcc, cnf['Dinstall::Bcc']) - - subst = { - '__DISTRO__': cnf['Dinstall::MyDistribution'], - '__ADMIN_ADDRESS__': cnf['Dinstall::MyAdminAddress'], - - '__CHANGES_FILENAME__': upload.changes.filename, - - '__SOURCE__': control.get('Source', '(unknown)'), - '__ARCHITECTURE__': control.get('Architecture', '(unknown)'), - '__VERSION__': control.get('Version', '(unknown)'), + pu = daklib.announce.ProcessedUpload() - '__SUITE__': suite_name, + pu.maintainer = control.get('Maintainer') + pu.changed_by = control.get('Changed-By') + pu.fingerprint = changes.primary_fingerprint - '__DAK_ADDRESS__': cnf['Dinstall::MyEmailAddress'], - '__MAINTAINER_FROM__': maintainer[1], - '__MAINTAINER_TO__': ", ".join(addresses), - '__MAINTAINER__': changed_by_field, - '__BCC__': bcc, + pu.suites = upload.final_suites or [] + pu.from_policy_suites = [] - '__BUG_SERVER__': cnf.get('Dinstall::BugServer'), + pu.changes = open(upload.changes.path, 'r').read() + pu.changes_filename = upload.changes.filename + pu.sourceful = upload.changes.source is not None + pu.source = control.get('Source') + pu.version = control.get('Version') + pu.architecture = control.get('Architecture') + pu.bugs = changes.closed_bugs - '__FILE_CONTENTS__': open(upload.changes.path, 'r').read(), - } + pu.program = "process-upload" - override_maintainer = cnf.get('Dinstall::OverrideMaintainer') - if override_maintainer: - subst['__MAINTAINER_TO__'] = subst['__MAINTAINER_FROM__'] = override_maintainer - - return subst + return pu @try_or_reject def accept(directory, upload): @@ -308,41 +274,8 @@ def accept(directory, upload): urgency = cnf['Urgency::Default'] UrgencyLog().log(control['Source'], control['Version'], urgency) - # send mail to maintainer - subst = subst_for_upload(upload) - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.accepted')) - utils.send_mail(message) - - # send mail to announce lists and tracking server - if accepted_to_real_suite and sourceful_upload: - subst = subst_for_upload(upload) - announce = set() - for suite in upload.final_suites: - if suite.policy_queue is not None: - continue - announce.update(suite.announce or []) - announce_address = ", ".join(announce) - - tracking = cnf.get('Dinstall::TrackingServer') - if tracking and 'source' in upload.changes.architectures: - announce_address = '{0}\nBcc: {1}@{2}'.format(announce_address, control['Source'], tracking) - - subst['__ANNOUNCE_LIST_ADDRESS__'] = announce_address - - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.announce')) - utils.send_mail(message) - - # Only close bugs for uploads that were not redirected to a policy queue. - # process-policy will close bugs for those once they are accepted. - subst = subst_for_upload(upload) - if accepted_to_real_suite and cnf.find_b('Dinstall::CloseBugs') and sourceful_upload: - for bugnum in upload.changes.closed_bugs: - subst['__BUG_NUMBER__'] = str(bugnum) - - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.bug-close')) - utils.send_mail(message) - - del subst['__BUG_NUMBER__'] + pu = get_processed_upload(upload) + daklib.announce.announce_accept(pu) # Move .changes to done, but only for uploads that were accepted to a # real suite. process-policy will handle this for uploads to queues. @@ -368,9 +301,8 @@ def accept_to_new(directory, upload): upload.install_to_new() # TODO: tag bugs pending - subst = subst_for_upload(upload) - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.new')) - utils.send_mail(message) + pu = get_processed_upload(upload) + daklib.announce.announce_new(pu) SummaryStats().accept_count += 1 SummaryStats().accept_bytes += upload.changes.bytes @@ -412,14 +344,8 @@ def real_reject(directory, upload, reason=None, notify=True): fh.close() if notify: - subst = subst_for_upload(upload) - subst['__REJECTOR_ADDRESS__'] = cnf['Dinstall::MyEmailAddress'] - subst['__MANUAL_REJECT_MESSAGE__'] = '' - subst['__REJECT_MESSAGE__'] = reason - subst['__CC__'] = 'X-DAK-Rejection: automatic (moo)' - - message = utils.TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'queue.rejected')) - utils.send_mail(message) + pu = get_processed_upload(upload) + daklib.announce.announce_reject(pu, reason) SummaryStats().reject_count += 1 diff --git a/daklib/announce.py b/daklib/announce.py new file mode 100644 index 00000000..8288af9d --- /dev/null +++ b/daklib/announce.py @@ -0,0 +1,154 @@ +"""module to send announcements for processed packages + +@contact: Debian FTP Master +@copyright: 2012, Ansgar Burchardt +@license: GPL-2+ +""" + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os + +from daklib.config import Config +from daklib.textutils import fix_maintainer +from daklib.utils import mail_addresses_for_upload, TemplateSubst, send_mail + +class ProcessedUpload(object): + # people + maintainer = None + changed_by = None + fingerprint = None + + # suites + suites = [] + from_policy_suites = [] + + # package + changes = None + changes_filename = None + sourceful = None + source = None + architecture = None + version = None + bugs = None + + # program + program = "unknown-program" + +def _subst_for_upload(upload): + cnf = Config() + + maintainer = upload.maintainer or cnf['Dinstall::MyEmailAddress'] + changed_by = upload.changed_by or maintainer + if upload.sourceful: + maintainer_to = mail_addresses_for_upload(maintainer, changed_by, upload.fingerprint) + else: + maintainer_to = mail_addresses_for_upload(maintainer, maintainer, upload.fingerprint) + + bcc = 'X-DAK: dak {0}'.format(upload.program) + if 'Dinstall::Bcc' in cnf: + bcc = '{0}\nBcc: {1}'.format(bcc, cnf['Dinstall::Bcc']) + + subst = { + '__DISTRO__': cnf['Dinstall::MyDistribution'], + '__BUG_SERVER__': cnf.get('Dinstall::BugServer'), + '__ADMIN_ADDRESS__': cnf['Dinstall::MyAdminAddress'], + '__DAK_ADDRESS__': cnf['Dinstall::MyEmailAddress'], + '__REJECTOR_ADDRESS__': cnf['Dinstall::MyEmailAddress'], + '__MANUAL_REJECT_MESSAGE__': '', + + '__BCC__': bcc, + + '__MAINTAINER__': changed_by, + '__MAINTAINER_FROM__': fix_maintainer(changed_by)[1], + '__MAINTAINER_TO__': ', '.join(maintainer_to), + '__CHANGES_FILENAME__': upload.changes_filename, + '__FILE_CONTENTS__': upload.changes, + '__SOURCE__': upload.source, + '__VERSION__': upload.version, + '__ARCHITECTURE__': upload.architecture, + } + + override_maintainer = cnf.get('Dinstall::OverrideMaintainer') + if override_maintainer: + subst['__MAINTAINER_FROM__'] = subst['__MAINTAINER_TO__'] = override_maintainer + + return subst + +def announce_reject(upload, reason, rejected_by=None): + cnf = Config() + subst = _subst_for_upload(upload) + + automatic = rejected_by is None + + subst['__CC__'] = 'X-DAK-Rejection: {0}'.format('automatic' if automatic else 'manual') + subst['__REJECT_MESSAGE__'] = reason + + if rejected_by: + subst['__REJECTOR_ADDRESS__'] = rejected_by + + if not automatic: + subst['__BCC__'] = '{0}\nBcc: {1}'.format(subst['__BCC__'], cnf['Dinstall::MyEmailAddress']) + + message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'queue.rejected')) + send_mail(message) + +def announce_accept(upload): + cnf = Config() + subst = _subst_for_upload(upload) + + accepted_to_real_suite = any(suite.policy_queue in None for suite in upload.suites) + + suite_names = [] + for suite in upload.suites: + if suite.policy_queue: + suite_names.append("{0}->{1}".format(suite.suite_name, suite.policy_queue.queue_name)) + else: + suite_names.append(suite.suite_name) + suite_names.extend(suite.suite_name for suite in upload.from_policy_suites) + subst['__SUITE__'] = ', '.join(suite_names) or '(none)' + + message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.accepted')) + send_mail(message) + + if accepted_to_real_suite and upload.sourceful: + # senf mail to announce lists and tracking server + announce = set(suite.announce or [] for suite in upload.suites if suite.policy_queue is None) + announce_list_address = ", ".join(announce) + + tracking = cnf.get('Dinstall::TrackingServer') + if tracking: + announce_list_address = "{0}\n{1}@{2}".format(announce_list_address, upload.source, tracking) + + my_subst = subst.copy() + my_subst['__ANNOUNCE_LIST_ADDRESS__'] = announce_list_address + + message = TemplateSubst(my_subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.announce')) + utils.send_mail(message) + + if accepted_to_real_suite and upload.sourceful and cnf.find_b('Dinstall::CloseBugs'): + for bug in upload.bugs: + my_subst = subst.copy() + my_subst['__BUG_NUMBER__'] = str(bug) + + message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.bug-close')) + send_mail(message) + +def announce_new(upload): + cnf = Config() + subst = _subst_for_upload(upload) + + message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.new')) + send_mail(message) -- 2.39.5