aboutsummaryrefslogtreecommitdiffstats
path: root/interfaces/web/Bugs-Everywhere-Web/libbe/diff.py
diff options
context:
space:
mode:
authorgian <gian@li82-39>2009-10-21 14:51:06 +0200
committergian <gian@li82-39>2009-10-21 14:51:06 +0200
commit2e235351d68715d0b232d48c21974ef6a89bb685 (patch)
treec80ae73263199f46daf6d4fda5b8e8c451fbda1a /interfaces/web/Bugs-Everywhere-Web/libbe/diff.py
parent85ab0b48299435a5ecfa6f93af95948d432e096a (diff)
parentc80312557917015fcda9f7baa9e1acdce8ad9de7 (diff)
downloadbugseverywhere-2e235351d68715d0b232d48c21974ef6a89bb685.tar.gz
test for bzr merge
Diffstat (limited to 'interfaces/web/Bugs-Everywhere-Web/libbe/diff.py')
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/libbe/diff.py419
1 files changed, 0 insertions, 419 deletions
diff --git a/interfaces/web/Bugs-Everywhere-Web/libbe/diff.py b/interfaces/web/Bugs-Everywhere-Web/libbe/diff.py
deleted file mode 100644
index 9253a23..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/libbe/diff.py
+++ /dev/null
@@ -1,419 +0,0 @@
-# Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc.
-# 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 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.
-
-"""Compare two bug trees."""
-
-import difflib
-import doctest
-
-from libbe import bugdir, bug, settings_object, tree
-from libbe.utility import time_to_str
-
-
-class DiffTree (tree.Tree):
- """
- A tree holding difference data for easy report generation.
- >>> bugdir = DiffTree("bugdir")
- >>> bdsettings = DiffTree("settings", data="target: None -> 1.0")
- >>> bugdir.append(bdsettings)
- >>> bugs = DiffTree("bugs", "bug-count: 5 -> 6")
- >>> bugdir.append(bugs)
- >>> new = DiffTree("new", "new bugs: ABC, DEF")
- >>> bugs.append(new)
- >>> rem = DiffTree("rem", "removed bugs: RST, UVW")
- >>> bugs.append(rem)
- >>> print bugdir.report_string()
- target: None -> 1.0
- bug-count: 5 -> 6
- new bugs: ABC, DEF
- removed bugs: RST, UVW
- >>> print "\\n".join(bugdir.paths())
- bugdir
- bugdir/settings
- bugdir/bugs
- bugdir/bugs/new
- bugdir/bugs/rem
- >>> bugdir.child_by_path("/") == bugdir
- True
- >>> bugdir.child_by_path("/bugs") == bugs
- True
- >>> bugdir.child_by_path("/bugs/rem") == rem
- True
- >>> bugdir.child_by_path("bugdir") == bugdir
- True
- >>> bugdir.child_by_path("bugdir/") == bugdir
- True
- >>> bugdir.child_by_path("bugdir/bugs") == bugs
- True
- >>> bugdir.child_by_path("/bugs").masked = True
- >>> print bugdir.report_string()
- target: None -> 1.0
- """
- 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_part_fn = data_part_fn
- self.requires_children = requires_children
- self.masked = masked
- def paths(self, parent_path=None):
- paths = []
- if parent_path == None:
- path = self.name
- else:
- path = "%s/%s" % (parent_path, self.name)
- paths.append(path)
- for child in self:
- paths.extend(child.paths(path))
- return paths
- def child_by_path(self, path):
- if hasattr(path, "split"): # convert string path to a list of names
- names = path.split("/")
- if names[0] == "":
- names[0] = self.name # replace root with self
- if len(names) > 1 and names[-1] == "":
- names = names[:-1] # strip empty tail
- else: # it was already an array
- names = path
- assert len(names) > 0, path
- if names[0] == self.name:
- if len(names) == 1:
- return self
- for child in self:
- if names[1] == child.name:
- return child.child_by_path(names[1:])
- if len(names) == 1:
- raise KeyError, "%s doesn't match '%s'" % (names, self.name)
- 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, parent=None, depth=0):
- if root == None:
- root = self.make_root()
- if self.masked == True:
- return None
- data_part = self.data_part(depth)
- if self.requires_children == True and len(self) == 0:
- pass
- else:
- self.join(root, parent, data_part)
- if data_part != None:
- depth += 1
- for child in self:
- child.report(root, self, depth)
- return root
- def make_root(self):
- return []
- 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_part_lines = data_part.splitlines()
- indent = " "*(depth)
- line_sep = "\n"+indent
- data_part = indent+line_sep.join(data_part_lines)
- self._cached_data_part = data_part
- return data_part
-
-class Diff (object):
- """
- Difference tree generator for BugDirs.
- >>> import copy
- >>> bd = bugdir.SimpleBugDir(sync_with_disk=False)
- >>> bd.user_id = "John Doe <j@doe.com>"
- >>> bd_new = copy.deepcopy(bd)
- >>> bd_new.target = "1.0"
- >>> a = bd_new.bug_from_uuid("a")
- >>> rep = a.comment_root.new_reply("I'm closing this bug")
- >>> rep.uuid = "acom"
- >>> rep.date = "Thu, 01 Jan 1970 00:00:00 +0000"
- >>> a.status = "closed"
- >>> b = bd_new.bug_from_uuid("b")
- >>> bd_new.remove_bug(b)
- >>> c = bd_new.new_bug("c", "Bug C")
- >>> d = Diff(bd, bd_new)
- >>> r = d.report_tree()
- >>> print "\\n".join(r.paths())
- bugdir
- bugdir/settings
- bugdir/bugs
- bugdir/bugs/new
- bugdir/bugs/new/c
- bugdir/bugs/rem
- bugdir/bugs/rem/b
- bugdir/bugs/mod
- bugdir/bugs/mod/a
- 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
- >>> print r.report_string()
- Changed bug directory settings:
- target: None -> 1.0
- New bugs:
- c:om: Bug C
- Removed bugs:
- b:cm: Bug B
- Modified bugs:
- a:cm: Bug A
- Changed bug settings:
- status: open -> closed
- New comments:
- from John Doe <j@doe.com> on Thu, 01 Jan 1970 00:00:00 +0000
- I'm closing this bug...
- >>> bd.cleanup()
- """
- def __init__(self, old_bugdir, new_bugdir):
- self.old_bugdir = old_bugdir
- self.new_bugdir = new_bugdir
-
- # data assembly methods
-
- def _changed_bugs(self):
- """
- Search for differences in all bugs between .old_bugdir and
- .new_bugdir. Returns
- (added_bugs, modified_bugs, removed_bugs)
- where added_bugs and removed_bugs are lists of added and
- removed bugs respectively. modified_bugs is a list of
- (old_bug,new_bug) pairs.
- """
- if hasattr(self, "__changed_bugs"):
- return self.__changed_bugs
- added = []
- removed = []
- modified = []
- for uuid in self.new_bugdir.list_uuids():
- new_bug = self.new_bugdir.bug_from_uuid(uuid)
- try:
- old_bug = self.old_bugdir.bug_from_uuid(uuid)
- except KeyError:
- added.append(new_bug)
- else:
- if old_bug.sync_with_disk == True:
- old_bug.load_comments()
- if new_bug.sync_with_disk == True:
- new_bug.load_comments()
- if old_bug != new_bug:
- modified.append((old_bug, new_bug))
- for uuid in self.old_bugdir.list_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)
- self.__changed_bugs = (added, modified, removed)
- return self.__changed_bugs
- def _bug_modified_cmp(self, left, right):
- return cmp(left[1], right[1])
- def _changed_comments(self, old, new):
- """
- Search for differences in all loaded comments between the bugs
- old and new. Returns
- (added_comments, modified_comments, removed_comments)
- analogous to ._changed_bugs.
- """
- if hasattr(self, "__changed_comments"):
- if new.uuid in self.__changed_comments:
- return self.__changed_comments[new.uuid]
- else:
- self.__changed_comments = {}
- added = []
- removed = []
- modified = []
- old.comment_root.sort(key=lambda comm : comm.time)
- new.comment_root.sort(key=lambda comm : comm.time)
- old_comment_ids = [c.uuid for c in old.comments()]
- new_comment_ids = [c.uuid for c in new.comments()]
- for uuid in new_comment_ids:
- new_comment = new.comment_from_uuid(uuid)
- try:
- old_comment = old.comment_from_uuid(uuid)
- except KeyError:
- added.append(new_comment)
- else:
- if old_comment != new_comment:
- modified.append((old_comment, new_comment))
- for uuid in old_comment_ids:
- if uuid not in new_comment_ids:
- new_comment = new.comment_from_uuid(uuid)
- removed.append(new_comment)
- self.__changed_comments[new.uuid] = (added, modified, removed)
- return self.__changed_comments[new.uuid]
- def _attribute_changes(self, old, new, attributes):
- """
- Take two objects old and new, and compare the value of *.attr
- for attr in the list attribute names. Returns a list of
- (attr_name, old_value, new_value)
- tuples.
- """
- change_list = []
- for attr in attributes:
- old_value = getattr(old, attr)
- new_value = getattr(new, attr)
- if old_value != new_value:
- change_list.append((attr, old_value, new_value))
- if len(change_list) >= 0:
- return change_list
- return None
- def _settings_properties_attribute_changes(self, old, new,
- hidden_properties=[]):
- properties = sorted(new.settings_properties)
- for p in hidden_properties:
- properties.remove(p)
- attributes = [settings_object.setting_name_to_attr_name(None, p)
- for p in properties]
- return self._attribute_changes(old, new, attributes)
- def _bugdir_attribute_changes(self):
- return self._settings_properties_attribute_changes( \
- self.old_bugdir, self.new_bugdir,
- ["vcs_name"]) # tweaked by bugdir.duplicate_bugdir
- def _bug_attribute_changes(self, old, new):
- return self._settings_properties_attribute_changes(old, new)
- def _comment_attribute_changes(self, old, new):
- return self._settings_properties_attribute_changes(old, new)
-
- # report generation methods
-
- def report_tree(self, diff_tree=DiffTree):
- """
- Pretty bare to make it easy to adjust to specific cases. You
- can pass in a DiffTree subclass via diff_tree to override the
- default report assembly process.
- """
- if hasattr(self, "__report_tree"):
- return self.__report_tree
- bugdir_settings = sorted(self.new_bugdir.settings_properties)
- bugdir_settings.remove("vcs_name") # tweaked by bugdir.duplicate_bugdir
- root = diff_tree("bugdir")
- bugdir_attribute_changes = self._bugdir_attribute_changes()
- if len(bugdir_attribute_changes) > 0:
- bugdir = diff_tree("settings", bugdir_attribute_changes,
- self.bugdir_attribute_change_string)
- root.append(bugdir)
- bug_root = diff_tree("bugs")
- root.append(bug_root)
- add,mod,rem = self._changed_bugs()
- bnew = diff_tree("new", "New bugs:", requires_children=True)
- bug_root.append(bnew)
- for bug in add:
- b = diff_tree(bug.uuid, bug, self.bug_add_string)
- bnew.append(b)
- brem = diff_tree("rem", "Removed bugs:", requires_children=True)
- bug_root.append(brem)
- for bug in rem:
- b = diff_tree(bug.uuid, bug, self.bug_rem_string)
- brem.append(b)
- bmod = diff_tree("mod", "Modified bugs:", requires_children=True)
- bug_root.append(bmod)
- for old,new in mod:
- b = diff_tree(new.uuid, (old,new), self.bug_mod_string)
- bmod.append(b)
- bug_attribute_changes = self._bug_attribute_changes(old, new)
- if len(bug_attribute_changes) > 0:
- bset = diff_tree("settings", bug_attribute_changes,
- self.bug_attribute_change_string)
- b.append(bset)
- if old.summary != new.summary:
- data = (old.summary, new.summary)
- bsum = diff_tree("summary", data, self.bug_summary_change_string)
- b.append(bsum)
- cr = diff_tree("comments")
- b.append(cr)
- a,m,d = self._changed_comments(old, new)
- cnew = diff_tree("new", "New comments:", requires_children=True)
- for comment in a:
- c = diff_tree(comment.uuid, comment, self.comment_add_string)
- cnew.append(c)
- crem = diff_tree("rem", "Removed comments:",requires_children=True)
- for comment in d:
- c = diff_tree(comment.uuid, comment, self.comment_rem_string)
- crem.append(c)
- cmod = diff_tree("mod","Modified comments:",requires_children=True)
- for o,n in m:
- c = diff_tree(n.uuid, (o,n), self.comment_mod_string)
- cmod.append(c)
- comm_attribute_changes = self._comment_attribute_changes(o, n)
- if len(comm_attribute_changes) > 0:
- cset = diff_tree("settings", comm_attribute_changes,
- self.comment_attribute_change_string)
- if o.body != n.body:
- data = (o.body, n.body)
- cbody = diff_tree("cbody", data,
- self.comment_body_change_string)
- c.append(cbody)
- cr.extend([cnew, crem, cmod])
- self.__report_tree = root
- return self.__report_tree
-
- # change data -> string methods.
- # Feel free to play with these in subclasses.
-
- def attribute_change_string(self, attribute_changes, indent=0):
- indent_string = " "*indent
- change_strings = [u"%s: %s -> %s" % f for f in attribute_changes]
- for i,change_string in enumerate(change_strings):
- change_strings[i] = indent_string+change_string
- return u"\n".join(change_strings)
- def bugdir_attribute_change_string(self, attribute_changes):
- return "Changed bug directory settings:\n%s" % \
- self.attribute_change_string(attribute_changes, indent=1)
- def bug_attribute_change_string(self, attribute_changes):
- return "Changed bug settings:\n%s" % \
- self.attribute_change_string(attribute_changes, indent=1)
- def comment_attribute_change_string(self, attribute_changes):
- return "Changed comment settings:\n%s" % \
- self.attribute_change_string(attribute_changes, indent=1)
- def bug_add_string(self, bug):
- return bug.string(shortlist=True)
- def bug_rem_string(self, bug):
- return bug.string(shortlist=True)
- def bug_mod_string(self, bugs):
- old_bug,new_bug = bugs
- return new_bug.string(shortlist=True)
- def bug_summary_change_string(self, summaries):
- old_summary,new_summary = summaries
- return "summary changed:\n %s\n %s" % (old_summary, new_summary)
- def _comment_summary_string(self, comment):
- return "from %s on %s" % (comment.author, time_to_str(comment.time))
- def comment_add_string(self, comment):
- summary = self._comment_summary_string(comment)
- first_line = comment.body.splitlines()[0]
- return "%s\n %s..." % (summary, first_line)
- def comment_rem_string(self, comment):
- summary = self._comment_summary_string(comment)
- first_line = comment.body.splitlines()[0]
- return "%s\n %s..." % (summary, first_line)
- def comment_mod_string(self, comments):
- old_comment,new_comment = comments
- 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)
-
-
-suite = doctest.DocTestSuite()