alter the parser (e.g. add some more options) before returning it.
Again, you can just browse around in becommands to get a feel for things.
+
+Run any doctests in your plugin with
+ be$ python test.py <yourplugin>
+for example
+ be$ python test.py merge
+
--- /dev/null
+# Copyright (C) 2005 Aaron Bentley and Panometrics, Inc.
+# <abentley@panoramicfeedback.com>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""Merge duplicate bugs"""
+from libbe import cmdutil, bugdir
+import os, copy
+__desc__ = __doc__
+
+def execute(args):
+ """
+ >>> from libbe import utility
+ >>> bd = bugdir.simple_bug_dir()
+ >>> a = bd.bug_from_shortname("a")
+ >>> a.comment_root.time = 0
+ >>> dummy = a.new_comment("Testing")
+ >>> dummy.time = 1
+ >>> dummy = dummy.new_reply("Testing...")
+ >>> dummy.time = 2
+ >>> b = bd.bug_from_shortname("b")
+ >>> b.status = "open"
+ >>> b.comment_root.time = 0
+ >>> dummy = b.new_comment("1 2")
+ >>> dummy.time = 1
+ >>> dummy = dummy.new_reply("1 2 3 4")
+ >>> dummy.time = 2
+ >>> bd.save()
+ >>> os.chdir(bd.root)
+ >>> execute(["a", "b"])
+ Merging bugs a and b
+ >>> bd._clear_bugs()
+ >>> a = bd.bug_from_shortname("a")
+ >>> a.load_comments()
+ >>> mergeA = a.comment_from_shortname(":3")
+ >>> mergeA.time = 3
+ >>> print a.string(show_comments=True)
+ ID : a
+ Short name : a
+ Severity : minor
+ Status : open
+ Assigned :
+ Target :
+ Creator : John Doe <jdoe@example.com>
+ Created : Wed, 31 Dec 1969 19:00 (Thu, 01 Jan 1970 00:00:00 +0000)
+ Bug A
+ --------- Comment ---------
+ Name: a:1
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:01 +0000
+ <BLANKLINE>
+ Testing
+ --------- Comment ---------
+ Name: a:2
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:02 +0000
+ <BLANKLINE>
+ Testing...
+ --------- Comment ---------
+ Name: a:3
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:03 +0000
+ <BLANKLINE>
+ Merged from bug b
+ --------- Comment ---------
+ Name: a:4
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:01 +0000
+ <BLANKLINE>
+ 1 2
+ --------- Comment ---------
+ Name: a:5
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:02 +0000
+ <BLANKLINE>
+ 1 2 3 4
+ >>> b = bd.bug_from_shortname("b")
+ >>> b.load_comments()
+ >>> mergeB = b.comment_from_shortname(":3")
+ >>> mergeB.time = 3
+ >>> print b.string(show_comments=True)
+ ID : b
+ Short name : b
+ Severity : minor
+ Status : closed
+ Assigned :
+ Target :
+ Creator : Jane Doe <jdoe@example.com>
+ Created : Wed, 31 Dec 1969 19:00 (Thu, 01 Jan 1970 00:00:00 +0000)
+ Bug B
+ --------- Comment ---------
+ Name: b:1
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:01 +0000
+ <BLANKLINE>
+ 1 2
+ --------- Comment ---------
+ Name: b:2
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:02 +0000
+ <BLANKLINE>
+ 1 2 3 4
+ --------- Comment ---------
+ Name: b:3
+ From: wking <wking@thor.yang.physics.drexel.edu>
+ Date: Thu, 01 Jan 1970 00:00:03 +0000
+ <BLANKLINE>
+ Merged into bug a
+ >>> print b.status
+ closed
+ """
+ options, args = get_parser().parse_args(args)
+ if len(args) < 2:
+ raise cmdutil.UserError("Please two bug ids.")
+ if len(args) > 2:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+
+ bd = bugdir.BugDir(from_disk=True)
+ bugA = bd.bug_from_shortname(args[0])
+ bugA.load_comments()
+ bugB = bd.bug_from_shortname(args[1])
+ bugB.load_comments()
+ mergeA = bugA.new_comment("Merged from bug %s" % bugB.uuid)
+ newCommTree = copy.deepcopy(bugB.comment_root)
+ for comment in newCommTree.traverse():
+ comment.bug = bugA
+ for comment in newCommTree:
+ mergeA.add_reply(comment, allow_time_inversion=True)
+ bugB.new_comment("Merged into bug %s" % bugA.uuid)
+ bugB.status = "closed"
+ bd.save()
+ print "Merging bugs %s and %s" % (bugA.uuid, bugB.uuid)
+
+def get_parser():
+ parser = cmdutil.CmdOptionParser("be merge BUG-ID BUG-ID")
+ return parser
+
+longhelp="""
+The second bug (B) is merged into the first (A). This adds merge
+comments to both bugs, closes B, and appends B's comment tree to A's
+merge comment.
+"""
+
+def help():
+ return get_parser().help_str() + longhelp
active = property(_get_active)
+ def _get_comment_root(self):
+ if self._comment_root == None:
+ if self._comments_loaded == True:
+ self._comment_root = comment.loadComments(self)
+ else:
+ self._comment_root = comment.Comment(self,
+ uuid=comment.INVALID_UUID)
+ return self._comment_root
+
+ def _set_comment_root(self, comment_root):
+ self._comment_root = comment_root
+
+ _comment_root = None
+ comment_root = property(_get_comment_root, _set_comment_root,
+ doc="The trunk of the comment tree")
+
def __init__(self, bugdir=None, uuid=None, from_disk=False,
load_comments=False, summary=None):
self.bugdir = bugdir
self.severity = "minor"
self.assigned = None
self.time = int(time.time()) # only save to second precision
- self.comment_root = comment.Comment(self, uuid=comment.INVALID_UUID)
def __repr__(self):
return "Bug(uuid=%r)" % self.uuid
statuschar = self.status[0]
severitychar = self.severity[0]
chars = "%c%c" % (statuschar, severitychar)
- bugout = "%s:%s: %s" % (shortname, chars, self.summary.rstrip('\n'))
+ bugout = "%s:%s: %s" % (shortname,chars,self.summary.rstrip('\n'))
if show_comments == True:
if self._comments_loaded == False:
self.load_comments()
def load_comments(self):
- self.comment_root = comment.loadComments(self)
+ # clear _comment_root, so _get_comment_root returns a fresh version
+ self._comment_root = None
self._comments_loaded = True
-
+
def comments(self):
if self._comments_loaded == False:
self.load_comments()
path = self.get_path("values")
mapfile.map_save(self.rcs, path, map)
- if self._comments_loaded:
- if len(self.comment_root) > 0:
- self.rcs.mkdir(self.get_path("comments"))
- comment.saveComments(self)
+ if len(self.comment_root) > 0:
+ self.rcs.mkdir(self.get_path("comments"))
+ comment.saveComments(self)
def remove(self):
- self.load_comments()
self.comment_root.remove()
path = self.get_path()
self.rcs.recursive_remove(path)
def new_comment(self, body=None):
- comm = comment.comment_root.new_reply(body=body)
+ comm = self.comment_root.new_reply(body=body)
return comm
def comment_from_shortname(self, shortname, *args, **kwargs):
- return self.comment_root.comment_from_shortname(shortname, *args, **kwargs)
+ return self.comment_root.comment_from_shortname(shortname,
+ *args, **kwargs)
def comment_from_uuid(self, uuid):
return self.comment_root.comment_from_uuid(uuid)
for comment in bug.comment_root.traverse():
comment.save()
+class InvalidShortname(KeyError):
+ def __init__(self, shortname, shortnames):
+ msg = "Invalid shortname %s\n%s" % (shortname, shortnames)
+ KeyError.__init__(self, msg)
+ self.shortname = shortname
+ self.shortnames = shortnames
+
+
class Comment(Tree):
def __init__(self, bug=None, uuid=None, from_disk=False,
in_reply_to=None, body=None):
def string(self, indent=0, shortname=None):
"""
>>> comm = Comment(bug=None, body="Some\\ninsightful\\nremarks\\n")
- >>> comm.time = utility.str_to_time("Thu, 20 Nov 2008 15:55:11 +0000")
+ >>> comm.time = utility.str_to_time("Thu, 01 Jan 1970 00:00:00 +0000")
>>> print comm.string(indent=2, shortname="com-1")
--------- Comment ---------
Name: com-1
From:
- Date: Thu, 20 Nov 2008 15:55:11 +0000
+ Date: Thu, 01 Jan 1970 00:00:00 +0000
<BLANKLINE>
Some
insightful
path = comment.get_path()
self.rcs.recursive_remove(path)
- def add_reply(self, reply):
- if reply.time != None and self.time != None:
- assert reply.time >= self.time
+ def add_reply(self, reply, allow_time_inversion=False):
if self.uuid != INVALID_UUID:
reply.in_reply_to = self.uuid
self.append(reply)
for cur_name, comment in self.comment_shortnames(*args, **kwargs):
if comment_shortname == cur_name:
return comment
- raise KeyError(comment_shortname)
+ raise InvalidShortname(comment_shortname,
+ list(self.comment_shortnames(*args, **kwargs)))
def comment_from_uuid(self, uuid):
"""
BUG=`echo "$OUT" | sed -n 's/Created bug with ID //p'`
echo "Working with bug: $BUG"
be comment $BUG "This is an argument"
+be set user_id "$ID" # get tired of guessing user id for none RCS
+be set # show settings
be comment $BUG:1 "No it isn't" # comment on the first comment
be show $BUG # show details on a given bug
be close $BUG # set bug status to 'closed'
be open $BUG # set bug status to 'open'
be comment $BUG "Reopend, comment again"
be status $BUG fixed # set bug status to 'fixed'
-be show $BUG # show bug details & comments
be list # list all open bugs
be list --status fixed # list all fixed bugs
be assign $BUG # assign the bug to yourself
be list -a Joe -s fixed # list the fixed bugs assigned to Joe
be assign $BUG none # assign the bug to noone
be diff # see what has changed
+OUT=`be new 'also having too much fun'`
+BUGB=`echo "$OUT" | sed -n 's/Created bug with ID //p'`
+be comment $BUGB "Blissfully unaware of a similar bug"
+be merge $BUG $BUGB # join BUGB to BUG
+be show $BUG # show bug details & comments
be remove $BUG # decide that you don't like that bug after all
cd /
rm -rf $TESTDIR