Previously, every node in the DiffTree created it's own attachment.
Now they're consolidated into a single attachment per bug. higher
level nodes are still one attachment per node.
Also:
* added send_pgp_mime.append_text()
* pulled guess_encoding() out of send_pgp_mime.encodedMIMEText().
* renamed data_string -> data_part in libbe.diff, since it needn't be a string.
import unittest
from becommands import subscribe
-import libbe.cmdutil, libbe.encoding, libbe.utility, libbe.bugdir
-import libbe.diff
+import libbe.cmdutil, libbe.encoding, libbe.utility, libbe.diff, \
+ libbe.bugdir, libbe.bug, libbe.comment
import send_pgp_mime
THIS_SERVER = u"thor.physics.drexel.edu"
return response_generator.plain()
class DiffTree (libbe.diff.DiffTree):
+ """
+ In order to avoid tons of tiny MIMEText attachments, bug-level
+ nodes set .add_child_text=True (in .join()), which is propogated
+ on to their descendents. Instead of creating their own
+ attachement, each of these descendents appends his data_part to
+ the end of the bug-level MIMEText attachment.
+
+ For the example tree in the libbe.diff.Diff unittests:
+ bugdir
+ bugdir/settings
+ bugdir/bugs
+ bugdir/bugs/new
+ bugdir/bugs/new/c <- sets .add_child_text
+ bugdir/bugs/rem
+ bugdir/bugs/rem/b <- sets .add_child_text
+ bugdir/bugs/mod
+ bugdir/bugs/mod/a <- sets .add_child_text
+ bugdir/bugs/mod/a/settings
+ bugdir/bugs/mod/a/comments
+ bugdir/bugs/mod/a/comments/new
+ bugdir/bugs/mod/a/comments/new/acom
+ bugdir/bugs/mod/a/comments/rem
+ bugdir/bugs/mod/a/comments/mod
+ """
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)
+ def join(self, root, parent, data_part):
+ if hasattr(parent, "attach_child_text"):
+ self.attach_child_text = True
+ if data_part != None:
+ send_pgp_mime.append_text(parent.data_mime_part, u"\n\n%s" % (data_part))
+ self.data_mime_part = parent.data_mime_part
+ else:
+ self.data_mime_part = None
+ if data_part != None:
+ self.data_mime_part = send_pgp_mime.encodedMIMEText(data_part)
+ if parent != None and parent.name in ["new", "rem", "mod"]:
+ self.attach_child_text = True
+ if data_part == None: # make blank data_mime_part for children's appends
+ self.data_mime_part = send_pgp_mime.encodedMIMEText("")
+ if self.data_mime_part != None:
+ self.data_mime_part["Content-Description"] = self.name
+ root.attach(self.data_mime_part)
+ def data_part(self, depth, indent=False):
+ return libbe.diff.DiffTree.data_part(self, depth, indent=indent)
class Diff (libbe.diff.Diff):
def bug_add_string(self, bug):
if options.notify_since != None:
if options.subscribers == True:
- libbe.encoding.set_IO_stream_encodings(ENCODING) # _after_ reading message
+ libbe.encoding.set_IO_stream_encodings(ENCODING)
open_logfile(options.logfile)
if LOGFILE != None:
LOGFILE.write(u"Checking for subscribers to notify since revision %s\n"
p = Parser()
return p.parsestr(text, headersonly=True)
+def guess_encoding(text):
+ if type(text) == types.StringType:
+ encoding = "us-ascii"
+ elif type(text) == types.UnicodeType:
+ for encoding in ["us-ascii", "iso-8859-1", "utf-8"]:
+ try:
+ text.encode(encoding)
+ except UnicodeError:
+ pass
+ else:
+ break
+ assert encoding != None
+ return encoding
+
def encodedMIMEText(body, encoding=None):
if encoding == None:
- if type(body) == types.StringType:
- encoding = "us-ascii"
- elif type(body) == types.UnicodeType:
- for encoding in ["us-ascii", "iso-8859-1", "utf-8"]:
- try:
- body.encode(encoding)
- except UnicodeError:
- pass
- else:
- break
- assert encoding != None
- # Create the message ('plain' stands for Content-Type: text/plain)
+ encoding = guess_encoding(body)
if encoding == "us-ascii":
return MIMEText(body)
else:
+ # Create the message ('plain' stands for Content-Type: text/plain)
return MIMEText(body.encode(encoding), 'plain', encoding)
+def append_text(text_part, new_text):
+ original_payload = text_part.get_payload(decode=True)
+ new_payload = u"%s%s" % (original_payload, new_text)
+ new_encoding = guess_encoding(new_payload)
+ text_part.set_payload(new_payload.encode(new_encoding), new_encoding)
+
def attach_root(header, root_part):
"""
Attach the email.Message root_part to the email.Message header
>>> print all.report_string()
target: None -> 1.0
"""
- def __init__(self, name, data=None, data_string_fn=str,
+ def __init__(self, name, data=None, data_part_fn=str,
requires_children=False, masked=False):
tree.Tree.__init__(self)
self.name = name
self.data = data
- self.data_string_fn = data_string_fn
+ self.data_part_fn = data_part_fn
self.requires_children = requires_children
self.masked = masked
def paths(self, parent_path=None):
raise KeyError, "%s points to child not in %s" % (names, [c.name for c in self])
def report_string(self):
return "\n".join(self.report())
- def report(self, root=None, depth=0):
+ def report(self, root=None, parent=None, depth=0):
if root == None:
root = self.make_root()
if self.masked == True:
return None
- data_string = self.data_string(depth)
- if self.data == None:
- pass
- elif self.requires_children == True and len(self) == 0:
+ data_part = self.data_part(depth)
+ if self.requires_children == True and len(self) == 0:
pass
else:
- self.join(root, data_string)
+ self.join(root, parent, data_part)
depth += 1
for child in self:
- child.report(root, depth)
+ child.report(root, self, depth)
return root
def make_root(self):
return []
- def join(self, root, part):
- if part != None:
- root.append(part)
- def data_string(self, depth, indent=True):
- if hasattr(self, "_cached_data_string"):
- return self._cached_data_string
- data_string = self.data_string_fn(self.data)
+ def join(self, root, parent, data_part):
+ if data_part != None:
+ root.append(data_part)
+ def data_part(self, depth, indent=True):
+ if self.data == None:
+ return None
+ if hasattr(self, "_cached_data_part"):
+ return self._cached_data_part
+ data_part = self.data_part_fn(self.data)
if indent == True:
- data_string_lines = data_string.splitlines()
+ data_part_lines = data_part.splitlines()
indent = " "*(depth)
line_sep = "\n"+indent
- data_string = indent+line_sep.join(data_string_lines)
- self._cached_data_string = data_string
- return data_string
+ data_part = indent+line_sep.join(data_part_lines)
+ self._cached_data_part = data_part
+ return data_part
class Diff (object):
"""