aboutsummaryrefslogtreecommitdiffstats
path: root/interfaces/email/interactive/be-handle-mail
diff options
context:
space:
mode:
Diffstat (limited to 'interfaces/email/interactive/be-handle-mail')
-rwxr-xr-xinterfaces/email/interactive/be-handle-mail140
1 files changed, 133 insertions, 7 deletions
diff --git a/interfaces/email/interactive/be-handle-mail b/interfaces/email/interactive/be-handle-mail
index f457b6a..ed45bdd 100755
--- a/interfaces/email/interactive/be-handle-mail
+++ b/interfaces/email/interactive/be-handle-mail
@@ -52,10 +52,14 @@ import traceback
import doctest
import unittest
-import libbe.cmdutil, libbe.encoding, libbe.utility
+from becommands import subscribe
+import libbe.cmdutil, libbe.encoding, libbe.utility, libbe.bugdir
+import libbe.diff
import send_pgp_mime
-HANDLER_ADDRESS = u"BE Bugs <wking@thor.physics.drexel.edu>"
+THIS_SERVER = u"thor.physics.drexel.edu"
+THIS_ADDRESS = u"BE Bugs <wking@thor.physics.drexel.edu>"
+
_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
BE_DIR = _THIS_DIR
LOGPATH = os.path.join(_THIS_DIR, u"be-handle-mail.log")
@@ -135,6 +139,12 @@ class InvalidOption (InvalidCommand):
InvalidCommand.__init__(self, msg, info, command, bigmessage)
self.option = option
+class NotificationFailed (Exception):
+ def __init__(self, msg):
+ bigmessage = "Notification failed: %s" % msg
+ Exception.__init__(self, bigmessage)
+ self.short_msg = msg
+
class ID (object):
"""
Sometimes you want to reference the output of a command that
@@ -261,6 +271,23 @@ class Command (object):
send_pgp_mime.PGPMimeMessageFactory(u"\n".join(response_body))
return response_generator.plain()
+class DiffTree (libbe.diff.DiffTree):
+ def report_string(self):
+ return send_pgp_mime.flatten(self.report(), to_unicode=True)
+ def make_root(self):
+ return MIMEMultipart()
+ def join(self, root, part):
+ if part != None:
+ root.attach(send_pgp_mime.encodedMIMEText(part))
+ def data_string(self, depth, indent=False):
+ return libbe.diff.DiffTree.data_string(self, depth, indent=indent)
+
+class Diff (libbe.diff.Diff):
+ def bug_add_string(self, bug):
+ return bug.string(show_comments=True)
+ def comment_summary_string(self, comment):
+ return comment.string()
+
class Message (object):
def __init__(self, email_text):
self.text = email_text
@@ -472,15 +499,15 @@ class Message (object):
finally:
if AUTOCOMMIT == True:
tag,subject = self._split_subject()
- command = Command(self, "commit", [subject])
- command.run()
+ self.commit_command = Command(self, "commit", [subject])
+ self.commit_command.run()
if LOGFILE != None:
LOGFILE.write("Autocommit:\n%s\n\n" %
- send_pgp_mime.flatten(command.response_msg(),
- to_unicode=True))
+ send_pgp_mime.flatten(self.commit_command.response_msg(),
+ to_unicode=True))
def _begin_response(self):
tag,subject = self._split_subject()
- response_header = [u"From: %s" % HANDLER_ADDRESS,
+ response_header = [u"From: %s" % THIS_ADDRESS,
u"To: %s" % self.author_addr(),
u"Date: %s" % libbe.utility.time_to_str(time.time()),
u"Subject: %s Re: %s"%(SUBJECT_TAG_RESPONSE,subject)
@@ -501,6 +528,88 @@ class Message (object):
for message in self._response_messages:
response_body.attach(message)
return send_pgp_mime.attach_root(self.response_header, response_body)
+ def subscriber_emails(self):
+ if AUTOCOMMIT != True: # no way to tell what's changed
+ raise NotificationFailed("Autocommit dissabled")
+ assert len(self._response_messages) > 0
+ if self.commit_command.ret != 0:
+ # commit failed. Error already logged.
+ raise NotificationFailed("Commit failed")
+
+ # read only bugdir.
+ bd = libbe.bugdir.BugDir(from_disk=True,
+ manipulate_encodings=False)
+ if bd.rcs.versioned == False: # no way to tell what's changed
+ raise NotificationFailed("Not versioned")
+
+ subscribers = subscribe.get_bugdir_subscribers(bd, THIS_SERVER)
+ if len(subscribers) == 0:
+ return []
+
+ before_bd, after_bd = self._get_before_and_after_bugdirs(bd)
+ diff = Diff(before_bd, after_bd)
+ diff_tree = diff.report_tree(diff_tree=DiffTree)
+ bug_index = {}
+ for child in diff_tree.child_by_path("/bugs/new"):
+ bug_index[child.name] = ("added", child)
+ for child in diff_tree.child_by_path("/bugs/mod"):
+ bug_index[child.name] = ("modified", child)
+ for child in diff_tree.child_by_path("/bugs/rem"):
+ bug_index[child.name] = ("removed", child)
+ header = self._subscriber_header(bd)
+
+ emails = []
+ for subscriber,subscriptions in subscribers.items():
+ header.replace_header("to", subscriber)
+ parts = []
+ for id,types in subscriptions.items():
+ if id == "DIR":
+ if subscribe.BUGDIR_TYPE_ALL in types:
+ parts.append(diff_tree.report())
+ break
+ if subscribe.BUGDIR_TYPE_NEW in types:
+ new = diff_tree.child_by_path("/bugs/new")
+ parts.append(new.report())
+ continue # move on to next id
+ assert types == [subscribe.BUG_TYPE_ALL], types
+ type,bug_root = bug_index[id]
+ parts.append(bug_root.report())
+ if len(parts) == 0:
+ continue # no email to this subscriber
+ elif len(parts) == 1:
+ root = parts[0]
+ else: # join subscription parts into a single body
+ root = MIMEMultipart()
+ for part in parts:
+ root.attach(part)
+ emails.append(send_pgp_mime.attach_root(header, root))
+ if LOGFILE != None:
+ LOGFILE.write("Notfying %s of changes\n" % subscriber)
+ return emails
+ def _get_before_and_after_bugdirs(self, bd):
+ commit_msg = self.commit_command.stdout
+ assert commit_msg.startswith("Committed "), commit_msg
+ after_revision = commit_msg[len("Committed "):]
+ before_revision = bd.rcs.revision_id(-2)
+ if before_revision == None:
+ # this commit was the initial commit
+ before_bd = libbe.bugdir.BugDir(from_disk=False,
+ manipulate_encodings=False)
+ else:
+ before_bd = bd.duplicate_bugdir(before_revision)
+ #after_bd = bd.duplicate_bugdir(after_revision)
+ after_bd = bd # assume no changes since commit a few cycles ago
+ return (before_bd, after_bd)
+ def _subscriber_header(self, bd):
+ root_dir = os.path.basename(bd.root)
+ subject = "Changes to %s on %s by %s" \
+ % (root_dir, THIS_SERVER, self.author_addr())
+ header = [u"From: %s" % THIS_ADDRESS,
+ u"To: %s" % u"DUMMY-AUTHOR",
+ u"Date: %s" % libbe.utility.time_to_str(time.time()),
+ u"Subject: %s Re: %s" % (SUBJECT_TAG_RESPONSE, subject)
+ ]
+ return send_pgp_mime.header_from_text(text=u"\n".join(header))
def generate_global_tags(tag_base=u"be-bug"):
"""
@@ -571,6 +680,9 @@ def main():
parser.add_option('-a', '--disable-autocommit', dest='autocommit',
default=True, action='store_false',
help='Disable the autocommit after parsing the email.')
+ parser.add_option('-s', '--disable-subscribers', dest='subscribers',
+ default=True, action='store_false',
+ help='Disable subscriber notification emails.')
parser.add_option('--test', dest='test', action='store_true',
help='Run internal unit-tests and exit.')
@@ -615,8 +727,22 @@ def main():
LOGFILE.write(u"\n%s\n\n" % send_pgp_mime.flatten(response,
to_unicode=True))
send_pgp_mime.mail(response, send_pgp_mime.sendmail)
+ if options.subscribers == True:
+ LOGFILE.write(u"Checking for subscribers\n")
+ try:
+ emails = m.subscriber_emails()
+ except NotificationFailed, e:
+ LOGFILE.write(unicode(e) + u"\n")
+ else:
+ for msg in emails:
+ if options.output == True:
+ print send_pgp_mime.flatten(msg, to_unicode=True)
+ else:
+ send_pgp_mime.mail(msg, send_pgp_mime.sendmail)
+
close_logfile()
+
class GenerateGlobalTagsTestCase (unittest.TestCase):
def setUp(self):
super(GenerateGlobalTagsTestCase, self).setUp()