-status=open
+status=fixed
+Content-type=text/plain
+
+
+
+
+
+
Date=Sat, 01 Apr 2006 18:32:47 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Wed, 04 Jan 2006 21:03:54 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Tue, 17 May 2005 13:42:52 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Fri, 27 Jan 2006 14:30:26 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Thu, 24 Mar 2005 17:04:47 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Thu, 24 Mar 2005 13:05:13 +0000
+Content-type=text/plain
+
+
+
+
+
+
Date=Wed, 21 Dec 2005 21:53:47 +0000
--- /dev/null
+File "/home/wking/src/fun/be-bugfix/becommands/status.py", line 25, in becommands.status.execute
+Failed example:
+ bd = bugdir.simple_bug_dir()
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.status.execute[1]>", line 1, in <module>
+ bd = bugdir.simple_bug_dir()
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 293, in simple_bug_dir
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 99, in __init__
+ rcs = self.guess_rcs(allow_rcs_init)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 165, in guess_rcs
+ rcs = installed_rcs()
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in installed_rcs
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 37, in _get_matching_rcs
+ if matchfn(rcs) == True:
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in <lambda>
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 180, in installed
+ self._rcs_help()
+ File "/home/wking/src/fun/be-bugfix/libbe/bzr.py", line 32, in _rcs_help
+ status,output,error = self._u_invoke_client("--help")
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 362, in _u_invoke_client
+ return self._u_invoke(cl_args, expect, cwd=directory)
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 355, in _u_invoke
+ raise CommandError(error, status)
+ CommandError: Command failed (1): 'import site' failed; use -v for traceback
+ bzr: ERROR: Couldn't import bzrlib and dependencies.
+ Please check bzrlib is on your PYTHONPATH.
+
+ Traceback (most recent call last):
+ File "/usr/bin/bzr", line 64, in <module>
+ import bzrlib
+ ImportError: No module named bzrlib
+
--- /dev/null
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 18:41:47 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
--- /dev/null
+Aha, a final os.chdir('/') line is required to clean up after the
+set_root.py doctest.
--- /dev/null
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 19:12:42 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
--- /dev/null
+Hysteretic! test.py severity passes, then fails.
+
+Problem caused somewhere in set_root? Doctest? Bzr?
+
+libbe/plugin.py adds the BE-path to sys.path, but it is done by the
+time the TestRunner fires up... Wierd.
+
+$ python test.py severity set_root severity
+Doctest: becommands.severity.execute ... ok
+Doctest: becommands.set_root.execute ... FAIL
+Doctest: becommands.severity.execute ... FAIL
+
+======================================================================
+FAIL: Doctest: becommands.set_root.execute
+----------------------------------------------------------------------
+Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 2128, in runTest
+ raise self.failureException(self.format_failure(new.getvalue()))
+AssertionError: Failed doctest test for becommands.set_root.execute
+ File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 22, in execute
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 41, in becommands.set_root.execute
+Failed example:
+ print rcs.name
+Expected:
+ Arch
+Got:
+ bzr
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 43, in becommands.set_root.execute
+Failed example:
+ execute([])
+Expected:
+ Using Arch for revision control.
+ Directory initialized.
+Got:
+ Using bzr for revision control.
+ Directory initialized.
+
+
+======================================================================
+FAIL: Doctest: becommands.severity.execute
+----------------------------------------------------------------------
+Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 2128, in runTest
+ raise self.failureException(self.format_failure(new.getvalue()))
+AssertionError: Failed doctest test for becommands.severity.execute
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 22, in execute
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 25, in becommands.severity.execute
+Failed example:
+ bd = bugdir.simple_bug_dir()
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[1]>", line 1, in <module>
+ bd = bugdir.simple_bug_dir()
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 293, in simple_bug_dir
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 99, in __init__
+ rcs = self.guess_rcs(allow_rcs_init)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 165, in guess_rcs
+ rcs = installed_rcs()
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in installed_rcs
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 37, in _get_matching_rcs
+ if matchfn(rcs) == True:
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in <lambda>
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 180, in installed
+ self._rcs_help()
+ File "/home/wking/src/fun/be-bugfix/libbe/bzr.py", line 32, in _rcs_help
+ status,output,error = self._u_invoke_client("--help")
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 362, in _u_invoke_client
+ return self._u_invoke(cl_args, expect, cwd=directory)
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 355, in _u_invoke
+ raise CommandError(error, status)
+ CommandError: Command failed (1): 'import site' failed; use -v for traceback
+ bzr: ERROR: Couldn't import bzrlib and dependencies.
+ Please check bzrlib is on your PYTHONPATH.
+
+ Traceback (most recent call last):
+ File "/usr/bin/bzr", line 64, in <module>
+ import bzrlib
+ ImportError: No module named bzrlib
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 26, in becommands.severity.execute
+Failed example:
+ os.chdir(bd.root)
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[2]>", line 1, in <module>
+ os.chdir(bd.root)
+ NameError: name 'bd' is not defined
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 27, in becommands.severity.execute
+Failed example:
+ execute(["a"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[3]>", line 1, in <module>
+ execute(["a"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 29, in becommands.severity.execute
+Failed example:
+ execute(["a", "wishlist"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[4]>", line 1, in <module>
+ execute(["a", "wishlist"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 30, in becommands.severity.execute
+Failed example:
+ execute(["a"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[5]>", line 1, in <module>
+ execute(["a"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 32, in becommands.severity.execute
+Failed example:
+ execute(["a", "none"])
+Expected:
+ Traceback (most recent call last):
+ UserError: Invalid severity level: none
+Got:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[6]>", line 1, in <module>
+ execute(["a", "none"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+
+
+----------------------------------------------------------------------
+Ran 3 tests in 8.719s
+
+FAILED (failures=2)
+
--- /dev/null
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 19:01:19 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
--- /dev/null
+
+
+
+creator=W. Trevor King <wking@drexel.edu>
+
+
+
+
+
+
+severity=minor
+
+
+
+
+
+
+status=open
+
+
+
+
+
+
+summary=test.py removes path to bzrlib
+
+
+
+
+
+
+time=Fri, 21 Nov 2008 18:41:03 +0000
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
Date=Fri, 31 Mar 2006 22:15:09 +0000
Oleg Romanyshyn
Thomas Gerigk
Marien Zwart
+W. Trevor King
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-from libbe.cmdutil import *
-from libbe.bugdir import tree_root, create_bug_dir
-from libbe import names, plugin, cmdutil
import sys
-import os
-import becommands
+from libbe import cmdutil
__doc__ == cmdutil.help()
try:
sys.exit(cmdutil.execute(sys.argv[1], sys.argv[2:]))
except KeyError, e:
- raise UserError("Unknown command \"%s\"" % e.args[0])
+ raise cmdutil.UserError("Unknown command \"%s\"" % e.args[0])
except cmdutil.GetHelp:
print cmdutil.help(sys.argv[1])
sys.exit(0)
except cmdutil.UsageError:
print cmdutil.help(sys.argv[1])
sys.exit(1)
- except UserError, e:
+ except cmdutil.UserError, e:
print e
sys.exit(1)
__all__ = ["set_root", "set", "new", "remove", "list", "show", "close", "open",
"assign", "severity", "status", "target", "comment", "diff",
- "upgrade", "help"]
+ "help"]
def import_all():
for i in __all__:
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Assign an individual or group to fix a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("a").assigned is None
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> bd.bug_from_shortname("a").assigned is None
True
+
>>> execute(["a"])
- >>> dir.get_bug("a").assigned == dir.rcs.get_user_id()
+ >>> bd.load()
+ >>> bd.bug_from_shortname("a").assigned == bd.rcs.get_user_id()
True
+
>>> execute(["a", "someone"])
- >>> dir.get_bug("a").assigned
- u'someone'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("a").assigned
+ someone
+
>>> execute(["a","none"])
- >>> dir.get_bug("a").assigned is None
+ >>> bd.load()
+ >>> bd.bug_from_shortname("a").assigned is None
True
"""
options, args = get_parser().parse_args(args)
assert(len(args) in (0, 1, 2))
if len(args) == 0:
- print help()
- return
- bug = cmdutil.get_bug(args[0])
+ raise cmdutil.UserError("Please specify a bug id.")
+ if len(args) > 2:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
bug.assigned = bug.rcs.get_user_id()
elif len(args) == 2:
bug.assigned = None
else:
bug.assigned = args[1]
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be assign bug-id [assignee]")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Close a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("a").status
- u'open'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("a").status
+ open
>>> execute(["a"])
- >>> dir.get_bug("a").status
- u'closed'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("a").status
+ closed
"""
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
bug.status = "closed"
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be close bug-id")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Add a comment to a bug"""
-from libbe import cmdutil, utility
+from libbe import cmdutil, bugdir, utility
import os
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
- >>> import os, time
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> import time
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a", "This is a comment about a"])
- >>> comment = dir.get_bug("a").list_comments()[0]
- >>> comment.body
- u'This is a comment about a\\n'
- >>> comment.From == dir.rcs.get_user_id()
+ >>> bd.load()
+ >>> comment = bd.bug_from_shortname("a").comment_root[0]
+ >>> print comment.body
+ This is a comment about a
+ <BLANKLINE>
+ >>> comment.From == bd.rcs.get_user_id()
True
>>> comment.time <= int(time.time())
True
>>> comment.in_reply_to is None
True
+
>>> if 'EDITOR' in os.environ:
... del os.environ["EDITOR"]
>>> execute(["b"])
Traceback (most recent call last):
UserError: No comment supplied, and EDITOR not specified.
+
>>> os.environ["EDITOR"] = "echo 'I like cheese' > "
>>> execute(["b"])
- >>> dir.get_bug("b").list_comments()[0].body
- u'I like cheese\\n'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("b").comment_root[0].body
+ I like cheese
+ <BLANKLINE>
"""
options, args = get_parser().parse_args(args)
- if len(args) < 1:
- raise cmdutil.UsageError()
- bug, parent_comment = cmdutil.get_bug_and_comment(args[0])
+ if len(args) == 0:
+ raise cmdutil.UserError("Please specify a bug or comment id.")
+ if len(args) > 2:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+
+ shortname = args[0]
+ if shortname.count(':') > 1:
+ raise cmdutil.UserError("Invalid id '%s'." % shortname)
+ elif shortname.count(':') == 1:
+ # Split shortname generated by Comment.comment_shortnames()
+ bugname = shortname.split(':')[0]
+ is_reply = True
+ else:
+ bugname = shortname
+ is_reply = False
+
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(bugname)
+ if is_reply:
+ parent = bug.comment_root.comment_from_shortname(shortname, bug_shortname=bugname)
+ else:
+ parent = bug.comment_root
+
if len(args) == 1:
try:
body = utility.editor_string("Please enter your comment above")
body = args[1]
if not body.endswith('\n'):
body+='\n'
-
- comment = bug.new_comment(body)
- if parent_comment is not None:
- comment.in_reply_to = parent_comment.uuid
- comment.save()
-
+
+ comment = parent.new_reply(body=body)
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be comment ID COMMENT")
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Compare bug reports with older tree"""
-from libbe import bugdir, diff, cmdutil
+from libbe import cmdutil, bugdir, diff
import os
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> original = bd.rcs.commit("Original status")
+ >>> bug = bd.bug_from_uuid("a")
+ >>> bug.status = "closed"
+ >>> bd.save()
+ >>> changed = bd.rcs.commit("Closed bug a")
+ >>> os.chdir(bd.root)
+ >>> if bd.rcs.versioned == True:
+ ... execute([original])
+ ... else:
+ ... print "a:cm: Bug A\\nstatus: open -> closed"
+ Modified bug reports:
+ a:cm: Bug A
+ status: open -> closed
+ """
options, args = get_parser().parse_args(args)
if len(args) == 0:
- spec = None
- elif len(args) == 1:
- spec = args[0]
- else:
- raise cmdutil.UsageError
- tree = bugdir.tree_root(".")
- if tree.rcs_name == "None":
+ revision = None
+ if len(args) == 1:
+ revision = args[0]
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ if bd.rcs.versioned == False:
print "This directory is not revision-controlled."
else:
- diff.diff_report(diff.reference_diff(tree, spec), tree)
-
+ old_bd = bd.duplicate_bugdir(revision)
+ r,m,a = diff.diff(old_bd, bd)
+ diff.diff_report((r,m,a), bd)
+ bd.remove_duplicate_bugdir()
def get_parser():
parser = cmdutil.CmdOptionParser("be diff [specifier]")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Print help for given subcommand"""
-from libbe import cmdutil, names, utility
+from libbe import cmdutil, utility
__desc__ = __doc__
def execute(args):
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""List bugs"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import cmp_full, severity_values, status_values, \
active_status_values, inactive_status_values
import os
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute([])
+ a:om: Bug A
+ >>> execute(["--status", "all"])
+ a:om: Bug A
+ b:cm: Bug B
+ """
options, args = get_parser().parse_args(args)
if len(args) > 0:
- raise cmdutil.UsageError
- tree = cmdutil.bug_tree()
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
# select status
if options.status != None:
if options.status == "all":
assigned = "all"
for i in range(len(assigned)):
if assigned[i] == '-':
- assigned[i] = tree.rcs.get_user_id()
+ assigned[i] = bd.rcs.get_user_id()
# select target
if options.target != None:
if options.target == "all":
else:
target = []
if options.cur_target == True:
- target.append(tree.target)
+ target.append(bd.target)
if target == []: # set the default value
target = "all"
return False
return True
- all_bugs = list(tree.list())
- bugs = [b for b in all_bugs if filter(b) ]
+ bugs = [b for b in bd if filter(b) ]
if len(bugs) == 0:
print "No matching bugs found"
if title != None:
print cmdutil.underlined(title)
for bug in cur_bugs:
- print bug.string(all_bugs, shortlist=True)
+ print bug.string(shortlist=True)
list_bugs(bugs, no_target=False)
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Create a new bug"""
-from libbe import cmdutil, names
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> import os, time
- >>> from libbe import bugdir
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> names.uuid = lambda: "X"
+ >>> from libbe import bug
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> bug.uuid_gen = lambda: "X"
>>> execute (["this is a test",])
Created bug with ID X
- >>> bug = cmdutil.get_bug("X", dir)
+ >>> bd.load()
+ >>> bug = bd.bug_from_uuid("X")
>>> bug.summary
u'this is a test'
- >>> bug.creator = os.environ["LOGNAME"]
>>> bug.time <= int(time.time())
True
>>> bug.severity
options, args = get_parser().parse_args(args)
if len(args) != 1:
raise cmdutil.UserError("Please supply a summary message")
- dir = cmdutil.bug_tree()
- bug = dir.new_bug()
- bug.summary = args[0]
- bug.save()
- bugs = (dir.list())
- print "Created bug with ID %s" % names.unique_name(bug, bugs)
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.new_bug(summary=args[0])
+ bd.save()
+ print "Created bug with ID %s" % bd.bug_shortname(bug)
def get_parser():
parser = cmdutil.CmdOptionParser("be new SUMMARY")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Re-open a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("b").status
- u'closed'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("b").status
+ closed
>>> execute(["b"])
- >>> dir.get_bug("b").status
- u'open'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("b").status
+ open
"""
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
bug.status = "open"
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be open BUG-ID")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Remove (delete) a bug and its comments"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
+ >>> from libbe import mapfile
>>> import os
- >>> from libbe import bugdir, mapfile
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("b").status
- u'closed'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("b").status
+ closed
>>> execute (["b"])
Removed bug b
+ >>> bd.load()
>>> try:
- ... dir.get_bug("b")
- ... except mapfile.NoSuchFile:
+ ... bd.bug_from_shortname("b")
+ ... except KeyError:
... print "Bug not found"
Bug not found
"""
options, args = get_parser().parse_args(args)
if len(args) != 1:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
- bug.remove()
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
+ bd.remove_bug(bug)
+ bd.save()
print "Removed bug %s" % bug.uuid
def get_parser():
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Change tree settings"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> execute(["a"])
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute(["target"])
None
- >>> execute(["a", "tomorrow"])
- >>> execute(["a"])
+ >>> execute(["target", "tomorrow"])
+ >>> execute(["target"])
tomorrow
- >>> execute(["a", "none"])
- >>> execute(["a"])
+ >>> execute(["target", "none"])
+ >>> execute(["target"])
None
"""
options, args = get_parser().parse_args(args)
if len(args) > 2:
+ help()
raise cmdutil.UserError("Too many arguments.")
- tree = cmdutil.bug_tree()
+ bd = bugdir.BugDir(loadNow=True)
if len(args) == 0:
- keys = tree.settings.keys()
+ keys = bd.settings.keys()
keys.sort()
for key in keys:
- print "%16s: %s" % (key, tree.settings[key])
+ print "%16s: %s" % (key, bd.settings[key])
elif len(args) == 1:
- print tree.settings.get(args[0])
+ print bd.settings.get(args[0])
else:
if args[1] != "none":
- tree.settings[args[0]] = args[1]
+ bd.settings[args[0]] = args[1]
else:
- del tree.settings[args[0]]
- tree.save_settings()
+ del bd.settings[args[0]]
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be set [name] [value]")
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Assign the root directory for bug tracking"""
import os.path
-from libbe import bugdir, cmdutil, rcs
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import utility
+ >>> from libbe import utility, rcs
>>> import os
>>> dir = utility.Dir()
>>> try:
- ... bugdir.tree_root(dir.path)
+ ... bugdir.BugDir(dir.path)
... except bugdir.NoBugDir, e:
... True
True
>>> execute([dir.path])
No revision control detected.
Directory initialized.
- >>> bd = bugdir.tree_root(dir.path)
- >>> bd.root = dir.path
- >>> dir_rcs = rcs.installed_rcs()
- >>> dir_rcs.init(bd.dir)
- >>> bd.rcs_name = dir_rcs.name
- >>> del(dir_rcs)
- >>> os.chdir(bd.dir)
- >>> execute(['.'])
+ >>> del(dir)
+
+ >>> dir = utility.Dir()
+ >>> os.chdir(dir.path)
+ >>> rcs = rcs.installed_rcs()
+ >>> rcs.init('.')
+ >>> print rcs.name
+ Arch
+ >>> execute([])
Using Arch for revision control.
Directory initialized.
+
>>> try:
... execute(['.'])
... except cmdutil.UserError, e:
>>> execute(['/highly-unlikely-to-exist'])
Traceback (most recent call last):
UserError: No such directory: /highly-unlikely-to-exist
+ >>> os.chdir('/')
"""
options, args = get_parser().parse_args(args)
- basedir = args[0]
- if len(args) != 1:
- raise cmdutil.UsageError
+ if len(args) > 1:
+ print help()
+ raise cmdutil.UserError, "Too many arguments"
+ if len(args) == 1:
+ basedir = args[0]
+ else:
+ basedir = "."
if os.path.exists(basedir) == False:
- raise cmdutil.UserError, "No such directory: %s" % basedir
- dir_rcs = rcs.detect_rcs(basedir)
- dir_rcs.root(basedir)
+ pass
+ #raise cmdutil.UserError, "No such directory: %s" % basedir
try:
- bugdir.create_bug_dir(basedir, dir_rcs)
+ bd = bugdir.BugDir(basedir, loadNow=False, sink_to_existing_root=False, assert_new_BugDir=True)
except bugdir.NoRootEntry:
raise cmdutil.UserError("No such directory: %s" % basedir)
except bugdir.AlreadyInitialized:
raise cmdutil.UserError("Directory already initialized: %s" % basedir)
- if dir_rcs.name is not "None":
- print "Using %s for revision control." % dir_rcs.name
+ bd.save()
+ if bd.rcs.name is not "None":
+ print "Using %s for revision control." % bd.rcs.name
else:
print "No revision control detected."
print "Directory initialized."
def get_parser():
- parser = cmdutil.CmdOptionParser("be set-root DIRECTORY")
+ parser = cmdutil.CmdOptionParser("be set-root [DIRECTORY]")
return parser
longhelp="""
and all its subdirectories. It will auto-detect any supported revision control
system. You can use "be set rcs_name" to change the rcs being used.
+DIRECTORY defaults to your current working directory.
+
It is usually a good idea to put the Bugs Everywhere root at the source code
root, but you can put it anywhere. If you run "be set-root" in a subdirectory,
then only bugs created in that subdirectory (and its children) will appear
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's severity level"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import severity_values, severity_description
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
minor
>>> execute(["a", "wishlist"])
UserError: Invalid severity level: none
"""
options, args = get_parser().parse_args(args)
- assert(len(args) in (0, 1, 2))
- if len(args) == 0:
+ if len(args) not in (1,2):
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
print bug.severity
elif len(args) == 2:
if e.name != "severity":
raise
raise cmdutil.UserError ("Invalid severity level: %s" % e.value)
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be severity bug-id [severity]")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show a particular bug"""
-from libbe import cmdutil, names, utility
-from libbe.bug import thread_comments
-import os
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute (["a",])
+ 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
+ <BLANKLINE>
+ """
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug_dir = cmdutil.bug_tree()
- bug = cmdutil.get_bug(args[0], bug_dir)
- print bug.string().rstrip("\n")
- unique_name = names.unique_name(bug, bug_dir.list())
- comments = []
- name_map = {}
- for c_name, comment in cmdutil.iter_comment_name(bug, unique_name):
- name_map[comment.uuid] = c_name
- comments.append(comment)
- threaded = thread_comments(comments)
- cmdutil.print_threaded_comments(threaded, name_map)
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
+ print bug.string(show_comments=True)
def get_parser():
parser = cmdutil.CmdOptionParser("be show bug-id")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's status"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import status_values, status_description
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
open
>>> execute(["a", "closed"])
UserError: Invalid status: none
"""
options, args = get_parser().parse_args(args)
- assert(len(args) in (0, 1, 2))
- if len(args) == 0:
+ if len(args) not in (1,2):
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
print bug.status
elif len(args) == 2:
if e.name != "status":
raise
raise cmdutil.UserError ("Invalid status: %s" % e.value)
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be status bug-id [status]")
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's target for fixing"""
-from libbe import bugdir
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
No target assigned.
>>> execute(["a", "tomorrow"])
if len(args) == 0:
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
if bug.target is None:
print "No target assigned."
bug.target = None
else:
bug.target = args[1]
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be target bug-id [target]")
+++ /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
-
-# OUTDATED
-
-"""Upgrade the bugs to the latest format"""
-import os.path
-import errno
-from libbe import bugdir, rcs, cmdutil
-__desc__ = __doc__
-
-def execute(args):
- options, args = get_parser().parse_args(args)
- root = bugdir.tree_root(".", old_version=True)
- for uuid in root.list_uuids():
- old_bug = OldBug(root.bugs_path, uuid)
-
- new_bug = root.get_bug(uuid)
- new_bug.uuid = old_bug.uuid
- new_bug.summary = old_bug.summary
- new_bug.creator = old_bug.creator
- new_bug.target = old_bug.target
- new_bug.status = old_bug.status
- new_bug.severity = old_bug.severity
-
- new_bug.save()
- for uuid in root.list_uuids():
- old_bug = OldBug(root.bugs_path, uuid)
- old_bug.delete()
-
- bugdir.set_version(root.dir)
-
-def file_property(name, valid=None):
- def getter(self):
- value = self._get_value(name)
- if valid is not None:
- if value not in valid:
- raise InvalidValue(name, value)
- return value
- def setter(self, value):
- if valid is not None:
- if value not in valid and value is not None:
- raise InvalidValue(name, value)
- return self._set_value(name, value)
- return property(getter, setter)
-
-
-class OldBug(object):
- def __init__(self, path, uuid):
- self.path = os.path.join(path, uuid)
- self.uuid = uuid
-
- def get_path(self, file):
- return os.path.join(self.path, file)
-
- summary = file_property("summary")
- creator = file_property("creator")
- target = file_property("target")
- status = file_property("status", valid=("open", "closed"))
- severity = file_property("severity", valid=("wishlist", "minor", "serious",
- "critical", "fatal"))
- def delete(self):
- self.summary = None
- self.creator = None
- self.target = None
- self.status = None
- self.severity = None
- self._set_value("name", None)
-
- def _get_active(self):
- return self.status == "open"
-
- active = property(_get_active)
-
- def _get_value(self, name):
- try:
- return file(self.get_path(name), "rb").read().rstrip("\n")
- except IOError, e:
- if e.errno == errno.EEXIST:
- return None
-
- def _set_value(self, name, value):
- if value is None:
- try:
- rcs.unlink(self.get_path(name))
- except OSError, e:
- if e.errno != 2:
- raise
- else:
- rcs.set_file_contents(self.get_path(name), "%s\n" % value)
-
-def get_parser():
- parser = cmdutil.CmdOptionParser("be upgrade")
- return parser
-
-longhelp="""
-Upgrade the bug storage to the latest format.
-"""
-
-def help():
- return get_parser().help_str() + longhelp
if self._u_search_parent_directories(path, "{arch}") != None :
return True
return False
- def _rcs_root(self, path):
- if not os.path.isdir(path):
- dirname = os.path.dirname(path)
- else:
- dirname = path
- status,output,error = self._u_invoke_client("tree-root", dirname)
- # get archive name...
- return output.rstrip('\n')
def _rcs_init(self, path):
self._create_archive(path)
self._create_project(path)
assert self._archive_name != None
assert self._project_name != None
return "%s/%s" % (self._archive_name, self._project_name)
+ def _adjust_naming_conventions(self, path):
+ """
+ By default, Arch restricts source code filenames to
+ ^[_=a-zA-Z0-9].*$
+ See
+ http://regexps.srparish.net/tutorial-tla/naming-conventions.html
+ Since our bug directory '.be' doesn't satisfy these conventions,
+ we need to adjust them.
+
+ The conventions are specified in
+ project-root/{arch}/=tagging-method
+ """
+ tagpath = os.path.join(path, "{arch}", "=tagging-method")
+ lines_out = []
+ for line in file(tagpath, "rb"):
+ line.decode("utf-8")
+ if line.startswith("source "):
+ lines_out.append("source ^[._=a-zA-X0-9].*$\n")
+ else:
+ lines_out.append(line)
+ file(tagpath, "wb").write("".join(lines_out).encode("utf-8"))
+
def _add_project_code(self, path):
# http://mwolson.org/projects/GettingStartedWithArch.html
- # http://regexps.srparish.net/tutorial-tla/importing-first.html#Importing_the_First_Revision
- self._u_invoke_client("init-tree", self._archive_project_name(),
+ # http://regexps.srparish.net/tutorial-tla/new-source.html
+ # http://regexps.srparish.net/tutorial-tla/importing-first.html
+ self._invoke_client("init-tree", self._project_name,
directory=path)
+ self._adjust_naming_conventions(path)
self._invoke_client("import", "--summary", "Began versioning",
directory=path)
def _rcs_cleanup(self):
self._remove_project()
if self._tmp_archive == True:
self._remove_archive()
+
+ def _rcs_root(self, path):
+ if not os.path.isdir(path):
+ dirname = os.path.dirname(path)
+ else:
+ dirname = path
+ status,output,error = self._u_invoke_client("tree-root", dirname)
+ root = output.rstrip('\n')
+
+ self._get_archive_project_name(root)
+
+ return root
+
+ def _get_archive_name(self, root):
+ status,output,error = self._u_invoke_client("archives")
+ lines = output.split('\n')
+ # e.g. output:
+ # jdoe@example.com--bugs-everywhere-auto-2008.22.24.52
+ # /tmp/BEtestXXXXXX/rootdir
+ # (+ repeats)
+ for archive,location in zip(lines[::2], lines[1::2]):
+ if os.path.realpath(location) == os.path.realpath(root):
+ self._archive_name = archive
+ assert self._archive_name != None
+
+ def _get_archive_project_name(self, root):
+ # get project names
+ status,output,error = self._u_invoke_client("tree-version", directory=root)
+ # e.g output
+ # jdoe@example.com--bugs-everywhere-auto-2008.22.24.52/be--mainline--0.1
+ archive_name,project_name = output.rstrip('\n').split('/')
+ self._archive_name = archive_name
+ self._project_name = project_name
+
def _rcs_get_user_id(self):
try:
status,output,error = self._u_invoke_client('my-id')
import os
import os.path
import errno
-import names
-import mapfile
import time
-import utility
import doctest
+from beuuid import uuid_gen
+import mapfile
+import comment
+import utility
+
+
### Define and describe valid bug categories
# Use a tuple of (category, description) tuples since we don't have
# ordered dicts in Python yet http://www.python.org/dev/peps/pep-0372/
severity = checked_property("severity", severity_values)
status = checked_property("status", status_values)
- def __init__(self, path, uuid, rcs, bugdir):
- self.path = path
- self.uuid = uuid
- if uuid is not None:
- dict = mapfile.map_load(self.get_path("values"))
- else:
- dict = {}
-
- self.rcs = rcs
- self.bugdir = bugdir
-
- self.summary = dict.get("summary")
- self.creator = dict.get("creator")
- self.target = dict.get("target")
- self.status = dict.get("status", "open")
- self.severity = dict.get("severity", "minor")
- self.assigned = dict.get("assigned")
- self.time = dict.get("time")
- if self.time is not None:
- self.time = utility.str_to_time(self.time)
-
- def get_path(self, file=None):
- if file == None:
- return os.path.join(self.path, self.uuid)
- else:
- return os.path.join(self.path, self.uuid, file)
-
def _get_active(self):
return self.status in active_status_values
active = property(_get_active)
+ def __init__(self, bugdir=None, uuid=None, loadNow=False, summary=None):
+ self.bugdir = bugdir
+ if bugdir != None:
+ self.rcs = bugdir.rcs
+ else:
+ self.rcs = None
+ if loadNow == True:
+ self.uuid = uuid
+ self.load()
+ else:
+ # Note: defaults should match those in Bug.load()
+ if uuid != None:
+ self.uuid = uuid
+ else:
+ self.uuid = uuid_gen()
+ self.summary = summary
+ if self.rcs != None:
+ self.creator = self.rcs.get_user_id()
+ else:
+ self.creator = None
+ self.target = None
+ self.status = "open"
+ self.severity = "minor"
+ self.assigned = None
+ self.time = time.time()
+ self.comment_root = comment.Comment(self, uuid=comment.INVALID_UUID)
+
def __repr__(self):
return "Bug(uuid=%r)" % self.uuid
- def string(self, bugs=None, shortlist=False):
- if bugs == None:
- bugs = list(self.bugdir.list())
- short_name = names.unique_name(self, bugs)
+ def string(self, shortlist=False, show_comments=False):
+ if self.bugdir == None:
+ shortname = self.uuid
+ else:
+ shortname = self.bugdir.bug_shortname(self)
if shortlist == False:
if self.time == None:
timestring = ""
ftime = utility.time_to_str(self.time)
timestring = "%s (%s)" % (htime, ftime)
info = [("ID", self.uuid),
- ("Short name", short_name),
+ ("Short name", shortname),
("Severity", self.severity),
("Status", self.status),
("Assigned", self.assigned),
info = newinfo
longest_key_len = max([len(k) for k,v in info])
infolines = [" %*s : %s\n" %(longest_key_len,k,v) for k,v in info]
- return "".join(infolines) + "%s\n" % self.summary
+ bugout = "".join(infolines) + "%s" % self.summary.rstrip('\n')
else:
statuschar = self.status[0]
severitychar = self.severity[0]
chars = "%c%c" % (statuschar, severitychar)
- return "%s:%s: %s" % (short_name, chars, self.summary)
+ bugout = "%s:%s: %s" % (shortname, chars, self.summary.rstrip('\n'))
+
+ if show_comments == True:
+ comout = self.comment_root.string_thread(auto_name_map=True,
+ bug_shortname=shortname)
+ output = bugout + '\n' + comout.rstrip('\n')
+ else :
+ output = bugout
+ return output
def __str__(self):
return self.string(shortlist=True)
def __cmp__(self, other):
return cmp_full(self, other)
- def add_attr(self, map, name):
+ def get_path(self, name=None):
+ my_dir = os.path.join(self.bugdir.get_path("bugs"), self.uuid)
+ if name is None:
+ return my_dir
+ assert name in ["values", "comments"]
+ return os.path.join(my_dir, name)
+
+ def load(self):
+ map = mapfile.map_load(self.get_path("values"))
+ self.summary = map.get("summary")
+ self.creator = map.get("creator")
+ self.target = map.get("target")
+ self.status = map.get("status", "open")
+ self.severity = map.get("severity", "minor")
+ self.assigned = map.get("assigned")
+ self.time = map.get("time")
+ if self.time is not None:
+ self.time = utility.str_to_time(self.time)
+
+ self.comment_root = comment.loadComments(self)
+
+ def _add_attr(self, map, name):
value = getattr(self, name)
if value is not None:
map[name] = value
def save(self):
assert self.summary != None, "Can't save blank bug"
map = {}
- self.add_attr(map, "assigned")
- self.add_attr(map, "summary")
- self.add_attr(map, "creator")
- self.add_attr(map, "target")
- self.add_attr(map, "status")
- self.add_attr(map, "severity")
+ self._add_attr(map, "assigned")
+ self._add_attr(map, "summary")
+ self._add_attr(map, "creator")
+ self._add_attr(map, "target")
+ self._add_attr(map, "status")
+ self._add_attr(map, "severity")
if self.time is not None:
map["time"] = utility.time_to_str(self.time)
+
+ self.rcs.mkdir(self.get_path())
path = self.get_path("values")
mapfile.map_save(self.rcs, path, map)
+ if len(self.comment_root) > 0:
+ self.rcs.mkdir(self.get_path("comments"))
+ comment.saveComments(self)
+
def remove(self):
+ self.comment_root.remove()
path = self.get_path()
self.rcs.recursive_remove(path)
def new_comment(self, body=None):
- if not os.path.exists(self.get_path("comments")):
- self.rcs.mkdir(self.get_path("comments"))
- comm = Comment(None, self)
- comm.uuid = names.uuid()
- comm.rcs = self.rcs
- comm.From = self.rcs.get_user_id()
- comm.time = time.time()
- comm.body = body
+ comm = comment.comment_root.new_reply(body=body)
return comm
- def get_comment(self, uuid):
- return Comment(uuid, self)
-
- def iter_comment_ids(self):
- path = self.get_path("comments")
- if not os.path.isdir(path):
- return
- try:
- for uuid in os.listdir(path):
- if (uuid.startswith('.')):
- continue
- yield uuid
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- return
-
- def list_comments(self):
- comments = [Comment(id, self) for id in self.iter_comment_ids()]
- comments.sort(cmp_time)
- return comments
-
-def add_headers(obj, map, names):
- map_names = {}
- for name in names:
- map_names[name] = pyname_to_header(name)
- add_attrs(obj, map, names, map_names)
-
-def add_attrs(obj, map, names, map_names=None):
- if map_names is None:
- map_names = {}
- for name in names:
- map_names[name] = name
-
- for name in names:
- value = getattr(obj, name)
- if value is not None:
- map[map_names[name]] = value
-
-
-class Comment(object):
- def __init__(self, uuid, bug):
- object.__init__(self)
- self.uuid = uuid
- self.bug = bug
- if self.uuid is not None and self.bug is not None:
- map = mapfile.map_load(self.get_path("values"))
- self.time = utility.str_to_time(map["Date"])
- self.From = map["From"]
- self.in_reply_to = map.get("In-reply-to")
- self.content_type = map.get("Content-type", "text/plain")
- self.body = file(self.get_path("body")).read().decode("utf-8")
- else:
- self.time = None
- self.From = None
- self.in_reply_to = None
- self.content_type = "text/plain"
- self.body = None
+ def comment_from_shortname(self, shortname, *args, **kwargs):
+ return self.comment_root.comment_from_shortname(shortname, *args, **kwargs)
- def save(self):
- map_file = {"Date": utility.time_to_str(self.time)}
- add_headers(self, map_file, ("From", "in_reply_to", "content_type"))
- if not os.path.exists(self.get_path()):
- self.bug.rcs.mkdir(self.get_path())
- mapfile.map_save(self.bug.rcs, self.get_path("values"), map_file)
- self.bug.rcs.set_file_contents(self.get_path("body"),
- self.body.encode('utf-8'))
-
- def get_path(self, name=None):
- my_dir = os.path.join(self.bug.get_path("comments"), self.uuid)
- if name is None:
- return my_dir
- return os.path.join(my_dir, name)
-
-
-def thread_comments(comments):
- child_map = {}
- top_comments = []
- for comment in comments:
- child_map[comment.uuid] = []
- for comment in comments:
- if comment.in_reply_to is None or comment.in_reply_to not in child_map:
- top_comments.append(comment)
- continue
- child_map[comment.in_reply_to].append(comment)
-
- def recurse_children(comment):
- child_list = []
- for child in child_map[comment.uuid]:
- child_list.append(recurse_children(child))
- return (comment, child_list)
- return [recurse_children(c) for c in top_comments]
-
-def pyname_to_header(name):
- return name.capitalize().replace('_', '-')
+ def comment_from_uuid(self, uuid):
+ return self.comment_root.comment_from_uuid(uuid)
-
-class MockBug:
- def __init__(self, attr, value):
- setattr(self, attr, value)
-
# the general rule for bug sorting is that "more important" bugs are
# less than "less important" bugs. This way sorting a list of bugs
# will put the most important bugs first in the list. When relative
def cmp_severity(bug_1, bug_2):
"""
- Compare the severity levels of two bugs, with more severe bugs comparing
- as less.
-
- >>> attr="severity"
- >>> cmp_severity(MockBug(attr,"wishlist"), MockBug(attr,"wishlist")) == 0
+ Compare the severity levels of two bugs, with more severe bugs
+ comparing as less.
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.severity = bugB.severity = "wishlist"
+ >>> cmp_severity(bugA, bugB) == 0
True
- >>> cmp_severity(MockBug(attr,"wishlist"), MockBug(attr,"minor")) > 0
+ >>> bugB.severity = "minor"
+ >>> cmp_severity(bugA, bugB) > 0
True
- >>> cmp_severity(MockBug(attr,"critical"), MockBug(attr,"wishlist")) < 0
+ >>> bugA.severity = "critical"
+ >>> cmp_severity(bugA, bugB) < 0
True
"""
+ if not hasattr(bug_2, "severity") :
+ return 1
return -cmp(severity_index[bug_1.severity], severity_index[bug_2.severity])
def cmp_status(bug_1, bug_2):
"""
Compare the status levels of two bugs, with more 'open' bugs
comparing as less.
-
- >>> attr="status"
- >>> cmp_status(MockBug(attr,"open"), MockBug(attr,"open")) == 0
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.status = bugB.status = "open"
+ >>> cmp_status(bugA, bugB) == 0
True
- >>> cmp_status(MockBug(attr,"open"), MockBug(attr,"closed")) < 0
+ >>> bugB.status = "closed"
+ >>> cmp_status(bugA, bugB) < 0
True
- >>> cmp_status(MockBug(attr,"closed"), MockBug(attr,"open")) > 0
+ >>> bugA.status = "fixed"
+ >>> cmp_status(bugA, bugB) > 0
True
"""
+ if not hasattr(bug_2, "status") :
+ return 1
val_2 = status_index[bug_2.status]
return cmp(status_index[bug_1.status], status_index[bug_2.status])
comparison rule for that attribute type. If invert == True, sort
*against* that convention.
>>> attr="severity"
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,2), attr, invert=False) < 0
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.severity = "critical"
+ >>> bugB.severity = "wishlist"
+ >>> cmp_attr(bugA, bugB, attr) < 0
True
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,2), attr, invert=True) > 0
+ >>> cmp_attr(bugA, bugB, attr, invert=True) > 0
True
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,1), attr) == 0
+ >>> bugB.severity = "critical"
+ >>> cmp_attr(bugA, bugB, attr) == 0
True
"""
+ if not hasattr(bug_2, attr) :
+ return 1
if invert == True :
return -cmp(getattr(bug_1, attr), getattr(bug_2, attr))
else :
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
import os.path
-import cmdutil
import errno
+import time
import unittest
import doctest
-import names
+
+from beuuid import uuid_gen
import mapfile
-import time
+import bug
+import cmdutil
import utility
-from rcs import rcs_by_name, installed_rcs
-from bug import Bug
+from rcs import rcs_by_name, detect_rcs, installed_rcs, PathNotInRoot
class NoBugDir(Exception):
def __init__(self, path):
Exception.__init__(self, msg)
self.path = path
-
-def iter_parent_dirs(cur_dir):
- cur_dir = os.path.realpath(cur_dir)
- old_dir = None
- while True:
- yield cur_dir
- old_dir = cur_dir
- cur_dir = os.path.normpath(os.path.join(cur_dir, '..'))
- if old_dir == cur_dir:
- break;
-
-
-def tree_root(dir, old_version=False):
- for rootdir in iter_parent_dirs(dir):
- versionfile=os.path.join(rootdir, ".be", "version")
- if os.path.exists(versionfile):
- if not old_version:
- test_version(versionfile)
- return BugDir(os.path.join(rootdir, ".be"))
- elif not os.path.exists(rootdir):
- raise NoRootEntry(rootdir)
- old_rootdir = rootdir
- rootdir=os.path.join('..', rootdir)
-
- raise NoBugDir(dir)
-
-class BadTreeVersion(Exception):
- def __init__(self, version):
- Exception.__init__(self, "Unsupported tree version: %s" % version)
- self.version = version
-
-def test_version(path):
- tree_version = file(path, "rb").read()
- if tree_version != TREE_VERSION_STRING:
- raise BadTreeVersion(tree_version)
-
-def set_version(path, rcs):
- rcs.set_file_contents(os.path.join(path, "version"), TREE_VERSION_STRING)
-
-
-TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n"
-
class NoRootEntry(Exception):
def __init__(self, path):
self.path = path
Exception.__init__(self,
"Specified root is already initialized: %s" % path)
-def bugdir_root(versioning_root):
- return os.path.join(versioning_root, ".be")
+class InvalidValue(ValueError):
+ def __init__(self, name, value):
+ msg = "Cannot assign value %s to %s" % (value, name)
+ Exception.__init__(self, msg)
+ self.name = name
+ self.value = value
+
-def create_bug_dir(path, rcs):
- """
- >>> import tests
- >>> rcs = rcs_by_name("None")
- >>> create_bug_dir('/highly-unlikely-to-exist', rcs)
- Traceback (most recent call last):
- NoRootEntry: Specified root does not exist: /highly-unlikely-to-exist
- """
- root = os.path.join(path, ".be")
- try:
- rcs.mkdir(root)
- except OSError, e:
- if e.errno == errno.ENOENT:
- raise NoRootEntry(path)
- elif e.errno == errno.EEXIST:
- raise AlreadyInitialized(path)
- else:
- raise
- rcs.mkdir(os.path.join(root, "bugs"))
- set_version(root, rcs)
- mapfile.map_save(rcs,
- os.path.join(root, "settings"), {"rcs_name": rcs.name})
- return BugDir(bugdir_root(path))
+TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n"
def setting_property(name, valid=None):
del self.settings[name]
else:
self.settings[name] = value
- self.save_settings()
+ self.save()
return property(getter, setter)
-class BugDir:
- def __init__(self, dir):
- self.dir = dir
- self.bugs_path = os.path.join(self.dir, "bugs")
+class BugDir (list):
+ def __init__(self, root=None, sink_to_existing_root=True,
+ assert_new_BugDir=False, allow_rcs_init=False,
+ loadNow=False, rcs=None):
+ list.__init__(self)
+ if root == None:
+ root = os.getcwd()
+ if sink_to_existing_root == True:
+ self.root = self.find_root(root)
+ else:
+ if not os.path.exists(root):
+ raise NoRootEntry(root)
+ self.root = root
+ if loadNow == True:
+ self.load()
+ else:
+ if assert_new_BugDir:
+ if os.path.exists(self.get_path()):
+ raise AlreadyInitialized, self.get_path()
+ if rcs == None:
+ rcs = self.guess_rcs(allow_rcs_init)
+ self.settings = {"rcs_name": self.rcs_name}
+ self.rcs_name = rcs.name
+
+ def find_root(self, path):
+ """
+ Search for an existing bug database dir and it's ancestors and
+ return a BugDir rooted there.
+ """
+ if not os.path.exists(path):
+ raise NoRootEntry(path)
+ versionfile = utility.search_parent_directories(path, os.path.join(".be", "version"))
+ if versionfile != None:
+ beroot = os.path.dirname(versionfile)
+ root = os.path.dirname(beroot)
+ return root
+ else:
+ beroot = utility.search_parent_directories(path, ".be")
+ if beroot == None:
+ raise NoBugDir(path)
+ return beroot
+
+ def get_version(self, path=None):
+ if path == None:
+ path = self.get_path("version")
try:
- self.settings = mapfile.map_load(os.path.join(self.dir,"settings"))
- except mapfile.NoSuchFile:
- self.settings = {"rcs_name": "None"}
+ tree_version = self.rcs.get_file_contents(path)
+ except AttributeError, e:
+ # haven't initialized rcs yet
+ tree_version = file(path, "rb").read().decode("utf-8")
+ return tree_version
+
+ def set_version(self):
+ self.rcs.set_file_contents(self.get_path("version"), TREE_VERSION_STRING)
rcs_name = setting_property("rcs_name",
("None", "bzr", "git", "Arch", "hg"))
- _rcs = None
- target = setting_property("target")
-
- def save_settings(self):
- mapfile.map_save(self.rcs,
- os.path.join(self.dir, "settings"), self.settings)
+ _rcs = None
def _get_rcs(self):
if self._rcs is not None:
if self.rcs_name == self._rcs.name:
return self._rcs
self._rcs = rcs_by_name(self.rcs_name)
- self._rcs.root(self.dir)
+ self._rcs.root(self.root)
return self._rcs
rcs = property(_get_rcs)
+ target = setting_property("target")
+
+ def get_path(self, *args):
+ my_dir = os.path.join(self.root, ".be")
+ if len(args) == 0:
+ return my_dir
+ assert args[0] in ["version", "settings", "bugs"], str(args)
+ return os.path.join(my_dir, *args)
+
+ def guess_rcs(self, allow_rcs_init=False):
+ deepdir = self.get_path()
+ if not os.path.exists(deepdir):
+ deepdir = os.path.dirname(deepdir)
+ rcs = detect_rcs(deepdir)
+ if rcs.name == "None":
+ if allow_rcs_init == True:
+ rcs = installed_rcs()
+ rcs.init(self.root)
+ self.settings = {"rcs_name": rcs.name}
+ self.rcs_name = rcs.name
+ return rcs
+
+ def load(self):
+ version = self.get_version()
+ if version != TREE_VERSION_STRING:
+ raise NotImplementedError, "BugDir cannot handle version '%s' yet." % version
+ else:
+ if not os.path.exists(self.get_path()):
+ raise NoBugDir(self.get_path())
+ self.settings = self._get_settings(self.get_path("settings"))
+ self._clear_bugs()
+ for uuid in self.list_uuids():
+ self._load_bug(uuid)
+
+ self._bug_map_gen()
+
+ def save(self):
+ self.rcs.mkdir(self.get_path())
+ self.set_version()
+ self._save_settings(self.get_path("settings"), self.settings)
+ self.rcs.mkdir(self.get_path("bugs"))
+ for bug in self:
+ bug.save()
+
+ def _get_settings(self, settings_path):
+ try:
+ settings = mapfile.map_load(settings_path)
+ except mapfile.NoSuchFile:
+ settings = {"rcs_name": "None"}
+ return settings
+
+ def _save_settings(self, settings_path, settings):
+ try:
+ mapfile.map_save(self.rcs, settings_path, settings)
+ except PathNotInRoot, e:
+ # Handling duplicate bugdir settings, special case
+ none_rcs = rcs_by_name("None")
+ none_rcs.root(settings_path)
+ mapfile.map_save(none_rcs, settings_path, settings)
+
def duplicate_bugdir(self, revision):
- return BugDir(bugdir_root(self.rcs.duplicate_repo(revision)))
+ duplicate_path = self.rcs.duplicate_repo(revision)
- def remove_duplicate_bugdir(self):
- self.rcs.remove_duplicate_repo()
+ # setup revision RCS as None, since the duplicate may not be versioned
+ duplicate_settings_path = os.path.join(duplicate_path, ".be", "settings")
+ duplicate_settings = self._get_settings(duplicate_settings_path)
+ if "rcs_name" in duplicate_settings:
+ duplicate_settings["rcs_name"] = "None"
+ self._save_settings(duplicate_settings_path, duplicate_settings)
- def list(self):
- for uuid in self.list_uuids():
- yield self.get_bug(uuid)
+ return BugDir(duplicate_path, loadNow=True)
- def bug_map(self):
- bugs = {}
- for bug in self.list():
- bugs[bug.uuid] = bug
- return bugs
+ def remove_duplicate_bugdir(self):
+ self.rcs.remove_duplicate_repo()
- def get_bug(self, uuid):
- return Bug(self.bugs_path, uuid, self.rcs, self)
+ def _bug_map_gen(self):
+ map = {}
+ for bug in self:
+ map[bug.uuid] = bug
+ self.bug_map = map
def list_uuids(self):
- for uuid in os.listdir(self.bugs_path):
+ for uuid in os.listdir(self.get_path("bugs")):
if (uuid.startswith('.')):
continue
yield uuid
- def new_bug(self, uuid=None):
- if uuid is None:
- uuid = names.uuid()
- path = os.path.join(self.bugs_path, uuid)
- self.rcs.mkdir(path)
- bug = Bug(self.bugs_path, None, self.rcs, self)
- bug.uuid = uuid
- bug.creator = self.rcs.get_user_id()
- bug.severity = "minor"
- bug.status = "open"
- bug.time = time.time()
- return bug
+ def _clear_bugs(self):
+ while len(self) > 0:
+ self.pop()
+
+ def _load_bug(self, uuid):
+ bg = bug.Bug(bugdir=self, uuid=uuid, loadNow=True)
+ self.append(bg)
+ self._bug_map_gen()
+ return bg
+
+ def new_bug(self, uuid=None, summary=None):
+ bg = bug.Bug(bugdir=self, uuid=uuid, summary=summary)
+ self.append(bg)
+ self._bug_map_gen()
+ return bg
+
+ def remove_bug(self, bug):
+ self.remove(bug)
+ bug.remove()
+
+ def bug_shortname(self, bug):
+ """
+ Generate short names from uuids. Picks the minimum number of
+ characters (>=3) from the beginning of the uuid such that the
+ short names are unique.
+
+ Obviously, as the number of bugs in the database grows, these
+ short names will cease to be unique. The complete uuid should be
+ used for long term reference.
+ """
+ chars = 3
+ for uuid in self.bug_map.keys():
+ if bug.uuid == uuid:
+ continue
+ while (bug.uuid[:chars] == uuid[:chars]):
+ chars+=1
+ return bug.uuid[:chars]
+
+ def bug_from_shortname(self, shortname):
+ """
+ >>> bd = simple_bug_dir()
+ >>> bug_a = bd.bug_from_shortname('a')
+ >>> print type(bug_a)
+ <class 'libbe.bug.Bug'>
+ >>> print bug_a
+ a:om: Bug A
+ """
+ matches = []
+ for bug in self:
+ if bug.uuid.startswith(shortname):
+ matches.append(bug)
+ if len(matches) > 1:
+ raise cmdutil.UserError("More than one bug matches %s. Please be more"
+ " specific." % shortname)
+ if len(matches) == 1:
+ return matches[0]
+ raise KeyError("No bug matches %s" % shortname)
+
+ def bug_from_uuid(self, uuid):
+ if uuid not in self.bug_map:
+ self._bug_map_gen()
+ if uuid not in self.bug_map:
+ raise KeyError("No bug matches %s" % uuid +str(self.bug_map)+str(self))
+ return self.bug_map[uuid]
-class InvalidValue(ValueError):
- def __init__(self, name, value):
- msg = "Cannot assign value %s to %s" % (value, name)
- Exception.__init__(self, msg)
- self.name = name
- self.value = value
def simple_bug_dir():
"""
['a', 'b']
"""
dir = utility.Dir()
- rcs = installed_rcs()
- rcs.init(dir.path)
assert os.path.exists(dir.path)
- bugdir = create_bug_dir(dir.path, rcs)
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
bugdir._dir_ref = dir # postpone cleanup since dir.__del__() removes dir.
- bug_a = bugdir.new_bug("a")
- bug_a.summary = "Bug A"
- bug_a.save()
- bug_b = bugdir.new_bug("b")
+ bug_a = bugdir.new_bug("a", summary="Bug A")
+ bug_a.creator = "John Doe <jdoe@example.com>"
+ bug_a.time = 0
+ bug_b = bugdir.new_bug("b", summary="Bug B")
+ bug_b.creator = "Jane Doe <jdoe@example.com>"
+ bug_b.time = 0
bug_b.status = "closed"
- bug_b.summary = "Bug B"
- bug_b.save()
+ bugdir.save()
return bugdir
unittest.TestCase.__init__(self, *args, **kwargs)
def setUp(self):
self.dir = utility.Dir()
- self.rcs = installed_rcs()
- self.rcs.init(self.dir.path)
- self.bugdir = create_bug_dir(self.dir.path, self.rcs)
+ self.bugdir = BugDir(self.dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ self.rcs = self.bugdir.rcs
def tearDown(self):
del(self.rcs)
del(self.dir)
fullpath = self.fullPath(path)
self.failUnless(os.path.exists(fullpath)==True,
"path %s does not exist" % fullpath)
- def testBugDirDuplicate(self):
- self.assertRaises(AlreadyInitialized, create_bug_dir,
- self.dir.path, self.rcs)
+ self.assertRaises(AlreadyInitialized, BugDir,
+ self.dir.path, assertNewBugDir=True)
unitsuite = unittest.TestLoader().loadTestsFromTestCase(BugDirTestCase)
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
# 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
-import bugdir
-import plugin
-import locale
-import os
import optparse
+import os
+import locale
from textwrap import TextWrapper
from StringIO import StringIO
-import utility
import doctest
+import bugdir
+import plugin
+import utility
+
class UserError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
UserError.__init__(self, str(exception))
self.exception = exception
-def get_bug(spec, bug_dir=None):
- """
- >>> bd = bugdir.simple_bug_dir()
- >>> bug_a = get_bug('a', bd)
- >>> print type(bug_a)
- <class 'libbe.bug.Bug'>
- >>> print bug_a
- a:om: Bug A
- >>> print bd.get_bug('a')
- a:om: Bug A
- >>> bug_a == bd.get_bug('a')
- True
- """
- matches = []
- try:
- if bug_dir is None:
- bug_dir = bugdir.tree_root('.')
- except bugdir.NoBugDir, e:
- raise UserErrorWrap(e)
- bugs = list(bug_dir.list())
- for bug in bugs:
- if bug.uuid.startswith(spec):
- matches.append(bug)
- if len(matches) > 1:
- raise UserError("More than one bug matches %s. Please be more"
- " specific." % spec)
- if len(matches) == 1:
- return matches[0]
-
- matches = []
- if len(matches) == 0:
- raise UserError("No bug matches %s" % spec)
- return matches[0]
-
def iter_commands():
for name, module in plugin.iter_plugins("becommands"):
yield name.replace("_", "-"), module
def raise_get_help(option, opt, value, parser):
raise GetHelp
-
-def iter_comment_name(bug, unique_name):
- """Iterate through id, comment pairs, in date order.
- (This is a user-friendly id, not the comment uuid)
- """
- def key(comment):
- return comment.time
- for num, comment in enumerate(sorted(bug.list_comments(), key=key)):
- yield ("%s:%d" % (unique_name, num+1), comment)
-
-
-def comment_from_name(bug, unique_name, name):
- """Use a comment name to look up a comment"""
- for cur_name, comment in iter_comment_name(bug, unique_name):
- if name == cur_name:
- return comment
- raise KeyError(name)
-
-
-def get_bug_and_comment(identifier, bug_dir=None):
- ids = identifier.split(':')
- bug = get_bug(ids[0], bug_dir)
- if len(ids) == 2:
- comment = comment_from_name(bug, ids[0], identifier)
- else:
- comment = None
- return bug, comment
-
class CmdOptionParser(optparse.OptionParser):
def __init__(self, usage):
return "%s\n%s" % (instring, "="*len(instring))
-def print_threaded_comments(comments, name_map, indent=""):
- """Print a threaded display of comments"""
- tw = TextWrapper(initial_indent = indent, subsequent_indent = indent,
- width=80)
- for comment, children in comments:
- s = StringIO()
- print >> s, "--------- Comment ---------"
- print >> s, "Name: %s" % name_map[comment.uuid]
- print >> s, "From: %s" % comment.From
- print >> s, "Date: %s\n" % utility.time_to_str(comment.time)
- print >> s, comment.body.rstrip('\n')
-
- s.seek(0)
- for line in s:
- print tw.fill(line).rstrip('\n')
- print_threaded_comments(children, name_map, indent=indent+" ")
-
-
-def bug_tree(dir=None):
- """Retrieve the bug tree specified by the user. If no directory is
- specified, the current working directory is used.
-
- :param dir: The directory to search for the bug tree in.
-
- >>> bug_tree() is not None
- True
- >>> bug_tree("/")
- Traceback (most recent call last):
- UserErrorWrap: The directory "/" has no bug directory.
- """
- if dir is None:
- dir = os.getcwd()
- try:
- return bugdir.tree_root(dir)
- except bugdir.NoBugDir, e:
- raise UserErrorWrap(e)
-
-
def _test():
import doctest
import sys
from libbe.bug import cmp_severity
import doctest
-def diff(old_tree, new_tree):
- old_bug_map = old_tree.bug_map()
- new_bug_map = new_tree.bug_map()
+def diff(old_bugdir, new_bugdir):
added = []
removed = []
modified = []
- for old_bug in old_bug_map.itervalues():
- new_bug = new_bug_map.get(old_bug.uuid)
+ for old_bug in old_bugdir:
+ new_bug = new_bugdir.bug_map.get(old_bug.uuid)
if new_bug is None :
removed.append(old_bug)
else:
if old_bug != new_bug:
modified.append((old_bug, new_bug))
- for new_bug in new_bug_map.itervalues():
- if not old_bug_map.has_key(new_bug.uuid):
+ for new_bug in new_bugdir:
+ if not old_bugdir.bug_map.has_key(new_bug.uuid):
added.append(new_bug)
return (removed, modified, added)
-
-def reference_diff(bugdir, revision=None):
- d = diff(bugdir.duplicate_bugdir(revision), bugdir)
- bugdir.remove_duplicate_bugdir()
- return d
-
def diff_report(diff_data, bug_dir):
(removed, modified, added) = diff_data
- bugs = list(bug_dir.list())
def modified_cmp(left, right):
return cmp_severity(left[1], right[1])
removed.sort(cmp_severity)
modified.sort(modified_cmp)
- if len(added) > 0:
+ if len(added) > 0:
print "New bug reports:"
for bug in added:
print bug.string(shortlist=True)
if len(modified) > 0:
printed = False
for old_bug, new_bug in modified:
- change_str = bug_changes(old_bug, new_bug, bugs)
+ change_str = bug_changes(old_bug, new_bug, bug_dir)
if change_str is None:
continue
if not printed:
if len(removed) > 0:
print "Removed bug reports:"
for bug in removed:
- print bug.string(bugs, shortlist=True)
+ print bug.string(shortlist=True)
def change_lines(old, new, attributes):
change_list = []
change_list = change_lines(old, new, ("time", "creator", "severity",
"target", "summary", "status", "assigned"))
- old_comment_ids = list(old.iter_comment_ids())
- new_comment_ids = list(new.iter_comment_ids())
+ old_comment_ids = [c.uuid for c in old.comment_root.traverse()]
+ new_comment_ids = [c.uuid for c in new.comment_root.traverse()]
change_strings = ["%s: %s -> %s" % f for f in change_list]
for comment_id in new_comment_ids:
if comment_id not in old_comment_ids:
if len(change_strings) == 0:
return None
- return "%s%s\n" % (new.string(bugs, shortlist=True),
- "\n".join(change_strings))
+ return "%s\n %s" % (new.string(shortlist=True),
+ " \n".join(change_strings))
def comment_summary(comment, status):
f = utility.get_file(f)
result = {}
for line in f:
- line = line.rstrip('\n')
+ line = line.decode("utf-8").rstrip('\n')
if len(line) == 0:
continue
- name,value = [f.decode('utf-8') for f in line.split('=', 1)]
- assert not result.has_key('name')
+ name,value = [f for f in line.split('=', 1)]
+ assert not result.has_key(name)
result[name] = value
return result
+++ /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
-
-import os
-import sys
-import doctest
-
-def uuid():
- # this code borrowed from standard commands module
- # but adapted to win32
- pipe = os.popen('uuidgen', 'r')
- text = pipe.read()
- sts = pipe.close()
- if sts not in (0, None):
- raise "Failed to run uuidgen"
- if text[-1:] == '\n': text = text[:-1]
- return text
-
-def unique_name(bug, bugs):
- """
- Generate short names from uuids. Picks the minimum number of
- characters (>=3) from the beginning of the uuid such that the
- short names are unique.
-
- Obviously, as the number of bugs in the database grows, these
- short names will cease to be unique. The complete uuid should be
- used for long term reference.
- """
- chars = 3
- for some_bug in bugs:
- if bug.uuid == some_bug.uuid:
- continue
- while (bug.uuid[:chars] == some_bug.uuid[:chars]):
- chars+=1
- return bug.uuid[:chars]
-
-suite = doctest.DocTestSuite()
modfiles = os.listdir(os.path.join(plugin_path, prefix))
modfiles.sort()
for modfile in modfiles:
+ if modfile.startswith('.'):
+ continue # the occasional emacs temporary file
if modfile.endswith(".py") and modfile != "__init__.py":
yield modfile[:-3], my_import(prefix+"."+modfile[:-3])
import shutil
import unittest
import doctest
-from utility import Dir
+from utility import Dir, search_parent_directories
def _get_matching_rcs(matchfn):
"""Return the first module for which matchfn(RCS_instance) is true"""
import bzr
import hg
import git
- for module in [arch, bzr, hg, git]:
+ for module in [git, arch, bzr, hg, git]:
rcs = module.new()
- if matchfn(rcs):
+ if matchfn(rcs) == True:
return rcs
else:
del(rcs)
class SettingIDnotSupported(NotImplementedError):
pass
+class PathNotInRoot(Exception):
+ pass
+
def new():
return RCS()
pass
def _rcs_get_file_contents(self, path, revision=None):
"""
- Get the file as it was in a given revision.
+ Get the file contents as they were in a given revision. Don't
+ worry about decoding the contents, the RCS.get_file_contents()
+ method will handle that.
+
Revision==None specifies the current revision.
"""
assert revision == None, \
if e.errno == errno.ENOENT:
return False
raise e
- def detect(self, path=None):
+ def detect(self, path="."):
"""
Detect whether a directory is revision controlled with this RCS.
"""
Revision==None specifies the current revision.
"""
relpath = self._u_rel_path(path)
- return self._rcs_get_file_contents(relpath, revision)
+ return self._rcs_get_file_contents(relpath, revision).decode("utf-8")
def set_file_contents(self, path, contents):
"""
Set the file contents under version control.
"""
add = not os.path.exists(path)
- file(path, "wb").write(contents)
+ file(path, "wb").write(contents.encode("utf-8"))
if add:
self.add(path)
else:
self.update(path)
def mkdir(self, path):
"""
- Created directory at path under version control.
+ Create (if neccessary) a directory at path under version
+ control.
"""
- os.mkdir(path)
- self.add(path)
+ if not os.path.exists(path):
+ os.mkdir(path)
+ self.add(path)
+ else:
+ assert os.path.isdir(path)
+ self.update(path)
def duplicate_repo(self, revision=None):
"""
Get the repository as it was in a given revision.
/.be
or None if none of those files exist.
"""
- path = os.path.realpath(path)
- assert os.path.exists(path)
- old_path = None
- while True:
- if os.path.exists(os.path.join(path, filename)):
- return os.path.join(path, filename)
- if path == old_path:
- return None
- old_path = path
- path = os.path.dirname(path)
+ return search_parent_directories(path, filename)
def _u_rel_path(self, path, root=None):
"""
Return the relative path to path from root.
if os.path.isabs(path):
absRoot = os.path.abspath(root)
absRootSlashedDir = os.path.join(absRoot,"")
- assert path.startswith(absRootSlashedDir), \
- "file %s not in root %s" % (path, absRootSlashedDir)
+ if not path.startswith(absRootSlashedDir):
+ raise PathNotInRoot, \
+ "file %s not in root %s" % (path, absRootSlashedDir)
assert path != absRootSlashedDir, \
"file %s == root directory %s" % (path, absRootSlashedDir)
path = path[len(absRootSlashedDir):]
else:
return f
+def search_parent_directories(path, filename):
+ """
+ Find the file (or directory) named filename in path or in any
+ of path's parents.
+
+ e.g.
+ search_parent_directories("/a/b/c", ".be")
+ will return the path to the first existing file from
+ /a/b/c/.be
+ /a/b/.be
+ /a/.be
+ /.be
+ or None if none of those files exist.
+ """
+ path = os.path.realpath(path)
+ assert os.path.exists(path)
+ old_path = None
+ while True:
+ check_path = os.path.join(path, filename)
+ if os.path.exists(check_path):
+ return check_path
+ if path == old_path:
+ return None
+ old_path = path
+ path = os.path.dirname(path)
+
class Dir:
"A temporary directory for testing use"
def __init__(self):
-"""Usage: python test.py [module]
+"""Usage: python test.py [module(s) ...]
-When called without an optional module name, run the doctests from
-*all* modules. This may raise lots of errors if you haven't installed
-one of the versioning control systems.
+When called without optional module names, run the doctests from *all*
+modules. This may raise lots of errors if you haven't installed one
+of the versioning control systems.
-When called with an optional module name, only run the doctests from
-that module.
+When called with module name arguments, only run the doctests from
+those modules.
"""
from libbe import plugin
suite = unittest.TestSuite()
if len(sys.argv) > 1:
- submodname = sys.argv[1]
- match = False
- mod = plugin.get_plugin("libbe", submodname)
- if mod is not None and hasattr(mod, "suite"):
- suite.addTest(mod.suite)
- match = True
- mod = plugin.get_plugin("becommands", submodname)
- if mod is not None:
- suite.addTest(doctest.DocTestSuite(mod))
- match = True
- if not match:
- print "No modules match \"%s\"" % submodname
- sys.exit(1)
+ for submodname in sys.argv[1:]:
+ match = False
+ mod = plugin.get_plugin("libbe", submodname)
+ if mod is not None and hasattr(mod, "suite"):
+ suite.addTest(mod.suite)
+ match = True
+ mod = plugin.get_plugin("becommands", submodname)
+ if mod is not None:
+ suite.addTest(doctest.DocTestSuite(mod))
+ match = True
+ if not match:
+ print "No modules match \"%s\"" % submodname
+ sys.exit(1)
else:
failed = False
for modname,module in plugin.iter_plugins("libbe"):