-# Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc.
+# Copyright (C) 2005-2011 Aaron Bentley <abentley@panoramicfeedback.com>
+# Chris Ball <cjb@laptop.org>
# Gianluca Montecchi <gian@grys.it>
# W. Trevor King <wking@drexel.edu>
#
-# 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 file is part of Bugs Everywhere.
#
-# 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.
+# Bugs Everywhere 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.
#
-# 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.
+# Bugs Everywhere 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 Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
-"""Compare two bug trees."""
+"""Tools for comparing two :class:`libbe.bug.BugDir`\s.
+"""
import difflib
import types
class SubscriptionType (libbe.util.tree.Tree):
- """
- Trees of subscription types to allow users to select exactly what
+ """Trees of subscription types to allow users to select exactly what
notifications they want to subscribe to.
"""
def __init__(self, type_name, *args, **kwargs):
raise InvalidType(name, type_root)
class Subscription (object):
- """
+ """A user subscription.
+
+ Examples
+ --------
+
>>> subscriptions = [Subscription('XYZ', 'all'),
... Subscription('DIR', 'new'),
... Subscription('ABC', BUG_TYPE_ALL),]
return '<Subscription: %s (%s)>' % (self.id, self.type)
def subscriptions_from_string(string=None, subscription_sep=',', id_sep=':'):
- """
+ """Provide a simple way for non-Python interfaces to read in subscriptions.
+
+ Examples
+ --------
+
>>> subscriptions_from_string(None)
[<Subscription: DIR (all)>]
>>> subscriptions_from_string('DIR:new,DIR:rem,ABC:all,XYZ:all')
return subscriptions
class DiffTree (libbe.util.tree.Tree):
- """
- A tree holding difference data for easy report generation.
+ """A tree holding difference data for easy report generation.
+
+ Examples
+ --------
+
>>> bugdir = DiffTree('bugdir')
>>> bdsettings = DiffTree('settings', data='target: None -> 1.0')
>>> bugdir.append(bdsettings)
return data_part
class Diff (object):
- """
- Difference tree generator for BugDirs.
+ """Difference tree generator for BugDirs.
+
+ Examples
+ --------
+
>>> import copy
>>> bd = libbe.bugdir.SimpleBugDir(memory=True)
>>> bd_new = copy.deepcopy(bd)
old_uuids.extend([s for s in subscribed_bugs
if self.old_bugdir.has_bug(s)])
old_uuids = sorted(set(old_uuids))
+
added = []
removed = []
modified = []
- for uuid in new_uuids:
- new_bug = self.new_bugdir.bug_from_uuid(uuid)
- try:
- old_bug = self.old_bugdir.bug_from_uuid(uuid)
- except KeyError:
+ if hasattr(self.old_bugdir, 'changed'):
+ # take advantage of a RevisionedBugDir-style changed() method
+ new_ids,mod_ids,rem_ids = self.old_bugdir.changed()
+ for id in new_ids:
+ for a_id in self.new_bugdir.storage.ancestors(id):
+ if a_id.count('/') == 0:
+ if a_id in [b.id.storage() for b in added]:
+ break
+ try:
+ bug = self.new_bugdir.bug_from_uuid(a_id)
+ added.append(bug)
+ except libbe.bugdir.NoBugMatches:
+ pass
+ for id in rem_ids:
+ for a_id in self.old_bugdir.storage.ancestors(id):
+ if a_id.count('/') == 0:
+ if a_id in [b.id.storage() for b in removed]:
+ break
+ try:
+ bug = self.old_bugdir.bug_from_uuid(a_id)
+ removed.append(bug)
+ except libbe.bugdir.NoBugMatches:
+ pass
+ for id in mod_ids:
+ for a_id in self.new_bugdir.storage.ancestors(id):
+ if a_id.count('/') == 0:
+ if a_id in [b[0].id.storage() for b in modified]:
+ break
+ try:
+ new_bug = self.new_bugdir.bug_from_uuid(a_id)
+ old_bug = self.old_bugdir.bug_from_uuid(a_id)
+ modified.append((old_bug, new_bug))
+ except libbe.bugdir.NoBugMatches:
+ pass
+ else:
+ for uuid in new_uuids:
+ new_bug = self.new_bugdir.bug_from_uuid(uuid)
+ try:
+ old_bug = self.old_bugdir.bug_from_uuid(uuid)
+ except KeyError:
+ if BUGDIR_TYPE_ALL in bugdir_types \
+ or BUGDIR_TYPE_NEW in bugdir_types \
+ or uuid in subscribed_bugs:
+ added.append(new_bug)
+ continue
if BUGDIR_TYPE_ALL in bugdir_types \
- or BUGDIR_TYPE_NEW in bugdir_types \
+ or BUGDIR_TYPE_MOD in bugdir_types \
or uuid in subscribed_bugs:
- added.append(new_bug)
- continue
- if BUGDIR_TYPE_ALL in bugdir_types \
- or BUGDIR_TYPE_MOD in bugdir_types \
- or uuid in subscribed_bugs:
- if old_bug.storage != None and old_bug.storage.is_readable():
- old_bug.load_comments()
- if new_bug.storage != None and new_bug.storage.is_readable():
- new_bug.load_comments()
- if old_bug != new_bug:
- modified.append((old_bug, new_bug))
- for uuid in old_uuids:
- if not self.new_bugdir.has_bug(uuid):
- old_bug = self.old_bugdir.bug_from_uuid(uuid)
- removed.append(old_bug)
+ if old_bug.storage != None and old_bug.storage.is_readable():
+ old_bug.load_comments()
+ if new_bug.storage != None and new_bug.storage.is_readable():
+ new_bug.load_comments()
+ if old_bug != new_bug:
+ modified.append((old_bug, new_bug))
+ for uuid in old_uuids:
+ if not self.new_bugdir.has_bug(uuid):
+ old_bug = self.old_bugdir.bug_from_uuid(uuid)
+ removed.append(old_bug)
added.sort()
removed.sort()
modified.sort(self._bug_modified_cmp)
return self._comment_summary_string(new_comment)
def comment_body_change_string(self, bodies):
old_body,new_body = bodies
- return difflib.unified_diff(old_body, new_body)
+ return ''.join(difflib.unified_diff(
+ old_body.splitlines(True),
+ new_body.splitlines(True),
+ 'before', 'after'))