options, args = get_parser().parse_args(args)
if len(args) < 1:
raise cmdutil.UsageError()
- bug = cmdutil.get_bug(args[0])
+ bug, parent_comment = cmdutil.get_bug_and_comment(args[0])
if len(args) == 1:
try:
body = utility.editor_string()
body+='\n'
comment = bugdir.new_comment(bug, body)
+ if parent_comment is not None:
+ comment.in_reply_to = parent_comment.uuid
comment.save()
def get_parser():
- parser = cmdutil.CmdOptionParser("be comment BUG-ID COMMENT")
+ parser = cmdutil.CmdOptionParser("be comment ID COMMENT")
return parser
longhelp="""
-Add a comment to a bug.
+To add a comment to a bug, use the bug ID as the argument. To reply to another
+comment, specify the comment name (as shown in "be show" output).
+
+$EDITOR is used to launch an editor. If unspecified, no comment will be
+created.)
"""
def help():
time_str = "%s (%s)" % (utility.handy_time(bug.time),
utility.time_to_str(bug.time))
print "Created: %s" % time_str
- for comment in bug.list_comments():
- print "--------- Comment ---------"
- print "From: %s" % comment.From
- print "Date: %s\n" % utility.time_to_str(comment.date)
- print comment.body.rstrip('\n')
+ unique_name = cmdutil.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 = bugdir.thread_comments(comments)
+ cmdutil.print_threaded_comments(threaded, name_map)
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)
+ print top_comments
+ return [recurse_children(c) for c in top_comments]
+
+
def pyname_to_header(name):
return name.capitalize().replace('_', '-')
import locale
import os
import optparse
+from textwrap import TextWrapper
+from StringIO import StringIO
import utility
def unique_name(bug, bugs):
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.date
+ 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):
optparse.OptionParser.__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.date)
+ 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.