announce.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. """module to send announcements for processed packages
  2. @contact: Debian FTP Master <ftpmaster@debian.org>
  3. @copyright: 2012, Ansgar Burchardt <ansgar@debian.org>
  4. @license: GPL-2+
  5. """
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License along
  17. # with this program; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. import os
  20. from daklib.config import Config
  21. from daklib.textutils import fix_maintainer
  22. from daklib.utils import mail_addresses_for_upload, TemplateSubst, send_mail
  23. class ProcessedUpload(object):
  24. """Contains data of a processed upload.
  25. """
  26. # people
  27. maintainer = None #: Maintainer: field contents
  28. changed_by = None #: Changed-By: field contents
  29. fingerprint = None #: Fingerprint of upload signer
  30. # suites
  31. suites = [] #: Destination suites
  32. from_policy_suites = [] #: Policy suites
  33. # package
  34. changes = None #: Contents of .changes file from upload
  35. changes_filename = None #: Changes Filename
  36. sourceful = None #: Did upload contain source
  37. source = None #: Source value from changes
  38. architecture = None #: Architectures from changes
  39. version = None #: Version from changes
  40. bugs = None #: Bugs closed in upload
  41. # program
  42. program = "unknown-program" #: Which dak program was in use
  43. warnings = [] #: Eventual warnings for upload
  44. def _subst_for_upload(upload):
  45. """ Prepare substitutions used for announce mails.
  46. @type upload: L{daklib.upload.Source} or L{daklib.upload.Binary}
  47. @param upload: upload to handle
  48. @rtype: dict
  49. @returns: A dict of substition values for use by L{daklib.utils.TemplateSubst}
  50. """
  51. cnf = Config()
  52. maintainer = upload.maintainer or cnf['Dinstall::MyEmailAddress']
  53. changed_by = upload.changed_by or maintainer
  54. if upload.sourceful:
  55. maintainer_to = mail_addresses_for_upload(maintainer, changed_by, upload.fingerprint)
  56. else:
  57. maintainer_to = mail_addresses_for_upload(maintainer, maintainer, upload.fingerprint)
  58. bcc = 'X-DAK: dak {0}'.format(upload.program)
  59. if 'Dinstall::Bcc' in cnf:
  60. bcc = '{0}\nBcc: {1}'.format(bcc, cnf['Dinstall::Bcc'])
  61. subst = {
  62. '__DISTRO__': cnf['Dinstall::MyDistribution'],
  63. '__BUG_SERVER__': cnf.get('Dinstall::BugServer'),
  64. '__ADMIN_ADDRESS__': cnf['Dinstall::MyAdminAddress'],
  65. '__DAK_ADDRESS__': cnf['Dinstall::MyEmailAddress'],
  66. '__REJECTOR_ADDRESS__': cnf['Dinstall::MyEmailAddress'],
  67. '__MANUAL_REJECT_MESSAGE__': '',
  68. '__BCC__': bcc,
  69. '__MAINTAINER__': changed_by,
  70. '__MAINTAINER_FROM__': fix_maintainer(changed_by)[1],
  71. '__MAINTAINER_TO__': ', '.join(maintainer_to),
  72. '__CHANGES_FILENAME__': upload.changes_filename,
  73. '__FILE_CONTENTS__': upload.changes,
  74. '__SOURCE__': upload.source,
  75. '__VERSION__': upload.version,
  76. '__ARCHITECTURE__': upload.architecture,
  77. '__WARNINGS__': '\n'.join(upload.warnings),
  78. }
  79. override_maintainer = cnf.get('Dinstall::OverrideMaintainer')
  80. if override_maintainer:
  81. subst['__MAINTAINER_FROM__'] = subst['__MAINTAINER_TO__'] = override_maintainer
  82. return subst
  83. def _whitelists(upload):
  84. return [s.mail_whitelist for s in upload.suites]
  85. def announce_reject(upload, reason, rejected_by=None):
  86. """ Announce a reject.
  87. @type upload: L{daklib.upload.Source} or L{daklib.upload.Binary}
  88. @param upload: upload to handle
  89. @type reason: string
  90. @param reason: Reject reason
  91. @type rejected_by: string
  92. @param rejected_by: Who is doing the reject.
  93. """
  94. cnf = Config()
  95. subst = _subst_for_upload(upload)
  96. whitelists = _whitelists(upload)
  97. automatic = rejected_by is None
  98. subst['__CC__'] = 'X-DAK-Rejection: {0}'.format('automatic' if automatic else 'manual')
  99. subst['__REJECT_MESSAGE__'] = reason
  100. if rejected_by:
  101. subst['__REJECTOR_ADDRESS__'] = rejected_by
  102. if not automatic:
  103. subst['__BCC__'] = '{0}\nBcc: {1}'.format(subst['__BCC__'], subst['__REJECTOR_ADDRESS__'])
  104. message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'queue.rejected'))
  105. send_mail(message, whitelists=whitelists)
  106. def announce_accept(upload):
  107. """ Announce an upload.
  108. @type upload: L{daklib.upload.Source} or L{daklib.upload.Binary}
  109. @param upload: upload to handle
  110. """
  111. cnf = Config()
  112. subst = _subst_for_upload(upload)
  113. whitelists = _whitelists(upload)
  114. accepted_to_real_suite = any(suite.policy_queue is None or suite in upload.from_policy_suites for suite in upload.suites)
  115. suite_names = []
  116. for suite in upload.suites:
  117. if suite.policy_queue:
  118. suite_names.append("{0}->{1}".format(suite.suite_name, suite.policy_queue.queue_name))
  119. else:
  120. suite_names.append(suite.suite_name)
  121. suite_names.extend(suite.suite_name for suite in upload.from_policy_suites)
  122. subst['__SUITE__'] = ', '.join(suite_names) or '(none)'
  123. message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.accepted'))
  124. send_mail(message, whitelists=whitelists)
  125. if accepted_to_real_suite and upload.sourceful:
  126. # send mail to announce lists and tracking server
  127. announce = set()
  128. for suite in upload.suites:
  129. if suite.policy_queue is None or suite in upload.from_policy_suites:
  130. announce.update(suite.announce or [])
  131. announce_list_address = ", ".join(announce)
  132. # according to #890944 this email shall be sent to dispatch@<TrackingServer> to avoid
  133. # bouncing emails
  134. # the package email alias is not yet created shortly after accepting the package
  135. tracker = cnf.get('Dinstall::TrackingServer')
  136. if tracker:
  137. announce_list_address = "{0}\nBcc: dispatch@{1}".format(announce_list_address, tracker)
  138. if len(announce_list_address) != 0:
  139. my_subst = subst.copy()
  140. my_subst['__ANNOUNCE_LIST_ADDRESS__'] = announce_list_address
  141. message = TemplateSubst(my_subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.announce'))
  142. send_mail(message, whitelists=whitelists)
  143. close_bugs_default = cnf.find_b('Dinstall::CloseBugs')
  144. close_bugs = any(s.close_bugs if s.close_bugs is not None else close_bugs_default for s in upload.suites)
  145. if accepted_to_real_suite and upload.sourceful and close_bugs:
  146. for bug in upload.bugs:
  147. my_subst = subst.copy()
  148. my_subst['__BUG_NUMBER__'] = str(bug)
  149. message = TemplateSubst(my_subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.bug-close'))
  150. send_mail(message, whitelists=whitelists)
  151. def announce_new(upload):
  152. """ Announce an upload going to NEW.
  153. @type upload: L{daklib.upload.Source} or L{daklib.upload.Binary}
  154. @param upload: upload to handle
  155. """
  156. cnf = Config()
  157. subst = _subst_for_upload(upload)
  158. whitelists = _whitelists(upload)
  159. message = TemplateSubst(subst, os.path.join(cnf['Dir::Templates'], 'process-unchecked.new'))
  160. send_mail(message, whitelists=whitelists)