From ed4a943875d81732bfa3127eb252c2db2e3588f4 Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Thu, 1 Oct 2009 23:39:28 +0200 Subject: Merged with head branch --- becommands/assign.py | 29 +++++++------- becommands/close.py | 23 ++++++----- becommands/comment.py | 102 +++++++++++++++++++++++++++++++++++++++---------- becommands/commit.py | 77 +++++++++++++++++++++++++++++++++++++ becommands/depend.py | 23 ++++++----- becommands/diff.py | 39 ++++++++++--------- becommands/help.py | 23 ++++++----- becommands/init.py | 23 ++++++----- becommands/list.py | 26 ++++++------- becommands/merge.py | 31 ++++++++------- becommands/new.py | 42 +++++++++++--------- becommands/open.py | 24 ++++++------ becommands/remove.py | 24 ++++++------ becommands/set.py | 70 +++++++++++++++++++++------------ becommands/severity.py | 24 ++++++------ becommands/show.py | 82 +++++++++++++++++++++++++++------------ becommands/status.py | 63 ++++++++++++++++++------------ becommands/tag.py | 25 ++++++------ becommands/target.py | 28 +++++++------- 19 files changed, 487 insertions(+), 291 deletions(-) create mode 100644 becommands/commit.py (limited to 'becommands') diff --git a/becommands/assign.py b/becommands/assign.py index 985cfdd..536bca6 100644 --- a/becommands/assign.py +++ b/becommands/assign.py @@ -2,23 +2,22 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Assign an individual or group to fix a bug""" -from libbe import cmdutil, bugdir, settings_object +from libbe import cmdutil, bugdir __desc__ = __doc__ def execute(args, test=False): @@ -26,7 +25,7 @@ def execute(args, test=False): >>> import os >>> bd = bugdir.simple_bug_dir() >>> os.chdir(bd.root) - >>> bd.bug_from_shortname("a").assigned is settings_object.EMPTY + >>> bd.bug_from_shortname("a").assigned is None True >>> execute(["a"], test=True) @@ -41,7 +40,7 @@ def execute(args, test=False): >>> execute(["a","none"], test=True) >>> bd._clear_bugs() - >>> bd.bug_from_shortname("a").assigned is settings_object.EMPTY + >>> bd.bug_from_shortname("a").assigned is None True """ parser = get_parser() diff --git a/becommands/close.py b/becommands/close.py index deaccce..0ba8f50 100644 --- a/becommands/close.py +++ b/becommands/close.py @@ -2,21 +2,20 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Close a bug""" from libbe import cmdutil, bugdir __desc__ = __doc__ diff --git a/becommands/comment.py b/becommands/comment.py index 0b3a576..55b5913 100644 --- a/becommands/comment.py +++ b/becommands/comment.py @@ -1,25 +1,28 @@ # Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc. # Chris Ball # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Add a comment to a bug""" -from libbe import cmdutil, bugdir, settings_object, editor +from libbe import cmdutil, bugdir, comment, editor import os import sys +try: # import core module, Python >= 2.5 + from xml.etree import ElementTree +except ImportError: # look for non-core module + from elementtree import ElementTree __desc__ = __doc__ def execute(args, test=False): @@ -39,7 +42,7 @@ def execute(args, test=False): True >>> comment.time <= int(time.time()) True - >>> comment.in_reply_to is settings_object.EMPTY + >>> comment.in_reply_to is None True >>> if 'EDITOR' in os.environ: @@ -77,7 +80,8 @@ def execute(args, test=False): bugname = shortname is_reply = False - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=not test) bug = bd.bug_from_shortname(bugname) bug.load_comments(load_full=False) if is_reply: @@ -88,7 +92,13 @@ def execute(args, test=False): if len(args) == 1: # try to launch an editor for comment-body entry try: - body = editor.editor_string("Please enter your comment above") + if parent == bug.comment_root: + parent_body = bug.summary+"\n" + else: + parent_body = parent.body + estr = "Please enter your comment above\n\n> %s\n" \ + % ("\n> ".join(parent_body.splitlines())) + body = editor.editor_string(estr) except editor.CantFindEditor, e: raise cmdutil.UserError, "No comment supplied, and EDITOR not specified." if body is None: @@ -108,15 +118,67 @@ def execute(args, test=False): if not body.endswith('\n'): body+='\n' - comment = parent.new_reply(body=body) - if options.content_type != None: - comment.content_type = options.content_type - bd.save() + if options.XML == False: + new = parent.new_reply(body=body) + if options.author != None: + new.From = options.author + if options.alt_id != None: + new.alt_id = options.alt_id + if options.content_type != None: + new.content_type = options.content_type + else: # import XML comment [list] + # read in the comments + str_body = body.encode("unicode_escape").replace(r'\n', '\n') + comment_list = ElementTree.XML(str_body) + if comment_list.tag not in ["bug", "comment-list"]: + raise comment.InvalidXML( + comment_list, "root element must be or ") + new_comments = [] + ids = [] + for c in bug.comment_root.traverse(): + ids.append(c.uuid) + if c.alt_id != None: + ids.append(c.alt_id) + for child in comment_list.getchildren(): + if child.tag == "comment": + new = comment.Comment(bug) + new.from_xml(unicode(ElementTree.tostring(child)).decode("unicode_escape")) + if new.alt_id in ids: + raise cmdutil.UserError( + "Clashing comment alt_id: %s" % new.alt_id) + ids.append(new.uuid) + if new.alt_id != None: + ids.append(new.alt_id) + if new.in_reply_to == None: + new.in_reply_to = parent.uuid + new_comments.append(new) + else: + print >> sys.stderr, "Ignoring unknown tag %s in %s" \ + % (child.tag, comment_list.tag) + try: + comment.list_to_root(new_comments,bug,root=parent, # link new comments + ignore_missing_references=options.ignore_missing_references) + except comment.MissingReference, e: + raise cmdutil.UserError(e) + # Protect against programmer error causing data loss: + kids = [c.uuid for c in parent.traverse()] + for nc in new_comments: + assert nc.uuid in kids, "%s wasn't added to %s" % (nc.uuid, parent.uuid) + nc.save() def get_parser(): parser = cmdutil.CmdOptionParser("be comment ID [COMMENT]") + parser.add_option("-a", "--author", metavar="AUTHOR", dest="author", + help="Set the comment author", default=None) + parser.add_option("--alt-id", metavar="ID", dest="alt_id", + help="Set an alternate comment ID", default=None) parser.add_option("-c", "--content-type", metavar="MIME", dest="content_type", help="Set comment content-type (e.g. text/plain)", default=None) + parser.add_option("-x", "--xml", action="store_true", default=False, + dest='XML', help="Use COMMENT to specify an XML comment description rather than the comment body. The root XML element should be either or with one or more children. The syntax for the elements should match that generated by 'be show --xml COMMENT-ID'. Unrecognized tags are ignored. Missing tags are left at the default value. The comment UUIDs are always auto-generated, so if you set a field, but no field, your will be used as the comment's . An exception is raised if conflicts with an existing comment.") + parser.add_option("-i", "--ignore-missing-references", action="store_true", + dest="ignore_missing_references", + help="For XML import, if any comment's refers to a non-existent comment, ignore it (instead of raising an exception).") return parser longhelp=""" diff --git a/becommands/commit.py b/becommands/commit.py new file mode 100644 index 0000000..4f3bdbd --- /dev/null +++ b/becommands/commit.py @@ -0,0 +1,77 @@ +# Copyright (C) 2009 W. Trevor King +# +# 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. +"""Commit the currently pending changes to the repository""" +from libbe import cmdutil, bugdir, editor, rcs +import sys +__desc__ = __doc__ + +def execute(args, manipulate_encodings=True): + """ + >>> import os, time + >>> from libbe import bug + >>> bd = bugdir.simple_bug_dir() + >>> os.chdir(bd.root) + >>> full_path = "testfile" + >>> test_contents = "A test file" + >>> bd.rcs.set_file_contents(full_path, test_contents) + >>> execute(["Added %s." % (full_path)], manipulate_encodings=False) # doctest: +ELLIPSIS + Committed ... + """ + parser = get_parser() + options, args = parser.parse_args(args) + cmdutil.default_complete(options, args, parser) + if len(args) != 1: + raise cmdutil.UsageError("Please supply a commit message") + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + if args[0] == '-': # read summary from stdin + assert options.body != "EDITOR", \ + "Cannot spawn and editor when the summary is using stdin." + summary = sys.stdin.readline() + else: + summary = args[0] + if options.body == None: + body = None + elif options.body == "EDITOR": + body = editor.editor_string("Please enter your commit message above") + else: + body = bd.rcs.get_file_contents(options.body, allow_no_rcs=True) + try: + revision = bd.rcs.commit(summary, body=body, + allow_empty=options.allow_empty) + except rcs.EmptyCommit, e: + print e + return 1 + else: + print "Committed %s" % revision + +def get_parser(): + parser = cmdutil.CmdOptionParser("be commit COMMENT") + parser.add_option("-b", "--body", metavar="FILE", dest="body", + help='Provide a detailed body for the commit message. In the special case that FILE == "EDITOR", spawn an editor to enter the body text (in which case you cannot use stdin for the summary)', default=None) + parser.add_option("-a", "--allow-empty", dest="allow_empty", + help="Allow empty commits", + default=False, action="store_true") + return parser + +longhelp=""" +Commit the current repository status. The summary specified on the +commandline is a string (only one line) that describes the commit +briefly or "-", in which case the string will be read from stdin. +""" + +def help(): + return get_parser().help_str() + longhelp diff --git a/becommands/depend.py b/becommands/depend.py index 58e4388..4a23b0f 100644 --- a/becommands/depend.py +++ b/becommands/depend.py @@ -1,18 +1,18 @@ # Copyright (C) 2009 W. Trevor King # -# 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 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. +# 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 +# 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. """Add/remove bug dependencies""" from libbe import cmdutil, bugdir import os, copy @@ -58,7 +58,6 @@ def execute(args, test=False): else: # add the dependency estrs.append(depend_string) bugA.extra_strings = estrs # reassign to notice change - bugA.save() depends = [] for estr in bugA.extra_strings: diff --git a/becommands/diff.py b/becommands/diff.py index 2bdea93..13402c0 100644 --- a/becommands/diff.py +++ b/becommands/diff.py @@ -1,20 +1,19 @@ # Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc. # W. Trevor King -# # -# 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 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. +# 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 +# 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 bug reports with older tree""" from libbe import cmdutil, bugdir, diff @@ -25,10 +24,10 @@ def execute(args, test=False): """ >>> import os >>> bd = bugdir.simple_bug_dir() + >>> bd.set_sync_with_disk(True) >>> 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: @@ -38,7 +37,6 @@ def execute(args, test=False): Modified bug reports: a:cm: Bug A status: open -> closed - """ parser = get_parser() options, args = parser.parse_args(args) @@ -54,7 +52,7 @@ def execute(args, test=False): print "This directory is not revision-controlled." else: old_bd = bd.duplicate_bugdir(revision) - r,m,a = diff.diff(old_bd, bd) + r,m,a = diff.bug_diffs(old_bd, bd) optbugs = [] if options.all == True: @@ -69,7 +67,9 @@ def execute(args, test=False): for bug in optbugs: print bug.uuid else : - print diff.diff_report((r,m,a), bd).encode(bd.encoding) + rep = diff.diff_report((r,m,a), old_bd, bd).encode(bd.encoding) + if len(rep) > 0: + print rep bd.remove_duplicate_bugdir() def get_parser(): @@ -89,9 +89,10 @@ def get_parser(): return parser longhelp=""" -Uses the RCS to compare the current tree with a previous tree, and prints -a pretty report. If specifier is given, it is a specifier for the particular -previous tree to use. Specifiers are specific to their RCS. +Uses the RCS to compare the current tree with a previous tree, and +prints a pretty report. If REVISION is given, it is a specifier for +the particular previous tree to use. Specifiers are specific to their +RCS. For Arch your specifier must be a fully-qualified revision name. diff --git a/becommands/help.py b/becommands/help.py index b0b182d..a8ae338 100644 --- a/becommands/help.py +++ b/becommands/help.py @@ -1,21 +1,20 @@ # Copyright (C) 2006-2009 Aaron Bentley and Panometrics, Inc. # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Print help for given subcommand""" from libbe import cmdutil, utility __desc__ = __doc__ diff --git a/becommands/init.py b/becommands/init.py index 390dd15..5b2a416 100644 --- a/becommands/init.py +++ b/becommands/init.py @@ -1,20 +1,19 @@ # Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc. # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Assign the root directory for bug tracking""" import os.path from libbe import cmdutil, bugdir diff --git a/becommands/list.py b/becommands/list.py index 443704b..5ba1821 100644 --- a/becommands/list.py +++ b/becommands/list.py @@ -2,21 +2,20 @@ # Chris Ball # Oleg Romanyshyn # W. Trevor King -# # -# 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 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. +# 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 +# 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. """List bugs""" from libbe import cmdutil, bugdir, bug import os @@ -135,11 +134,12 @@ def execute(args, test=False): return True bugs = [b for b in bd if filter(b) ] - if len(bugs) == 0: + if len(bugs) == 0 and options.xml == False: print "No matching bugs found" def list_bugs(cur_bugs, title=None, just_uuids=False, xml=False): if xml == True: + print '' % bd.encoding print "" if len(cur_bugs) > 0: if title != None and xml == False: diff --git a/becommands/merge.py b/becommands/merge.py index 4bec6bf..4aaefa8 100644 --- a/becommands/merge.py +++ b/becommands/merge.py @@ -1,19 +1,18 @@ # Copyright (C) 2008-2009 W. Trevor King -# # -# 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 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. +# 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 +# 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. """Merge duplicate bugs""" from libbe import cmdutil, bugdir import os, copy @@ -23,6 +22,7 @@ def execute(args, test=False): """ >>> from libbe import utility >>> bd = bugdir.simple_bug_dir() + >>> bd.set_sync_with_disk(True) >>> a = bd.bug_from_shortname("a") >>> a.comment_root.time = 0 >>> dummy = a.new_comment("Testing") @@ -36,7 +36,6 @@ def execute(args, test=False): >>> dummy.time = 1 >>> dummy = dummy.new_reply("1 2 3 4") >>> dummy.time = 2 - >>> bd.save() >>> os.chdir(bd.root) >>> execute(["a", "b"], test=True) Merging bugs a and b @@ -141,13 +140,13 @@ def execute(args, test=False): bugB.load_comments() mergeA = bugA.new_comment("Merged from bug %s" % bugB.uuid) newCommTree = copy.deepcopy(bugB.comment_root) - for comment in newCommTree.traverse(): + for comment in newCommTree.traverse(): # all descendant comments comment.bug = bugA - for comment in newCommTree: + comment.save() # force onto disk under bugA + for comment in newCommTree: # just the child comments 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(): diff --git a/becommands/new.py b/becommands/new.py index 32e070a..af599d7 100644 --- a/becommands/new.py +++ b/becommands/new.py @@ -1,22 +1,22 @@ # Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc. # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Create a new bug""" -from libbe import cmdutil, bugdir, settings_object +from libbe import cmdutil, bugdir +import sys __desc__ = __doc__ def execute(args, test=False): @@ -36,7 +36,7 @@ def execute(args, test=False): True >>> print bug.severity minor - >>> bug.target == settings_object.EMPTY + >>> bug.target == None True """ parser = get_parser() @@ -45,16 +45,19 @@ def execute(args, test=False): if len(args) != 1: raise cmdutil.UsageError("Please supply a summary message") bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.new_bug(summary=args[0]) + if args[0] == '-': # read summary from stdin + summary = sys.stdin.readline() + else: + summary = args[0] + bug = bd.new_bug(summary=summary.strip()) if options.reporter != None: bug.reporter = options.reporter else: bug.reporter = bug.creator if options.assigned != None: bug.assigned = options.assigned - elif bd.default_assignee != settings_object.EMPTY: + elif bd.default_assignee != None: bug.assigned = bd.default_assignee - bd.save() print "Created bug with ID %s" % bd.bug_shortname(bug) def get_parser(): @@ -66,8 +69,9 @@ def get_parser(): return parser longhelp=""" -Create a new bug, with a new ID. The summary specified on the commandline -is a string that describes the bug briefly. +Create a new bug, with a new ID. The summary specified on the +commandline is a string (only one line) that describes the bug briefly +or "-", in which case the string will be read from stdin. """ def help(): diff --git a/becommands/open.py b/becommands/open.py index f9abcbb..2ef5f43 100644 --- a/becommands/open.py +++ b/becommands/open.py @@ -2,21 +2,20 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Re-open a bug""" from libbe import cmdutil, bugdir __desc__ = __doc__ @@ -44,7 +43,6 @@ def execute(args, test=False): bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) bug = bd.bug_from_shortname(args[0]) bug.status = "open" - bd.save() def get_parser(): parser = cmdutil.CmdOptionParser("be open BUG-ID") diff --git a/becommands/remove.py b/becommands/remove.py index 213a8d9..d79a7be 100644 --- a/becommands/remove.py +++ b/becommands/remove.py @@ -1,19 +1,18 @@ # Copyright (C) 2008-2009 W. Trevor King -# # -# 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 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. +# 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 +# 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. """Remove (delete) a bug and its comments""" from libbe import cmdutil, bugdir __desc__ = __doc__ @@ -44,7 +43,6 @@ def execute(args, test=False): bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) bug = bd.bug_from_shortname(args[0]) bd.remove_bug(bug) - bd.save() print "Removed bug %s" % bug.uuid def get_parser(): diff --git a/becommands/set.py b/becommands/set.py index e771018..0c0862f 100644 --- a/becommands/set.py +++ b/becommands/set.py @@ -3,30 +3,30 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Change tree settings""" -from libbe import cmdutil, bugdir, settings_object +import textwrap +from libbe import cmdutil, bugdir, rcs, settings_object __desc__ = __doc__ def _value_string(bd, setting): val = bd.settings.get(setting, settings_object.EMPTY) if val == settings_object.EMPTY: default = getattr(bd, bd._setting_name_to_attr_name(setting)) - if default != settings_object.EMPTY: + if default not in [None, settings_object.EMPTY]: val = "None (%s)" % default else: val = None @@ -60,7 +60,9 @@ def execute(args, test=False): elif len(args) == 1: print _value_string(bd, args[0]) else: - if args[1] != "none": + if args[1] == "none": + setattr(bd, args[0], settings_object.EMPTY) + else: if args[0] not in bd.settings_properties: msg = "Invalid setting %s\n" % args[0] msg += 'Allowed settings:\n ' @@ -68,14 +70,35 @@ def execute(args, test=False): raise cmdutil.UserError(msg) old_setting = bd.settings.get(args[0]) setattr(bd, args[0], args[1]) - else: - del bd.settings[args[0]] - bd.save() def get_parser(): parser = cmdutil.CmdOptionParser("be set [NAME] [VALUE]") return parser +def get_bugdir_settings(): + settings = [] + for s in bugdir.BugDir.settings_properties: + settings.append(s) + settings.sort() + documented_settings = [] + for s in settings: + set = getattr(bugdir.BugDir, s) + dstr = set.__doc__.strip() + # per-setting comment adjustments + if s == "rcs_name": + lines = dstr.split('\n') + while lines[0].startswith("This property defaults to") == False: + lines.pop(0) + assert len(lines) != None, \ + "Unexpected rcs_name docstring:\n '%s'" % dstr + lines.insert( + 0, "The name of the revision control system to use.\n") + dstr = '\n'.join(lines) + doc = textwrap.wrap(dstr, width=70, initial_indent=' ', + subsequent_indent=' ') + documented_settings.append("%s\n%s" % (s, '\n'.join(doc))) + return documented_settings + longhelp=""" Show or change per-tree settings. @@ -83,14 +106,11 @@ If name and value are supplied, the name is set to a new value. If no value is specified, the current value is printed. If no arguments are provided, all names and values are listed. -Interesting settings are: -rcs_name - The name of the revision control system. "Arch" and "None" are supported. -target - The current development goal - To unset a setting, set it to "none". -""" + +Allowed settings are: + +%s""" % ('\n'.join(get_bugdir_settings()),) def help(): return get_parser().help_str() + longhelp diff --git a/becommands/severity.py b/becommands/severity.py index f8a0c02..65467e3 100644 --- a/becommands/severity.py +++ b/becommands/severity.py @@ -2,21 +2,20 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Show or change a bug's severity level""" from libbe import cmdutil, bugdir, bug __desc__ = __doc__ @@ -51,7 +50,6 @@ def execute(args, test=False): if e.name != "severity": raise e raise cmdutil.UserError ("Invalid severity level: %s" % e.value) - bd.save() def get_parser(): parser = cmdutil.CmdOptionParser("be severity BUG-ID [SEVERITY]") diff --git a/becommands/show.py b/becommands/show.py index ff434ab..e43cfb9 100644 --- a/becommands/show.py +++ b/becommands/show.py @@ -3,22 +3,22 @@ # Thomas Gerigk # Thomas Habets # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Show a particular bug""" +import sys from libbe import cmdutil, bugdir __desc__ = __doc__ @@ -40,6 +40,7 @@ def execute(args, test=False): Bug A >>> execute (["--xml", "a"], test=True) # doctest: +ELLIPSIS + a a @@ -53,27 +54,60 @@ def execute(args, test=False): parser = get_parser() options, args = parser.parse_args(args) cmdutil.default_complete(options, args, parser, - bugid_args={0: lambda bug : bug.active==True}) + bugid_args={-1: lambda bug : bug.active==True}) if len(args) == 0: raise cmdutil.UsageError bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - for bugid in args: - bug = bd.bug_from_shortname(bugid) - if options.dumpXML: - print bug.xml(show_comments=True) + if options.XML: + print '' % bd.encoding + for shortname in args: + 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_comment = True else: - print bug.string(show_comments=True) - if bugid != args[-1]: - print "" # add a blank line between bugs + bugname = shortname + is_comment = False + if is_comment == True and options.comments == False: + continue + bug = bd.bug_from_shortname(bugname) + if is_comment == False: + if options.XML: + print bug.xml(show_comments=options.comments) + else: + print bug.string(show_comments=options.comments) + else: + comment = bug.comment_root.comment_from_shortname( + shortname, bug_shortname=bugname) + if options.XML: + print comment.xml(shortname=shortname) + else: + if len(args) == 1 and options.only_raw_body == True: + sys.__stdout__.write(comment.body) + else: + print comment.string(shortname=shortname) + if shortname != args[-1] and options.XML == False: + print "" # add a blank line between bugs/comments def get_parser(): - parser = cmdutil.CmdOptionParser("be show [options] BUG-ID [BUG-ID ...]") - parser.add_option("-x", "--xml", action="store_true", - dest='dumpXML', help="Dump as XML") + parser = cmdutil.CmdOptionParser("be show [options] ID [ID ...]") + parser.add_option("-x", "--xml", action="store_true", default=False, + dest='XML', help="Dump as XML") + parser.add_option("--only-raw-body", action="store_true", + dest='only_raw_body', + help="When printing only a single comment, just print it's body. This allows extraction of non-text content types.") + parser.add_option("-c", "--no-comments", dest="comments", + action="store_false", default=True, + help="Disable comment output. This is useful if you just want more details on a bug's current status.") return parser longhelp=""" -Show all information about a bug. +Show all information about the bugs or comments whose IDs are given. + +It's probably not a good idea to mix bug and comment IDs in a single +call, but you're free to do so if you like. """ def help(): diff --git a/becommands/status.py b/becommands/status.py index d8bd4c4..edc948d 100644 --- a/becommands/status.py +++ b/becommands/status.py @@ -1,19 +1,18 @@ # Copyright (C) 2008-2009 W. Trevor King -# # -# 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 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. +# 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 +# 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. """Show or change a bug's status""" from libbe import cmdutil, bugdir, bug __desc__ = __doc__ @@ -48,7 +47,6 @@ def execute(args, test=False): if e.name != "status": raise raise cmdutil.UserError ("Invalid status: %s" % e.value) - bd.save() def get_parser(): parser = cmdutil.CmdOptionParser("be status BUG-ID [STATUS]") @@ -56,24 +54,39 @@ def get_parser(): def help(): - longhelp=[""" -Show or change a bug's status. - -If no status is specified, the current value is printed. If a status -is specified, it will be assigned to the bug. - -Status levels are: -"""] try: # See if there are any per-tree status configurations bd = bugdir.BugDir(from_disk=True, manipulate_encodings=False) except bugdir.NoBugDir, e: pass # No tree, just show the defaults longest_status_len = max([len(s) for s in bug.status_values]) - for status in bug.status_values : + active_statuses = [] + for status in bug.active_status_values : + description = bug.status_description[status] + s = "%*s : %s" % (longest_status_len, status, description) + active_statuses.append(s) + inactive_statuses = [] + for status in bug.inactive_status_values : description = bug.status_description[status] - s = "%*s : %s\n" % (longest_status_len, status, description) - longhelp.append(s) - longhelp = ''.join(longhelp) + s = "%*s : %s" % (longest_status_len, status, description) + inactive_statuses.append(s) + longhelp=""" +Show or change a bug's status. + +If no status is specified, the current value is printed. If a status +is specified, it will be assigned to the bug. + +There are two classes of statuses, active and inactive, which are only +important for commands like "be list" that show only active bugs by +default. + +Active status levels are: + %s +Inactive status levels are: + %s + +You can overide the list of allowed statuses on a per-repository basis. +See "be set --help" for more details. +""" % ('\n '.join(active_statuses), '\n '.join(inactive_statuses)) return get_parser().help_str() + longhelp def complete(options, args, parser): diff --git a/becommands/tag.py b/becommands/tag.py index ab0324e..216ffbc 100644 --- a/becommands/tag.py +++ b/becommands/tag.py @@ -1,18 +1,18 @@ # Copyright (C) 2009 W. Trevor King # -# 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 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. +# 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 +# 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. """Tag a bug, or search bugs for tags""" from libbe import cmdutil, bugdir import os, copy @@ -22,6 +22,7 @@ def execute(args, test=False): """ >>> from libbe import utility >>> bd = bugdir.simple_bug_dir() + >>> bd.set_sync_with_disk(True) >>> os.chdir(bd.root) >>> a = bd.bug_from_shortname("a") >>> print a.extra_strings @@ -56,7 +57,6 @@ def execute(args, test=False): >>> a.extra_strings = [] >>> print a.extra_strings [] - >>> a.save() >>> execute(["a"], test=True) >>> bd._clear_bugs() # resync our copy of bug >>> a = bd.bug_from_shortname("a") @@ -102,7 +102,6 @@ def execute(args, test=False): else: # add the tag estrs.append(tag_string) bug.extra_strings = estrs # reassign to notice change - bug.save() tags = [] for estr in bug.extra_strings: diff --git a/becommands/target.py b/becommands/target.py index 283998a..527b16a 100644 --- a/becommands/target.py +++ b/becommands/target.py @@ -4,23 +4,22 @@ # Marien Zwart # Thomas Gerigk # W. Trevor King -# # -# 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 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. +# 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 +# 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. """Show or change a bug's target for fixing""" -from libbe import cmdutil, bugdir, settings_object +from libbe import cmdutil, bugdir __desc__ = __doc__ def execute(args, test=False): @@ -56,7 +55,7 @@ def execute(args, test=False): return bug = bd.bug_from_shortname(args[0]) if len(args) == 1: - if bug.target is None or bug.target is settings_object.EMPTY: + if bug.target is None: print "No target assigned." else: print bug.target @@ -66,7 +65,6 @@ def execute(args, test=False): bug.target = None else: bug.target = args[1] - bd.save() def get_parser(): parser = cmdutil.CmdOptionParser("be target BUG-ID [TARGET]\nor: be target --list") -- cgit From b0b3c9473e3a4b728ea72a2876e39fe41284a9ed Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Fri, 2 Oct 2009 23:46:24 +0200 Subject: Merged with Trevor's -rr branch --- becommands/assign.py | 15 +- becommands/close.py | 12 +- becommands/comment.py | 34 ++--- becommands/commit.py | 13 +- becommands/depend.py | 321 ++++++++++++++++++++++++++++++++++----- becommands/diff.py | 67 +++++---- becommands/help.py | 6 +- becommands/html.py | 214 +++++++++++++------------- becommands/init.py | 28 ++-- becommands/list.py | 17 ++- becommands/merge.py | 14 +- becommands/new.py | 12 +- becommands/open.py | 12 +- becommands/remove.py | 14 +- becommands/set.py | 24 +-- becommands/severity.py | 18 ++- becommands/show.py | 14 +- becommands/status.py | 21 +-- becommands/subscribe.py | 390 ++++++++++++++++++++++++++++++++++++++++++++++++ becommands/tag.py | 26 ++-- becommands/target.py | 22 +-- 21 files changed, 994 insertions(+), 300 deletions(-) create mode 100644 becommands/subscribe.py (limited to 'becommands') diff --git a/becommands/assign.py b/becommands/assign.py index 536bca6..794f028 100644 --- a/becommands/assign.py +++ b/becommands/assign.py @@ -20,28 +20,29 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> bd.bug_from_shortname("a").assigned is None True - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) >>> bd._clear_bugs() >>> bd.bug_from_shortname("a").assigned == bd.user_id True - >>> execute(["a", "someone"], test=True) + >>> execute(["a", "someone"], manipulate_encodings=False) >>> bd._clear_bugs() >>> print bd.bug_from_shortname("a").assigned someone - >>> execute(["a","none"], test=True) + >>> execute(["a","none"], manipulate_encodings=False) >>> bd._clear_bugs() >>> bd.bug_from_shortname("a").assigned is None True + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -53,7 +54,9 @@ def execute(args, test=False): if len(args) > 2: help() raise cmdutil.UsageError("Too many arguments.") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) bug = bd.bug_from_shortname(args[0]) if len(args) == 1: bug.assigned = bd.user_id diff --git a/becommands/close.py b/becommands/close.py index 0ba8f50..0532ed2 100644 --- a/becommands/close.py +++ b/becommands/close.py @@ -20,18 +20,19 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import bugdir >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> print bd.bug_from_shortname("a").status open - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) >>> bd._clear_bugs() >>> print bd.bug_from_shortname("a").status closed + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -41,8 +42,9 @@ def execute(args, test=False): raise cmdutil.UsageError("Please specify a bug id.") if len(args) > 1: raise cmdutil.UsageError("Too many arguments.") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) bug.status = "closed" bd.save() diff --git a/becommands/comment.py b/becommands/comment.py index 55b5913..9a614b2 100644 --- a/becommands/comment.py +++ b/becommands/comment.py @@ -25,20 +25,20 @@ except ImportError: # look for non-core module from elementtree import ElementTree __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import time - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute(["a", "This is a comment about a"], test=True) + >>> execute(["a", "This is a comment about a"], manipulate_encodings=False) >>> bd._clear_bugs() - >>> bug = bd.bug_from_shortname("a") + >>> bug = cmdutil.bug_from_shortname(bd, "a") >>> bug.load_comments(load_full=False) >>> comment = bug.comment_root[0] >>> print comment.body This is a comment about a - >>> comment.From == bd.user_id + >>> comment.author == bd.user_id True >>> comment.time <= int(time.time()) True @@ -47,19 +47,20 @@ def execute(args, test=False): >>> if 'EDITOR' in os.environ: ... del os.environ["EDITOR"] - >>> execute(["b"], test=True) + >>> execute(["b"], manipulate_encodings=False) Traceback (most recent call last): UserError: No comment supplied, and EDITOR not specified. >>> os.environ["EDITOR"] = "echo 'I like cheese' > " - >>> execute(["b"], test=True) + >>> execute(["b"], manipulate_encodings=False) >>> bd._clear_bugs() - >>> bug = bd.bug_from_shortname("b") + >>> bug = cmdutil.bug_from_shortname(bd, "b") >>> bug.load_comments(load_full=False) >>> comment = bug.comment_root[0] >>> print comment.body I like cheese + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -68,10 +69,10 @@ def execute(args, test=False): raise cmdutil.UsageError("Please specify a bug or comment id.") if len(args) > 2: raise cmdutil.UsageError("Too many arguments.") - + shortname = args[0] if shortname.count(':') > 1: - raise cmdutil.UserError("Invalid id '%s'." % shortname) + raise cmdutil.UserError("Invalid id '%s'." % shortname) elif shortname.count(':') == 1: # Split shortname generated by Comment.comment_shortnames() bugname = shortname.split(':')[0] @@ -79,17 +80,17 @@ def execute(args, test=False): else: bugname = shortname is_reply = False - + bd = bugdir.BugDir(from_disk=True, - manipulate_encodings=not test) - bug = bd.bug_from_shortname(bugname) + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, bugname) bug.load_comments(load_full=False) if is_reply: parent = bug.comment_root.comment_from_shortname(shortname, bug_shortname=bugname) else: parent = bug.comment_root - + if len(args) == 1: # try to launch an editor for comment-body entry try: if parent == bug.comment_root: @@ -103,7 +104,6 @@ def execute(args, test=False): raise cmdutil.UserError, "No comment supplied, and EDITOR not specified." if body is None: raise cmdutil.UserError("No comment entered.") - body = body.decode('utf-8') elif args[1] == '-': # read body from stdin binary = not (options.content_type == None or options.content_type.startswith("text/")) @@ -117,11 +117,11 @@ def execute(args, test=False): body = args[1] if not body.endswith('\n'): body+='\n' - + if options.XML == False: new = parent.new_reply(body=body) if options.author != None: - new.From = options.author + new.author = options.author if options.alt_id != None: new.alt_id = options.alt_id if options.content_type != None: diff --git a/becommands/commit.py b/becommands/commit.py index 4f3bdbd..dc70e7e 100644 --- a/becommands/commit.py +++ b/becommands/commit.py @@ -14,7 +14,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Commit the currently pending changes to the repository""" -from libbe import cmdutil, bugdir, editor, rcs +from libbe import cmdutil, bugdir, editor, vcs import sys __desc__ = __doc__ @@ -22,13 +22,14 @@ def execute(args, manipulate_encodings=True): """ >>> import os, time >>> from libbe import bug - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> full_path = "testfile" >>> test_contents = "A test file" - >>> bd.rcs.set_file_contents(full_path, test_contents) + >>> bd.vcs.set_file_contents(full_path, test_contents) >>> execute(["Added %s." % (full_path)], manipulate_encodings=False) # doctest: +ELLIPSIS Committed ... + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -48,11 +49,11 @@ def execute(args, manipulate_encodings=True): elif options.body == "EDITOR": body = editor.editor_string("Please enter your commit message above") else: - body = bd.rcs.get_file_contents(options.body, allow_no_rcs=True) + body = bd.vcs.get_file_contents(options.body, allow_no_vcs=True) try: - revision = bd.rcs.commit(summary, body=body, + revision = bd.vcs.commit(summary, body=body, allow_empty=options.allow_empty) - except rcs.EmptyCommit, e: + except vcs.EmptyCommit, e: print e return 1 else: diff --git a/becommands/depend.py b/becommands/depend.py index 4a23b0f..f72b8ba 100644 --- a/becommands/depend.py +++ b/becommands/depend.py @@ -14,26 +14,56 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Add/remove bug dependencies""" -from libbe import cmdutil, bugdir +from libbe import cmdutil, bugdir, tree import os, copy __desc__ = __doc__ -def execute(args, test=False): +BLOCKS_TAG="BLOCKS:" +BLOCKED_BY_TAG="BLOCKED-BY:" + +class BrokenLink (Exception): + def __init__(self, blocked_bug, blocking_bug, blocks=True): + if blocks == True: + msg = "Missing link: %s blocks %s" \ + % (blocking_bug.uuid, blocked_bug.uuid) + else: + msg = "Missing link: %s blocked by %s" \ + % (blocked_bug.uuid, blocking_bug.uuid) + Exception.__init__(self, msg) + self.blocked_bug = blocked_bug + self.blocking_bug = blocking_bug + + +def execute(args, manipulate_encodings=True): """ >>> from libbe import utility - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> bd.save() >>> os.chdir(bd.root) - >>> execute(["a", "b"], test=True) - Blocks on a: + >>> execute(["a", "b"], manipulate_encodings=False) + a blocked by: b - >>> execute(["a"], test=True) - Blocks on a: + >>> execute(["a"], manipulate_encodings=False) + a blocked by: b - >>> execute(["--show-status", "a"], test=True) # doctest: +NORMALIZE_WHITESPACE - Blocks on a: + >>> execute(["--show-status", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + a blocked by: + b closed + >>> execute(["b", "a"], manipulate_encodings=False) + b blocked by: + a + b blocks: + a + >>> execute(["--show-status", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + a blocked by: + b closed + a blocks: b closed - >>> execute(["-r", "a", "b"], test=True) + >>> execute(["-r", "b", "a"], manipulate_encodings=False) + b blocks: + a + >>> execute(["-r", "a", "b"], manipulate_encodings=False) + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -41,45 +71,83 @@ def execute(args, test=False): bugid_args={0: lambda bug : bug.active==True, 1: lambda bug : bug.active==True}) - if len(args) < 1: + if options.repair == True: + if len(args) > 0: + raise cmdutil.UsageError("No arguments with --repair calls.") + elif len(args) < 1: raise cmdutil.UsageError("Please a bug id.") - if len(args) > 2: + elif len(args) > 2: help() raise cmdutil.UsageError("Too many arguments.") - - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bugA = bd.bug_from_shortname(args[0]) + elif len(args) == 2 and options.tree_depth != None: + raise cmdutil.UsageError("Only one bug id used in tree mode.") + + + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + if options.repair == True: + good,fixed,broken = check_dependencies(bd, repair_broken_links=True) + assert len(broken) == 0, broken + if len(fixed) > 0: + print "Fixed the following links:" + print "\n".join(["%s |-- %s" % (blockee.uuid, blocker.uuid) + for blockee,blocker in fixed]) + return 0 + + bugA = cmdutil.bug_from_shortname(bd, args[0]) + + if options.tree_depth != None: + dtree = DependencyTree(bd, bugA, options.tree_depth) + if len(dtree.blocked_by_tree()) > 0: + print "%s blocked by:" % bugA.uuid + for depth,node in dtree.blocked_by_tree().thread(): + if depth == 0: continue + print "%s%s" % (" "*(depth), node.bug.string(shortlist=True)) + if len(dtree.blocks_tree()) > 0: + print "%s blocks:" % bugA.uuid + for depth,node in dtree.blocks_tree().thread(): + if depth == 0: continue + print "%s%s" % (" "*(depth), node.bug.string(shortlist=True)) + return 0 + if len(args) == 2: - bugB = bd.bug_from_shortname(args[1]) - estrs = bugA.extra_strings - depend_string = "BLOCKED-BY:%s" % bugB.uuid + bugB = cmdutil.bug_from_shortname(bd, args[1]) if options.remove == True: - estrs.remove(depend_string) + remove_block(bugA, bugB) else: # add the dependency - estrs.append(depend_string) - bugA.extra_strings = estrs # reassign to notice change - - depends = [] - for estr in bugA.extra_strings: - if estr.startswith("BLOCKED-BY:"): - uuid = estr[11:] - if options.show_status == True: - blocker = bd.bug_from_uuid(uuid) - block_string = "%s\t%s" % (uuid, blocker.status) - else: - block_string = uuid - depends.append(block_string) - if len(depends) > 0: - print "Blocks on %s:" % bugA.uuid - print '\n'.join(depends) + add_block(bugA, bugB) + + blocked_by = get_blocked_by(bd, bugA) + if len(blocked_by) > 0: + print "%s blocked by:" % bugA.uuid + if options.show_status == True: + print '\n'.join(["%s\t%s" % (bug.uuid, bug.status) + for bug in blocked_by]) + else: + print '\n'.join([bug.uuid for bug in blocked_by]) + blocks = get_blocks(bd, bugA) + if len(blocks) > 0: + print "%s blocks:" % bugA.uuid + if options.show_status == True: + print '\n'.join(["%s\t%s" % (bug.uuid, bug.status) + for bug in blocks]) + else: + print '\n'.join([bug.uuid for bug in blocks]) def get_parser(): - parser = cmdutil.CmdOptionParser("be depend BUG-ID [BUG-ID]") - parser.add_option("-r", "--remove", action="store_true", dest="remove", + parser = cmdutil.CmdOptionParser("be depend BUG-ID [BUG-ID]\nor: be depend --repair") + parser.add_option("-r", "--remove", action="store_true", + dest="remove", default=False, help="Remove dependency (instead of adding it)") parser.add_option("-s", "--show-status", action="store_true", - dest="show_status", + dest="show_status", default=False, help="Show status of blocking bugs") + parser.add_option("-t", "--tree-depth", metavar="DEPTH", default=None, + type="int", dest="tree_depth", + help="Print dependency tree rooted at BUG-ID with DEPTH levels of both blockers and blockees. Set DEPTH <= 0 to disable the depth limit.") + parser.add_option("--repair", action="store_true", + dest="repair", default=False, + help="Check for and repair one-way links") return parser longhelp=""" @@ -88,7 +156,184 @@ If bug B is not specified, just print a list of bugs blocking (A). To search for bugs blocked by a particular bug, try $ be list --extra-strings BLOCKED-BY: + +In repair mode, add the missing direction to any one-way links. + +The "|--" symbol in the repair-mode output is inspired by the +"negative feedback" arrow common in biochemistry. See, for example + http://www.nature.com/nature/journal/v456/n7223/images/nature07513-f5.0.jpg """ def help(): return get_parser().help_str() + longhelp + +# internal helper functions + +def _generate_blocks_string(blocked_bug): + return "%s%s" % (BLOCKS_TAG, blocked_bug.uuid) + +def _generate_blocked_by_string(blocking_bug): + return "%s%s" % (BLOCKED_BY_TAG, blocking_bug.uuid) + +def _parse_blocks_string(string): + assert string.startswith(BLOCKS_TAG) + return string[len(BLOCKS_TAG):] + +def _parse_blocked_by_string(string): + assert string.startswith(BLOCKED_BY_TAG) + return string[len(BLOCKED_BY_TAG):] + +def _add_remove_extra_string(bug, string, add): + estrs = bug.extra_strings + if add == True: + estrs.append(string) + else: # remove the string + estrs.remove(string) + bug.extra_strings = estrs # reassign to notice change + +def _get_blocks(bug): + uuids = [] + for line in bug.extra_strings: + if line.startswith(BLOCKS_TAG): + uuids.append(_parse_blocks_string(line)) + return uuids + +def _get_blocked_by(bug): + uuids = [] + for line in bug.extra_strings: + if line.startswith(BLOCKED_BY_TAG): + uuids.append(_parse_blocked_by_string(line)) + return uuids + +def _repair_one_way_link(blocked_bug, blocking_bug, blocks=None): + if blocks == True: # add blocks link + blocks_string = _generate_blocks_string(blocked_bug) + _add_remove_extra_string(blocking_bug, blocks_string, add=True) + else: # add blocked by link + blocked_by_string = _generate_blocked_by_string(blocking_bug) + _add_remove_extra_string(blocked_bug, blocked_by_string, add=True) + +# functions exposed to other modules + +def add_block(blocked_bug, blocking_bug): + blocked_by_string = _generate_blocked_by_string(blocking_bug) + _add_remove_extra_string(blocked_bug, blocked_by_string, add=True) + blocks_string = _generate_blocks_string(blocked_bug) + _add_remove_extra_string(blocking_bug, blocks_string, add=True) + +def remove_block(blocked_bug, blocking_bug): + blocked_by_string = _generate_blocked_by_string(blocking_bug) + _add_remove_extra_string(blocked_bug, blocked_by_string, add=False) + blocks_string = _generate_blocks_string(blocked_bug) + _add_remove_extra_string(blocking_bug, blocks_string, add=False) + +def get_blocks(bugdir, bug): + """ + Return a list of bugs that the given bug blocks. + """ + blocks = [] + for uuid in _get_blocks(bug): + blocks.append(bugdir.bug_from_uuid(uuid)) + return blocks + +def get_blocked_by(bugdir, bug): + """ + Return a list of bugs blocking the given bug blocks. + """ + blocked_by = [] + for uuid in _get_blocked_by(bug): + blocked_by.append(bugdir.bug_from_uuid(uuid)) + return blocked_by + +def check_dependencies(bugdir, repair_broken_links=False): + """ + Check that links are bi-directional for all bugs in bugdir. + + >>> bd = bugdir.SimpleBugDir(sync_with_disk=False) + >>> a = bd.bug_from_uuid("a") + >>> b = bd.bug_from_uuid("b") + >>> blocked_by_string = _generate_blocked_by_string(b) + >>> _add_remove_extra_string(a, blocked_by_string, add=True) + >>> good,repaired,broken = check_dependencies(bd, repair_broken_links=False) + >>> good + [] + >>> repaired + [] + >>> broken + [(Bug(uuid='a'), Bug(uuid='b'))] + >>> _get_blocks(b) + [] + >>> good,repaired,broken = check_dependencies(bd, repair_broken_links=True) + >>> _get_blocks(b) + ['a'] + >>> good + [] + >>> repaired + [(Bug(uuid='a'), Bug(uuid='b'))] + >>> broken + [] + """ + if bugdir.sync_with_disk == True: + bugdir.load_all_bugs() + good_links = [] + fixed_links = [] + broken_links = [] + for bug in bugdir: + for blocker in get_blocked_by(bugdir, bug): + blocks = get_blocks(bugdir, blocker) + if (bug, blocks) in good_links+fixed_links+broken_links: + continue # already checked that link + if bug not in blocks: + if repair_broken_links == True: + _repair_one_way_link(bug, blocker, blocks=True) + fixed_links.append((bug, blocker)) + else: + broken_links.append((bug, blocker)) + else: + good_links.append((bug, blocker)) + for blockee in get_blocks(bugdir, bug): + blocked_by = get_blocked_by(bugdir, blockee) + if (blockee, bug) in good_links+fixed_links+broken_links: + continue # already checked that link + if bug not in blocked_by: + if repair_broken_links == True: + _repair_one_way_link(blockee, bug, blocks=False) + fixed_links.append((blockee, bug)) + else: + broken_links.append((blockee, bug)) + else: + good_links.append((blockee, bug)) + return (good_links, fixed_links, broken_links) + +class DependencyTree (object): + """ + Note: should probably be DependencyDiGraph. + """ + def __init__(self, bugdir, root_bug, depth_limit=0): + self.bugdir = bugdir + self.root_bug = root_bug + self.depth_limit = depth_limit + def _build_tree(self, child_fn): + root = tree.Tree() + root.bug = self.root_bug + root.depth = 0 + stack = [root] + while len(stack) > 0: + node = stack.pop() + if self.depth_limit > 0 and node.depth == self.depth_limit: + continue + for bug in child_fn(self.bugdir, node.bug): + child = tree.Tree() + child.bug = bug + child.depth = node.depth+1 + node.append(child) + stack.append(child) + return root + def blocks_tree(self): + if not hasattr(self, "_blocks_tree"): + self._blocks_tree = self._build_tree(get_blocks) + return self._blocks_tree + def blocked_by_tree(self): + if not hasattr(self, "_blocked_by_tree"): + self._blocked_by_tree = self._build_tree(get_blocked_by) + return self._blocked_by_tree diff --git a/becommands/diff.py b/becommands/diff.py index 13402c0..b6ac5b0 100644 --- a/becommands/diff.py +++ b/becommands/diff.py @@ -20,23 +20,35 @@ from libbe import cmdutil, bugdir, diff import os __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> bd.set_sync_with_disk(True) - >>> original = bd.rcs.commit("Original status") + >>> original = bd.vcs.commit("Original status") >>> bug = bd.bug_from_uuid("a") >>> bug.status = "closed" - >>> changed = bd.rcs.commit("Closed bug a") + >>> changed = bd.vcs.commit("Closed bug a") >>> os.chdir(bd.root) - >>> if bd.rcs.versioned == True: - ... execute([original], test=True) + >>> if bd.vcs.versioned == True: + ... execute([original], manipulate_encodings=False) ... else: - ... print "a:cm: Bug A\\nstatus: open -> closed\\n" - Modified bug reports: - a:cm: Bug A - status: open -> closed + ... print "Modified bugs:\\n a:cm: Bug A\\n Changed bug settings:\\n status: open -> closed" + Modified bugs: + a:cm: Bug A + Changed bug settings: + status: open -> closed + >>> if bd.vcs.versioned == True: + ... execute(["--modified", original], manipulate_encodings=False) + ... else: + ... print "a" + a + >>> if bd.vcs.versioned == False: + ... execute([original], manipulate_encodings=False) + ... else: + ... print "This directory is not revision-controlled." + This directory is not revision-controlled. + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -47,28 +59,31 @@ def execute(args, test=False): revision = args[0] if len(args) > 1: raise cmdutil.UsageError("Too many arguments.") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - if bd.rcs.versioned == False: + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + if bd.vcs.versioned == False: print "This directory is not revision-controlled." else: + if revision == None: # get the most recent revision + revision = bd.vcs.revision_id(-1) old_bd = bd.duplicate_bugdir(revision) - r,m,a = diff.bug_diffs(old_bd, bd) - - optbugs = [] + d = diff.Diff(old_bd, bd) + tree = d.report_tree() + + uuids = [] if options.all == True: options.new = options.modified = options.removed = True if options.new == True: - optbugs.extend(a) + uuids.extend([c.name for c in tree.child_by_path("/bugs/new")]) if options.modified == True: - optbugs.extend([new for old,new in m]) + uuids.extend([c.name for c in tree.child_by_path("/bugs/mod")]) if options.removed == True: - optbugs.extend(r) - if len(optbugs) > 0: - for bug in optbugs: - print bug.uuid + uuids.extend([c.name for c in tree.child_by_path("/bugs/rem")]) + if (options.new or options.modified or options.removed) == True: + print "\n".join(uuids) else : - rep = diff.diff_report((r,m,a), old_bd, bd).encode(bd.encoding) - if len(rep) > 0: + rep = tree.report_string() + if rep != None: print rep bd.remove_duplicate_bugdir() @@ -85,14 +100,14 @@ def get_parser(): long = "--%s" % s[1] help = s[2] parser.add_option(short, long, action="store_true", - dest=attr, help=help) + default=False, dest=attr, help=help) return parser longhelp=""" -Uses the RCS to compare the current tree with a previous tree, and +Uses the VCS to compare the current tree with a previous tree, and prints a pretty report. If REVISION is given, it is a specifier for the particular previous tree to use. Specifiers are specific to their -RCS. +VCS. For Arch your specifier must be a fully-qualified revision name. diff --git a/becommands/help.py b/becommands/help.py index a8ae338..a8f346a 100644 --- a/becommands/help.py +++ b/becommands/help.py @@ -19,9 +19,11 @@ from libbe import cmdutil, utility __desc__ = __doc__ -def execute(args): +def execute(args, manipulate_encodings=False): """ - Print help of specified command. + Print help of specified command (the manipulate_encodings argument + is ignored). + >>> execute(["help"]) Usage: be help [COMMAND] diff --git a/becommands/html.py b/becommands/html.py index 4835227..908c714 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -1,40 +1,47 @@ -# Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc. -# Marien Zwart -# Thomas Gerigk -# W. Trevor King -# +# Copyright (C) 2009 Gianluca Montecchi +# W. Trevor King # -# 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 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. +# 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 -"""Re-open a bug""" +# 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. +"""Generate a static HTML dump of the current repository status""" from libbe import cmdutil, bugdir, bug #from html_data import * -import os, re, time, string +import codecs, os, re, string, time +import xml.sax.saxutils, htmlentitydefs __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> print bd.bug_from_shortname("b").status - closed - >>> execute(["b"], test=True) - >>> bd._clear_bugs() - >>> print bd.bug_from_shortname("b").status - open + >>> execute([], manipulate_encodings=False) + Creating the html output in html_export + >>> os.path.exists("./html_export") + True + >>> os.path.exists("./html_export/index.html") + True + >>> os.path.exists("./html_export/index_inactive.html") + True + >>> os.path.exists("./html_export/bugs") + True + >>> os.path.exists("./html_export/bugs/a.html") + True + >>> os.path.exists("./html_export/bugs/b.html") + True + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -50,7 +57,8 @@ def execute(args, test=False): if len(args) > 0: raise cmdutil.UsageError, "Too many arguments." - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) bd.load_all_bugs() status_list = bug.status_values severity_list = bug.severity_values @@ -61,9 +69,9 @@ def execute(args, test=False): bugs_inactive = [] for s in status_list: st[s] = 0 - for b in bd: + for b in sorted(bd, reverse=True): stime[b.uuid] = b.time - if b.status in ["open", "test", "unconfirmed", "assigned"]: + if b.active == True: bugs_active.append(b) else: bugs_inactive.append(b) @@ -73,8 +81,8 @@ def execute(args, test=False): #open_bug_list = sorted([(value,key) for (key,value) in bugs.items()]) html_gen = BEHTMLGen(bd) - html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active") - html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive") + html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active", bd.encoding) + html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding) def get_parser(): parser = cmdutil.CmdOptionParser("be open OUTPUT_DIR") @@ -83,7 +91,8 @@ def get_parser(): return parser longhelp=""" -Generate a set of html pages. +Generate a set of html pages representing the current state of the bug +directory. """ def help(): @@ -94,7 +103,18 @@ def complete(options, args, parser): if "--complete" in args: raise cmdutil.GetCompletions() # no positional arguments for list - + +def escape(string): + if string == None: + return "" + chars = [] + for char in xml.sax.saxutils.escape(string): + codepoint = ord(char) + if codepoint in htmlentitydefs.codepoint2name: + char = "&%s;" % htmlentitydefs.codepoint2name[codepoint] + chars.append(char) + return "".join(chars) + class BEHTMLGen(): def __init__(self, bd): self.index_value = "" @@ -353,10 +373,12 @@ class BEHTMLGen(): """ self.index_first = """ + BugsEverywhere Issue Tracker - + @@ -368,17 +390,17 @@ class BEHTMLGen(): - - + +
Active BugsInactive BugsActive BugsInactive Bugs
- +
- """ + """ % self.bd.encoding self.bug_line =""" - + @@ -388,10 +410,12 @@ class BEHTMLGen(): """ self.detail_first = """ + BugsEverywhere Issue Tracker - + @@ -399,11 +423,11 @@ class BEHTMLGen():

BugsEverywhere Bug List

-
Back to Index
+
Back to Index

Bug: _bug_id_

%s %s %s
- """ + """ % self.bd.encoding @@ -430,7 +454,7 @@ class BEHTMLGen(): self.begin_comment_section =""" - ") + FD.write(self.detail_line%("Short name : ", escape(bug.uuid[0:3]))) + FD.write(self.detail_line%("Severity : ", escape(bug.severity))) + FD.write(self.detail_line%("Status : ", escape(bug.status))) + FD.write(self.detail_line%("Assigned : ", escape(bug.assigned))) + FD.write(self.detail_line%("Target : ", escape(bug.target))) + FD.write(self.detail_line%("Reporter : ", escape(bug.reporter))) + FD.write(self.detail_line%("Creator : ", escape(bug.creator))) + FD.write(self.detail_line%("Created : ", escape(bug.time_string))) + FD.write(self.detail_line%("Summary : ", escape(bug.summary))) + FD.write("") FD.write(self.begin_comment_section) tr = [] b = '' level = 0 - for i in bug_.comments(): - if not isinstance(i.in_reply_to,str): - first = True - a = i.string_thread(flatten=False) - d = re.split('\n',a) - for x in range(0,len(d)): - hr = "" - if re.match(" *--------- Comment ---------",d[x]): - com = """ - %s
- %s
- %s
- %s
- %s
- """%(d[x+1],d[x+2],d[x+3],d[x+4],d[x+5]) - l = re.sub("--------- Comment ---------", "", d[x]) - ll = l.split(" ") - la = l - ba = "" - if len(la) > level: - FD.write("
") - if len(la) < level: - FD.write("
") - if len(la) == 0: - if not first : - FD.write("") - first = False - FD.write("
") - level = len(la) - x += 5 - FD.write("--------- Comment ---------

") - FD.write(com) - FD.write("

") + stack = [] + for depth,comment in bug_.comment_root.thread(flatten=False): + while len(stack) > depth: + stack.pop(-1) # pop non-parents off the stack + FD.write("\n") # close non-parent
') + else: + FD.write('
') + FD.write("
\n".join(lines)+"
\n") + while len(stack) > 0: + stack.pop(-1) + FD.write("
\n") # close every remaining
>> from libbe import utility, rcs + >>> from libbe import utility, vcs >>> import os >>> dir = utility.Dir() >>> try: @@ -29,28 +29,28 @@ def execute(args, test=False): ... except bugdir.NoBugDir, e: ... True True - >>> execute(['--root', dir.path], test=True) + >>> execute(['--root', dir.path], manipulate_encodings=False) No revision control detected. Directory initialized. >>> del(dir) >>> dir = utility.Dir() >>> os.chdir(dir.path) - >>> rcs = rcs.installed_rcs() - >>> rcs.init('.') - >>> print rcs.name + >>> vcs = vcs.installed_vcs() + >>> vcs.init('.') + >>> print vcs.name Arch - >>> execute([], test=True) + >>> execute([], manipulate_encodings=False) Using Arch for revision control. Directory initialized. - >>> rcs.cleanup() + >>> vcs.cleanup() >>> try: - ... execute(['--root', '.'], test=True) + ... execute(['--root', '.'], manipulate_encodings=False) ... except cmdutil.UserError, e: ... str(e).startswith("Directory already initialized: ") True - >>> execute(['--root', '/highly-unlikely-to-exist'], test=True) + >>> execute(['--root', '/highly-unlikely-to-exist'], manipulate_encodings=False) Traceback (most recent call last): UserError: No such directory: /highly-unlikely-to-exist >>> os.chdir('/') @@ -64,14 +64,14 @@ def execute(args, test=False): bd = bugdir.BugDir(options.root_dir, from_disk=False, sink_to_existing_root=False, assert_new_BugDir=True, - manipulate_encodings=not test) + manipulate_encodings=manipulate_encodings) except bugdir.NoRootEntry: raise cmdutil.UserError("No such directory: %s" % options.root_dir) except bugdir.AlreadyInitialized: raise cmdutil.UserError("Directory already initialized: %s" % options.root_dir) bd.save() - if bd.rcs.name is not "None": - print "Using %s for revision control." % bd.rcs.name + if bd.vcs.name is not "None": + print "Using %s for revision control." % bd.vcs.name else: print "No revision control detected." print "Directory initialized." @@ -86,7 +86,7 @@ def get_parser(): longhelp=""" This command initializes Bugs Everywhere support for the specified directory 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. +system. You can use "be set vcs_name" to change the vcs being used. The directory defaults to your current working directory. diff --git a/becommands/list.py b/becommands/list.py index 5ba1821..12e1e29 100644 --- a/becommands/list.py +++ b/becommands/list.py @@ -26,16 +26,17 @@ __desc__ = __doc__ AVAILABLE_CMPS = [fn[4:] for fn in dir(bug) if fn[:4] == 'cmp_'] AVAILABLE_CMPS.remove("attr") # a cmp_* template. -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute([], test=True) + >>> execute([], manipulate_encodings=False) a:om: Bug A - >>> execute(["--status", "all"], test=True) + >>> execute(["--status", "all"], manipulate_encodings=False) a:om: Bug A b:cm: Bug B + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -46,11 +47,13 @@ def execute(args, test=False): if options.sort_by != None: for cmp in options.sort_by.split(','): if cmp not in AVAILABLE_CMPS: - raise cmdutil.UserError("Invalid sort on '%s'.\nValid sorts:\n %s" - % (cmp, '\n '.join(AVAILABLE_CMPS))) + raise cmdutil.UserError( + "Invalid sort on '%s'.\nValid sorts:\n %s" + % (cmp, '\n '.join(AVAILABLE_CMPS))) cmp_list.append(eval('bug.cmp_%s' % cmp)) - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) bd.load_all_bugs() # select status if options.status != None: diff --git a/becommands/merge.py b/becommands/merge.py index 4aaefa8..f212b01 100644 --- a/becommands/merge.py +++ b/becommands/merge.py @@ -18,10 +18,10 @@ from libbe import cmdutil, bugdir import os, copy __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import utility - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> bd.set_sync_with_disk(True) >>> a = bd.bug_from_shortname("a") >>> a.comment_root.time = 0 @@ -37,7 +37,7 @@ def execute(args, test=False): >>> dummy = dummy.new_reply("1 2 3 4") >>> dummy.time = 2 >>> os.chdir(bd.root) - >>> execute(["a", "b"], test=True) + >>> execute(["a", "b"], manipulate_encodings=False) Merging bugs a and b >>> bd._clear_bugs() >>> a = bd.bug_from_shortname("a") @@ -120,6 +120,7 @@ def execute(args, test=False): Merged into bug a >>> print b.status closed + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -133,10 +134,11 @@ def execute(args, test=False): help() raise cmdutil.UsageError("Too many arguments.") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bugA = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bugA = cmdutil.bug_from_shortname(bd, args[0]) bugA.load_comments() - bugB = bd.bug_from_shortname(args[1]) + bugB = cmdutil.bug_from_shortname(bd, args[1]) bugB.load_comments() mergeA = bugA.new_comment("Merged from bug %s" % bugB.uuid) newCommTree = copy.deepcopy(bugB.comment_root) diff --git a/becommands/new.py b/becommands/new.py index af599d7..a8ee2ec 100644 --- a/becommands/new.py +++ b/becommands/new.py @@ -19,16 +19,16 @@ from libbe import cmdutil, bugdir import sys __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os, time >>> from libbe import bug - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> bug.uuid_gen = lambda: "X" - >>> execute (["this is a test",], test=True) + >>> execute (["this is a test",], manipulate_encodings=False) Created bug with ID X - >>> bd.load() + >>> bd._clear_bugs() >>> bug = bd.bug_from_uuid("X") >>> print bug.summary this is a test @@ -38,13 +38,15 @@ def execute(args, test=False): minor >>> bug.target == None True + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) cmdutil.default_complete(options, args, parser) if len(args) != 1: raise cmdutil.UsageError("Please supply a summary message") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if args[0] == '-': # read summary from stdin summary = sys.stdin.readline() else: diff --git a/becommands/open.py b/becommands/open.py index 2ef5f43..0c6bf05 100644 --- a/becommands/open.py +++ b/becommands/open.py @@ -20,17 +20,18 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> print bd.bug_from_shortname("b").status closed - >>> execute(["b"], test=True) + >>> execute(["b"], manipulate_encodings=False) >>> bd._clear_bugs() >>> print bd.bug_from_shortname("b").status open + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -40,8 +41,9 @@ def execute(args, test=False): raise cmdutil.UsageError, "Please specify a bug id." if len(args) > 1: raise cmdutil.UsageError, "Too many arguments." - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) bug.status = "open" def get_parser(): diff --git a/becommands/remove.py b/becommands/remove.py index d79a7be..8d85033 100644 --- a/becommands/remove.py +++ b/becommands/remove.py @@ -17,22 +17,23 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import mapfile >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) >>> print bd.bug_from_shortname("b").status closed - >>> execute (["b"], test=True) + >>> execute (["b"], manipulate_encodings=False) Removed bug b >>> bd._clear_bugs() >>> try: ... bd.bug_from_shortname("b") - ... except KeyError: + ... except bugdir.NoBugMatches: ... print "Bug not found" Bug not found + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -40,8 +41,9 @@ def execute(args, test=False): bugid_args={0: lambda bug : bug.active==True}) if len(args) != 1: raise cmdutil.UsageError, "Please specify a bug id." - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) bd.remove_bug(bug) print "Removed bug %s" % bug.uuid diff --git a/becommands/set.py b/becommands/set.py index 0c0862f..f7e68d3 100644 --- a/becommands/set.py +++ b/becommands/set.py @@ -19,7 +19,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Change tree settings""" import textwrap -from libbe import cmdutil, bugdir, rcs, settings_object +from libbe import cmdutil, bugdir, vcs, settings_object __desc__ = __doc__ def _value_string(bd, setting): @@ -32,26 +32,28 @@ def _value_string(bd, setting): val = None return str(val) -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute(["target"], test=True) + >>> execute(["target"], manipulate_encodings=False) None - >>> execute(["target", "tomorrow"], test=True) - >>> execute(["target"], test=True) + >>> execute(["target", "tomorrow"], manipulate_encodings=False) + >>> execute(["target"], manipulate_encodings=False) tomorrow - >>> execute(["target", "none"], test=True) - >>> execute(["target"], test=True) + >>> execute(["target", "none"], manipulate_encodings=False) + >>> execute(["target"], manipulate_encodings=False) None + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) complete(options, args, parser) if len(args) > 2: raise cmdutil.UsageError, "Too many arguments" - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if len(args) == 0: keys = bd.settings_properties keys.sort() @@ -85,12 +87,12 @@ def get_bugdir_settings(): set = getattr(bugdir.BugDir, s) dstr = set.__doc__.strip() # per-setting comment adjustments - if s == "rcs_name": + if s == "vcs_name": lines = dstr.split('\n') while lines[0].startswith("This property defaults to") == False: lines.pop(0) assert len(lines) != None, \ - "Unexpected rcs_name docstring:\n '%s'" % dstr + "Unexpected vcs_name docstring:\n '%s'" % dstr lines.insert( 0, "The name of the revision control system to use.\n") dstr = '\n'.join(lines) diff --git a/becommands/severity.py b/becommands/severity.py index 65467e3..660586e 100644 --- a/becommands/severity.py +++ b/becommands/severity.py @@ -20,27 +20,29 @@ from libbe import cmdutil, bugdir, bug __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) minor - >>> execute(["a", "wishlist"], test=True) - >>> execute(["a"], test=True) + >>> execute(["a", "wishlist"], manipulate_encodings=False) + >>> execute(["a"], manipulate_encodings=False) wishlist - >>> execute(["a", "none"], test=True) + >>> execute(["a", "none"], manipulate_encodings=False) Traceback (most recent call last): UserError: Invalid severity level: none + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) complete(options, args, parser) if len(args) not in (1,2): raise cmdutil.UsageError - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) if len(args) == 1: print bug.severity elif len(args) == 2: diff --git a/becommands/show.py b/becommands/show.py index e43cfb9..50bd6eb 100644 --- a/becommands/show.py +++ b/becommands/show.py @@ -22,12 +22,12 @@ import sys from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute (["a",], test=True) # doctest: +ELLIPSIS + >>> execute (["a",], manipulate_encodings=False) # doctest: +ELLIPSIS ID : a Short name : a Severity : minor @@ -39,7 +39,7 @@ def execute(args, test=False): Created : ... Bug A - >>> execute (["--xml", "a"], test=True) # doctest: +ELLIPSIS + >>> execute (["--xml", "a"], manipulate_encodings=False) # doctest: +ELLIPSIS a @@ -50,6 +50,7 @@ def execute(args, test=False): ... Bug A + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -57,7 +58,8 @@ def execute(args, test=False): bugid_args={-1: lambda bug : bug.active==True}) if len(args) == 0: raise cmdutil.UsageError - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if options.XML: print '' % bd.encoding for shortname in args: @@ -72,7 +74,7 @@ def execute(args, test=False): is_comment = False if is_comment == True and options.comments == False: continue - bug = bd.bug_from_shortname(bugname) + bug = cmdutil.bug_from_shortname(bd, bugname) if is_comment == False: if options.XML: print bug.xml(show_comments=options.comments) diff --git a/becommands/status.py b/becommands/status.py index edc948d..f315003 100644 --- a/becommands/status.py +++ b/becommands/status.py @@ -17,27 +17,29 @@ from libbe import cmdutil, bugdir, bug __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) open - >>> execute(["a", "closed"], test=True) - >>> execute(["a"], test=True) + >>> execute(["a", "closed"], manipulate_encodings=False) + >>> execute(["a"], manipulate_encodings=False) closed - >>> execute(["a", "none"], test=True) + >>> execute(["a", "none"], manipulate_encodings=False) Traceback (most recent call last): UserError: Invalid status: none + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) complete(options, args, parser) if len(args) not in (1,2): raise cmdutil.UsageError - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) - bug = bd.bug_from_shortname(args[0]) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + bug = cmdutil.bug_from_shortname(bd, args[0]) if len(args) == 1: print bug.status else: @@ -55,7 +57,8 @@ def get_parser(): def help(): try: # See if there are any per-tree status configurations - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=False) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=False) except bugdir.NoBugDir, e: pass # No tree, just show the defaults longest_status_len = max([len(s) for s in bug.status_values]) diff --git a/becommands/subscribe.py b/becommands/subscribe.py new file mode 100644 index 0000000..0a23057 --- /dev/null +++ b/becommands/subscribe.py @@ -0,0 +1,390 @@ +# Copyright (C) 2009 W. Trevor King +# +# 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. +"""(Un)subscribe to change notification""" +from libbe import cmdutil, bugdir, tree +import os, copy +__desc__ = __doc__ + +TAG="SUBSCRIBE:" + +class SubscriptionType (tree.Tree): + """ + Trees of subscription types to allow users to select exactly what + notifications they want to subscribe to. + """ + def __init__(self, type_name, *args, **kwargs): + tree.Tree.__init__(self, *args, **kwargs) + self.type = type_name + def __str__(self): + return self.type + def __repr__(self): + return "" % str(self) + def string_tree(self, indent=0): + lines = [] + for depth,node in self.thread(): + lines.append("%s%s" % (" "*(indent+2*depth), node)) + return "\n".join(lines) + +BUGDIR_TYPE_NEW = SubscriptionType("new") +BUGDIR_TYPE_ALL = SubscriptionType("all", [BUGDIR_TYPE_NEW]) + +# same name as BUGDIR_TYPE_ALL for consistency +BUG_TYPE_ALL = SubscriptionType(str(BUGDIR_TYPE_ALL)) + +INVALID_TYPE = SubscriptionType("INVALID") + +class InvalidType (ValueError): + def __init__(self, type_name, type_root): + msg = "Invalid type %s for tree:\n%s" \ + % (type_name, type_root.string_tree(4)) + ValueError.__init__(self, msg) + self.type_name = type_name + self.type_root = type_root + + +def execute(args, manipulate_encodings=True): + """ + >>> bd = bugdir.SimpleBugDir() + >>> bd.set_sync_with_disk(True) + >>> os.chdir(bd.root) + >>> a = bd.bug_from_shortname("a") + >>> print a.extra_strings + [] + >>> execute(["-s","John Doe ", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + John Doe all * + >>> bd._clear_bugs() # resync our copy of bug + >>> a = bd.bug_from_shortname("a") + >>> print a.extra_strings + ['SUBSCRIBE:John Doe \\tall\\t*'] + >>> execute(["-s","Jane Doe ", "-S", "a.com,b.net", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe all a.com,b.net + John Doe all * + >>> execute(["-s","Jane Doe ", "-S", "a.edu", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe all a.com,a.edu,b.net + John Doe all * + >>> execute(["-u", "-s","Jane Doe ", "-S", "a.com", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe all a.edu,b.net + John Doe all * + >>> execute(["-s","Jane Doe ", "-S", "*", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe all * + John Doe all * + >>> execute(["-u", "-s","Jane Doe ", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + John Doe all * + >>> execute(["-u", "-s","John Doe ", "a"], manipulate_encodings=False) + >>> execute(["-s","Jane Doe ", "-t", "new", "DIR"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for bug directory: + Jane Doe new * + >>> execute(["-s","Jane Doe ", "DIR"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for bug directory: + Jane Doe all * + >>> bd.cleanup() + """ + parser = get_parser() + options, args = parser.parse_args(args) + cmdutil.default_complete(options, args, parser, + bugid_args={0: lambda bug : bug.active==True}) + + if len(args) > 1: + help() + raise cmdutil.UsageError("Too many arguments.") + + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) + + subscriber = options.subscriber + if subscriber == None: + subscriber = bd.user_id + if options.unsubscribe == True: + if options.servers == None: + options.servers = "INVALID" + if options.types == None: + options.types = "INVALID" + else: + if options.servers == None: + options.servers = "*" + if options.types == None: + options.types = "all" + servers = options.servers.split(",") + types = options.types.split(",") + + if len(args) == 0 or args[0] == "DIR": # directory-wide subscriptions + type_root = BUGDIR_TYPE_ALL + entity = bd + entity_name = "bug directory" + else: # bug-specific subscriptions + type_root = BUG_TYPE_ALL + bug = bd.bug_from_shortname(args[0]) + entity = bug + entity_name = bug.uuid + if options.list_all == True: + entity_name = "anything in the bug directory" + + types = [type_from_name(name, type_root, default=INVALID_TYPE, + default_ok=options.unsubscribe) + for name in types] + estrs = entity.extra_strings + if options.list == True or options.list_all == True: + pass + else: # alter subscriptions + if options.unsubscribe == True: + estrs = unsubscribe(estrs, subscriber, types, servers, type_root) + else: # add the tag + estrs = subscribe(estrs, subscriber, types, servers, type_root) + entity.extra_strings = estrs # reassign to notice change + + if options.list_all == True: + bd.load_all_bugs() + subscriptions = get_bugdir_subscribers(bd, servers[0]) + else: + subscriptions = [] + for estr in entity.extra_strings: + if estr.startswith(TAG): + subscriptions.append(estr[len(TAG):]) + + if len(subscriptions) > 0: + print "Subscriptions for %s:" % entity_name + print '\n'.join(subscriptions) + + +def get_parser(): + parser = cmdutil.CmdOptionParser("be subscribe ID") + parser.add_option("-u", "--unsubscribe", action="store_true", + dest="unsubscribe", default=False, + help="Unsubscribe instead of subscribing.") + parser.add_option("-a", "--list-all", action="store_true", + dest="list_all", default=False, + help="List all subscribers (no ID argument, read only action).") + parser.add_option("-l", "--list", action="store_true", + dest="list", default=False, + help="List subscribers (read only action).") + parser.add_option("-s", "--subscriber", dest="subscriber", + metavar="SUBSCRIBER", + help="Email address of the subscriber (defaults to bugdir.user_id).") + parser.add_option("-S", "--servers", dest="servers", metavar="SERVERS", + help="Servers from which you want notification.") + parser.add_option("-t", "--type", dest="types", metavar="TYPES", + help="Types of changes you wish to be notified about.") + return parser + +longhelp=""" +ID can be either a bug id, or blank/"DIR", in which case it refers to the +whole bug directory. + +SERVERS specifies the servers from which you would like to receive +notification. Multiple severs may be specified in a comma-separated +list, or you can use "*" to match all servers (the default). If you +have not selected a server, it should politely refrain from notifying +you of changes, although there is no way to guarantee this behavior. + +Available TYPES: + For bugs: +%s + For DIR : +%s + +For unsubscription, any listed SERVERS and TYPES are removed from your +subscription. Either the catch-all server "*" or type "%s" will +remove SUBSCRIBER entirely from the specified ID. + +This command is intended for use primarily by public interfaces, since +if you're just hacking away on your private repository, you'll known +what's changed ;). This command just (un)sets the appropriate +subscriptions, and leaves it up to each interface to perform the +notification. +""" % (BUG_TYPE_ALL.string_tree(6), BUGDIR_TYPE_ALL.string_tree(6), + BUGDIR_TYPE_ALL) + +def help(): + return get_parser().help_str() + longhelp + +# internal helper functions + +def _generate_string(subscriber, types, servers): + types = sorted([str(t) for t in types]) + servers = sorted(servers) + return "%s%s\t%s\t%s" % (TAG,subscriber,",".join(types),",".join(servers)) + +def _parse_string(string, type_root): + assert string.startswith(TAG), string + string = string[len(TAG):] + subscriber,types,servers = string.split("\t") + types = [type_from_name(name, type_root) for name in types.split(",")] + return (subscriber,types,servers.split(",")) + +def _get_subscriber(extra_strings, subscriber, type_root): + for i,string in enumerate(extra_strings): + if string.startswith(TAG): + s,ts,srvs = _parse_string(string, type_root) + if s == subscriber: + return i,s,ts,srvs # match! + return None # no match + +# functions exposed to other modules + +def type_from_name(name, type_root, default=None, default_ok=False): + if name == str(type_root): + return type_root + for t in type_root.traverse(): + if name == str(t): + return t + if default_ok: + return default + raise InvalidType(name, type_root) + +def subscribe(extra_strings, subscriber, types, servers, type_root): + args = _get_subscriber(extra_strings, subscriber, type_root) + if args == None: # no match + extra_strings.append(_generate_string(subscriber, types, servers)) + return extra_strings + # Alter matched string + i,s,ts,srvs = args + for t in types: + if t not in ts: + ts.append(t) + # remove descendant types + all_ts = copy.copy(ts) + for t in all_ts: + for tt in all_ts: + if tt in ts and t.has_descendant(tt): + ts.remove(tt) + if "*" in servers+srvs: + srvs = ["*"] + else: + srvs = list(set(servers+srvs)) + extra_strings[i] = _generate_string(subscriber, ts, srvs) + return extra_strings + +def unsubscribe(extra_strings, subscriber, types, servers, type_root): + args = _get_subscriber(extra_strings, subscriber, type_root) + if args == None: # no match + return extra_strings # pass + # Remove matched string + i,s,ts,srvs = args + all_ts = copy.copy(ts) + for t in types: + for tt in all_ts: + if tt in ts and t.has_descendant(tt): + ts.remove(tt) + if "*" in servers+srvs: + srvs = [] + else: + for srv in servers: + if srv in srvs: + srvs.remove(srv) + if len(ts) == 0 or len(srvs) == 0: + extra_strings.pop(i) + else: + extra_strings[i] = _generate_string(subscriber, ts, srvs) + return extra_strings + +def get_subscribers(extra_strings, type, server, type_root, + match_ancestor_types=False, + match_descendant_types=False): + """ + Set match_ancestor_types=True if you want to find eveyone who + cares about your particular type. + + Set match_descendant_types=True if you want to find subscribers + who may only care about some subset of your type. This is useful + for generating lists of all the subscribers in a given set of + extra_strings. + + >>> def sgs(*args, **kwargs): + ... return sorted(get_subscribers(*args, **kwargs)) + >>> es = [] + >>> es = subscribe(es, "John Doe ", [BUGDIR_TYPE_ALL], ["a.com"], BUGDIR_TYPE_ALL) + >>> es = subscribe(es, "Jane Doe ", [BUGDIR_TYPE_NEW], ["*"], BUGDIR_TYPE_ALL) + >>> sgs(es, BUGDIR_TYPE_ALL, "a.com", BUGDIR_TYPE_ALL) + ['John Doe '] + >>> sgs(es, BUGDIR_TYPE_ALL, "a.com", BUGDIR_TYPE_ALL, match_descendant_types=True) + ['Jane Doe ', 'John Doe '] + >>> sgs(es, BUGDIR_TYPE_ALL, "b.net", BUGDIR_TYPE_ALL, match_descendant_types=True) + ['Jane Doe '] + >>> sgs(es, BUGDIR_TYPE_NEW, "a.com", BUGDIR_TYPE_ALL) + ['Jane Doe '] + >>> sgs(es, BUGDIR_TYPE_NEW, "a.com", BUGDIR_TYPE_ALL, match_ancestor_types=True) + ['Jane Doe ', 'John Doe '] + """ + for string in extra_strings: + if not string.startswith(TAG): + continue + subscriber,types,servers = _parse_string(string, type_root) + type_match = False + if type in types: + type_match = True + if type_match == False and match_ancestor_types == True: + for t in types: + if t.has_descendant(type): + type_match = True + break + if type_match == False and match_descendant_types == True: + for t in types: + if type.has_descendant(t): + type_match = True + break + server_match = False + if server in servers or servers == ["*"] or server == "*": + server_match = True + if type_match == True and server_match == True: + yield subscriber + +def get_bugdir_subscribers(bugdir, server): + """ + I have a bugdir. Who cares about it, and what do they care about? + Returns a dict of dicts: + subscribers[user][id] = types + where id is either a bug.uuid (in the case of a bug subscription) + or "DIR" (in the case of a bugdir subscription). + + Only checks bugs that are currently in memory, so you might want + to call bugdir.load_all_bugs() first. + + >>> bd = bugdir.SimpleBugDir(sync_with_disk=False) + >>> a = bd.bug_from_shortname("a") + >>> bd.extra_strings = subscribe(bd.extra_strings, "John Doe ", [BUGDIR_TYPE_ALL], ["a.com"], BUGDIR_TYPE_ALL) + >>> bd.extra_strings = subscribe(bd.extra_strings, "Jane Doe ", [BUGDIR_TYPE_NEW], ["*"], BUGDIR_TYPE_ALL) + >>> a.extra_strings = subscribe(a.extra_strings, "John Doe ", [BUG_TYPE_ALL], ["a.com"], BUG_TYPE_ALL) + >>> subscribers = get_bugdir_subscribers(bd, "a.com") + >>> subscribers["Jane Doe "]["DIR"] + [] + >>> subscribers["John Doe "]["DIR"] + [] + >>> subscribers["John Doe "]["a"] + [] + >>> get_bugdir_subscribers(bd, "b.net") + {'Jane Doe ': {'DIR': []}} + >>> bd.cleanup() + """ + subscribers = {} + for sub in get_subscribers(bugdir.extra_strings, BUGDIR_TYPE_ALL, server, + BUGDIR_TYPE_ALL, match_descendant_types=True): + i,s,ts,srvs = _get_subscriber(bugdir.extra_strings,sub,BUGDIR_TYPE_ALL) + subscribers[sub] = {"DIR":ts} + for bug in bugdir: + for sub in get_subscribers(bug.extra_strings, BUG_TYPE_ALL, server, + BUG_TYPE_ALL, match_descendant_types=True): + i,s,ts,srvs = _get_subscriber(bug.extra_strings,sub,BUG_TYPE_ALL) + if sub in subscribers: + subscribers[sub][bug.uuid] = ts + else: + subscribers[sub] = {bug.uuid:ts} + return subscribers diff --git a/becommands/tag.py b/becommands/tag.py index 216ffbc..ecd853f 100644 --- a/becommands/tag.py +++ b/becommands/tag.py @@ -18,34 +18,34 @@ from libbe import cmdutil, bugdir import os, copy __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import utility - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> bd.set_sync_with_disk(True) >>> os.chdir(bd.root) >>> a = bd.bug_from_shortname("a") >>> print a.extra_strings [] - >>> execute(["a", "GUI"], test=True) + >>> execute(["a", "GUI"], manipulate_encodings=False) Tags for a: GUI >>> bd._clear_bugs() # resync our copy of bug >>> a = bd.bug_from_shortname("a") >>> print a.extra_strings ['TAG:GUI'] - >>> execute(["a", "later"], test=True) + >>> execute(["a", "later"], manipulate_encodings=False) Tags for a: GUI later - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) Tags for a: GUI later - >>> execute(["--list"], test=True) + >>> execute(["--list"], manipulate_encodings=False) GUI later - >>> execute(["a", "Alphabetically first"], test=True) + >>> execute(["a", "Alphabetically first"], manipulate_encodings=False) Tags for a: Alphabetically first GUI @@ -57,15 +57,16 @@ def execute(args, test=False): >>> a.extra_strings = [] >>> print a.extra_strings [] - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) >>> bd._clear_bugs() # resync our copy of bug >>> a = bd.bug_from_shortname("a") >>> print a.extra_strings [] - >>> execute(["a", "Alphabetically first"], test=True) + >>> execute(["a", "Alphabetically first"], manipulate_encodings=False) Tags for a: Alphabetically first - >>> execute(["--remove", "a", "Alphabetically first"], test=True) + >>> execute(["--remove", "a", "Alphabetically first"], manipulate_encodings=False) + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -78,7 +79,8 @@ def execute(args, test=False): help() raise cmdutil.UsageError("Too many arguments.") - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if options.list: bd.load_all_bugs() tags = [] @@ -92,7 +94,7 @@ def execute(args, test=False): if len(tags) > 0: print '\n'.join(tags) return - bug = bd.bug_from_shortname(args[0]) + bug = cmdutil.bug_from_shortname(bd, args[0]) if len(args) == 2: given_tag = args[1] estrs = bug.extra_strings diff --git a/becommands/target.py b/becommands/target.py index 527b16a..7e41451 100644 --- a/becommands/target.py +++ b/becommands/target.py @@ -22,21 +22,22 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> import os - >>> bd = bugdir.simple_bug_dir() + >>> bd = bugdir.SimpleBugDir() >>> os.chdir(bd.root) - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) No target assigned. - >>> execute(["a", "tomorrow"], test=True) - >>> execute(["a"], test=True) + >>> execute(["a", "tomorrow"], manipulate_encodings=False) + >>> execute(["a"], manipulate_encodings=False) tomorrow - >>> execute(["--list"], test=True) + >>> execute(["--list"], manipulate_encodings=False) tomorrow - >>> execute(["a", "none"], test=True) - >>> execute(["a"], test=True) + >>> execute(["a", "none"], manipulate_encodings=False) + >>> execute(["a"], manipulate_encodings=False) No target assigned. + >>> bd.cleanup() """ parser = get_parser() options, args = parser.parse_args(args) @@ -46,14 +47,15 @@ def execute(args, test=False): if len(args) not in (1, 2): if not (options.list == True and len(args) == 0): raise cmdutil.UsageError - bd = bugdir.BugDir(from_disk=True, manipulate_encodings=not test) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if options.list: ts = set([bd.bug_from_uuid(bug).target for bug in bd.list_uuids()]) for target in sorted(ts): if target and isinstance(target,str): print target return - bug = bd.bug_from_shortname(args[0]) + bug = cmdutil.bug_from_shortname(bd, args[0]) if len(args) == 1: if bug.target is None: print "No target assigned." -- cgit From d34b3a3f0ff18857adb79bbdf46c8c37e22389f8 Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Sat, 3 Oct 2009 00:05:16 +0200 Subject: Added the initial support for css templates --- becommands/html.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 908c714..0ddbb6c 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -49,9 +49,15 @@ def execute(args, manipulate_encodings=True): cmdutil.default_complete(options, args, parser, bugid_args={0: lambda bug : bug.active==False}) + if len(args) == 0: out_dir = options.outdir - print "Creating the html output in %s"%out_dir + css_file = options.css_file + if css_file == None: + _css_file = "default" + else: + _css_file = css_file + print "Creating the html output in %s using %s style"%(out_dir, _css_file) else: out_dir = args[0] if len(args) > 0: @@ -80,14 +86,16 @@ def execute(args, manipulate_encodings=True): ordered_bug_list_in = sorted([(value,key) for (key,value) in stime.items()]) #open_bug_list = sorted([(value,key) for (key,value) in bugs.items()]) - html_gen = BEHTMLGen(bd) + html_gen = BEHTMLGen(bd, css_file) html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active", bd.encoding) html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding) def get_parser(): parser = cmdutil.CmdOptionParser("be open OUTPUT_DIR") parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", - help="Set the output path, default is ./html_export", default="html_export") + help="Set the output path, default is ./html_export", default="html_export") + parser.add_option("-s", "--css-file", metavar="css_file", dest="css_file", + help="Use a different css file, default is empty", default=None) return parser longhelp=""" @@ -116,10 +124,10 @@ def escape(string): return "".join(chars) class BEHTMLGen(): - def __init__(self, bd): + def __init__(self, bd, template): self.index_value = "" self.bd = bd - + self.css_file = """ body { font-family: "lucida grande", "sans serif"; @@ -473,8 +481,13 @@ class BEHTMLGen(): - """ + """ + if template != None: + FO = open(template) + newCss = FO.read() + FO.close() + self.css_file = newCss def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): try: -- cgit From 877db84d2851680e8552c1d63a670155947aff9d Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Mon, 5 Oct 2009 23:51:13 +0200 Subject: help --- becommands/html.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 0ddbb6c..22bad5b 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -44,12 +44,13 @@ def execute(args, manipulate_encodings=True): >>> bd.cleanup() """ parser = get_parser() + options, args = parser.parse_args(args) complete(options, args, parser) cmdutil.default_complete(options, args, parser, bugid_args={0: lambda bug : bug.active==False}) - + if len(args) == 0: out_dir = options.outdir css_file = options.css_file @@ -57,7 +58,8 @@ def execute(args, manipulate_encodings=True): _css_file = "default" else: _css_file = css_file - print "Creating the html output in %s using %s style"%(out_dir, _css_file) + if options.verbose != None: + print "Creating the html output in %s using %s style"%(out_dir, _css_file) else: out_dir = args[0] if len(args) > 0: @@ -91,11 +93,13 @@ def execute(args, manipulate_encodings=True): html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding) def get_parser(): - parser = cmdutil.CmdOptionParser("be open OUTPUT_DIR") + parser = cmdutil.CmdOptionParser("be html [-v][-o][-s]") parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", help="Set the output path, default is ./html_export", default="html_export") parser.add_option("-s", "--css-file", metavar="css_file", dest="css_file", help="Use a different css file, default is empty", default=None) + parser.add_option("-v", "--verbose", metavar="verbose", dest="verbose", + help="Verbose output, default is no", default=None) return parser longhelp=""" -- cgit From cd8770308038114c79313fdc33a624f5e60468c0 Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Tue, 6 Oct 2009 00:08:11 +0200 Subject: Added the verbose option --- becommands/html.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 22bad5b..78364a0 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -44,12 +44,10 @@ def execute(args, manipulate_encodings=True): >>> bd.cleanup() """ parser = get_parser() - options, args = parser.parse_args(args) complete(options, args, parser) cmdutil.default_complete(options, args, parser, bugid_args={0: lambda bug : bug.active==False}) - if len(args) == 0: out_dir = options.outdir @@ -58,7 +56,7 @@ def execute(args, manipulate_encodings=True): _css_file = "default" else: _css_file = css_file - if options.verbose != None: + if options.verbose == True: print "Creating the html output in %s using %s style"%(out_dir, _css_file) else: out_dir = args[0] @@ -88,18 +86,18 @@ def execute(args, manipulate_encodings=True): ordered_bug_list_in = sorted([(value,key) for (key,value) in stime.items()]) #open_bug_list = sorted([(value,key) for (key,value) in bugs.items()]) - html_gen = BEHTMLGen(bd, css_file) + html_gen = BEHTMLGen(bd, css_file, options.verbose) html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active", bd.encoding) html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding) def get_parser(): - parser = cmdutil.CmdOptionParser("be html [-v][-o][-s]") + parser = cmdutil.CmdOptionParser("be html [options]") parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", help="Set the output path, default is ./html_export", default="html_export") parser.add_option("-s", "--css-file", metavar="css_file", dest="css_file", help="Use a different css file, default is empty", default=None) - parser.add_option("-v", "--verbose", metavar="verbose", dest="verbose", - help="Verbose output, default is no", default=None) + parser.add_option("-v", "--verbose", action="store_true", metavar="verbose", dest="verbose", + help="Verbose output, default is no", default=False) return parser longhelp=""" @@ -128,10 +126,10 @@ def escape(string): return "".join(chars) class BEHTMLGen(): - def __init__(self, bd, template): + def __init__(self, bd, template, verbose): self.index_value = "" self.bd = bd - + self.verbose = verbose self.css_file = """ body { font-family: "lucida grande", "sans serif"; @@ -515,9 +513,13 @@ class BEHTMLGen(): try: if fileid == "active": + if self.verbose: + print "Creating active bug index..." FO = codecs.open(out_dir_path+"/index.html", "w", encoding) FO.write(self.index_first%('td_sel','td_nsel')) if fileid == "inactive": + if self.verbose: + print "Creating inactive bug index..." FO = codecs.open(out_dir_path+"/index_inactive.html", "w", encoding) FO.write(self.index_first%('td_nsel','td_sel')) except: @@ -526,6 +528,8 @@ class BEHTMLGen(): c = 0 t = len(bugs) - 1 for l in range(t, -1, -1): + if self.verbose: + print "Creating bug entry: %s"%escape(bugs[l].uuid[0:3]) line = self.bug_line%(escape(bugs[l].severity), escape(bugs[l].uuid), escape(bugs[l].uuid[0:3]), escape(bugs[l].uuid), escape(bugs[l].status), @@ -535,6 +539,8 @@ class BEHTMLGen(): ) FO.write(line) c += 1 + if self.verbose: + print "\tCreating detail entry for bug: %s"%escape(bugs[l].uuid[0:3]) self.create_detail_file(bugs[l], out_dir_path, fileid, encoding) when = time.ctime() FO.write(self.index_last%when) -- cgit From 828721071e6283fbf7397ad7ad4b98c5d6ee49bc Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Tue, 6 Oct 2009 00:35:47 +0200 Subject: Initial implementation of a template system --- becommands/html.py | 277 +++-------------------------------------------------- 1 file changed, 14 insertions(+), 263 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 78364a0..f943258 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -51,13 +51,13 @@ def execute(args, manipulate_encodings=True): if len(args) == 0: out_dir = options.outdir - css_file = options.css_file - if css_file == None: + template = options.template + if template == None: _css_file = "default" else: - _css_file = css_file + _css_file = template if options.verbose == True: - print "Creating the html output in %s using %s style"%(out_dir, _css_file) + print "Creating the html output in %s using %s template"%(out_dir, _css_file) else: out_dir = args[0] if len(args) > 0: @@ -86,7 +86,7 @@ def execute(args, manipulate_encodings=True): ordered_bug_list_in = sorted([(value,key) for (key,value) in stime.items()]) #open_bug_list = sorted([(value,key) for (key,value) in bugs.items()]) - html_gen = BEHTMLGen(bd, css_file, options.verbose) + html_gen = BEHTMLGen(bd, template, options.verbose) html_gen.create_index_file(out_dir, st, bugs_active, ordered_bug_list, "active", bd.encoding) html_gen.create_index_file(out_dir, st, bugs_inactive, ordered_bug_list, "inactive", bd.encoding) @@ -94,8 +94,8 @@ def get_parser(): parser = cmdutil.CmdOptionParser("be html [options]") parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", help="Set the output path, default is ./html_export", default="html_export") - parser.add_option("-s", "--css-file", metavar="css_file", dest="css_file", - help="Use a different css file, default is empty", default=None) + parser.add_option("-t", "--template", metavar="template", dest="template", + help="Use a different template, default is empty", default=None) parser.add_option("-v", "--verbose", action="store_true", metavar="verbose", dest="verbose", help="Verbose output, default is no", default=False) return parser @@ -130,257 +130,13 @@ class BEHTMLGen(): self.index_value = "" self.bd = bd self.verbose = verbose - self.css_file = """ - body { - font-family: "lucida grande", "sans serif"; - color: #333; - width: auto; - margin: auto; - } - - - div.main { - padding: 20px; - margin: auto; - padding-top: 0; - margin-top: 1em; - background-color: #fcfcfc; - } - - .comment { - padding: 20px; - margin: auto; - padding-top: 20px; - margin-top: 0; - } - - .commentF { - padding: 0px; - margin: auto; - padding-top: 0px; - paddin-bottom: 20px; - margin-top: 0; - } - - tb { - border = 1; - } - - .wishlist-row { - background-color: #B4FF9B; - width: auto; - } - - .minor-row { - background-color: #FCFF98; - width: auto; - } - - - .serious-row { - background-color: #FFB648; - width: auto; - } - - .critical-row { - background-color: #FF752A; - width: auto; - } - - .fatal-row { - background-color: #FF3300; - width: auto; - } - - .person { - font-family: courier; - } - - a, a:visited { - background: inherit; - text-decoration: none; - } - - a { - color: #003d41; - } - - a:visited { - color: #553d41; - } - - ul { - list-style-type: none; - padding: 0; - } - - p { - width: auto; - } - - .inline-status-image { - position: relative; - top: 0.2em; - } - - .dimmed { - color: #bbb; - } - - table { - border-style: 10px solid #313131; - border-spacing: 0; - width: auto; - } - - table.log { - } - - td { - border-width: 0; - border-style: none; - padding-right: 0.5em; - padding-left: 0.5em; - width: auto; - } - - .td_sel { - background-color: #afafaf; - border: 1px solid #afafaf; - font-weight:bold; - padding-right: 1em; - padding-left: 1em; - - } - - .td_nsel { - border: 0px; - padding-right: 1em; - padding-left: 1em; - } - - tr { - vertical-align: top; - width: auto; - } - - h1 { - padding: 0.5em; - background-color: #305275; - margin-top: 0; - margin-bottom: 0; - color: #fff; - margin-left: -20px; - margin-right: -20px; - } - - wid { - text-transform: uppercase; - font-size: smaller; - margin-top: 1em; - margin-left: -0.5em; - /*background: #fffbce;*/ - /*background: #628a0d;*/ - padding: 5px; - color: #305275; - } - - .attrname { - text-align: right; - font-size: smaller; - } - - .attrval { - color: #222; - } - - .issue-closed-fixed { - background-image: "green-check.png"; - } - - .issue-closed-wontfix { - background-image: "red-check.png"; - } - - .issue-closed-reorg { - background-image: "blue-check.png"; - } - - .inline-issue-link { - text-decoration: underline; - } - - img { - border: 0; - } - - - div.footer { - font-size: small; - padding-left: 20px; - padding-right: 20px; - padding-top: 5px; - padding-bottom: 5px; - margin: auto; - background: #305275; - color: #fffee7; - } - - .footer a { - color: #508d91; - } - - - .header { - font-family: "lucida grande", "sans serif"; - font-size: smaller; - background-color: #a9a9a9; - text-align: left; - - padding-right: 0.5em; - padding-left: 0.5em; - - } - - - .selected-cell { - background-color: #e9e9e2; - } - - .plain-cell { - background-color: #f9f9f9; - } - - - .logcomment { - padding-left: 4em; - font-size: smaller; - } - - .id { - font-family: courier; - } - - .table_bug { - background-color: #afafaf; - border: 2px solid #afafaf; - } - - .message { - } - - .progress-meter-done { - background-color: #03af00; - } - - .progress-meter-undone { - background-color: #ddd; - } - - .progress-meter { - } - - """ + if template == None: + self.template = "default" + else: + self.template = template + FI = open("./templates/%s/style.css"%self.template) + self.css_file = FI.read() + FI.close() self.index_first = """ """ - if template != None: - FO = open(template) - newCss = FO.read() - FO.close() - self.css_file = newCss def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): try: -- cgit From c65661ce0bcacf67169faf3f62d495a1e8269aa8 Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Wed, 7 Oct 2009 20:41:49 +0200 Subject: Updated to trunk --- becommands/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'becommands') diff --git a/becommands/init.py b/becommands/init.py index 1125d93..a6098ba 100644 --- a/becommands/init.py +++ b/becommands/init.py @@ -32,7 +32,7 @@ def execute(args, manipulate_encodings=True): >>> execute(['--root', dir.path], manipulate_encodings=False) No revision control detected. Directory initialized. - >>> del(dir) + >>> dir.cleanup() >>> dir = utility.Dir() >>> os.chdir(dir.path) -- cgit From 32a16930caa09094b97069f08d504fa5d0f9514a Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Thu, 8 Oct 2009 00:41:31 +0200 Subject: Template system v1 completed --- becommands/html.py | 345 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 315 insertions(+), 30 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index f943258..084aa64 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -94,7 +94,7 @@ def get_parser(): parser = cmdutil.CmdOptionParser("be html [options]") parser.add_option("-o", "--output", metavar="export_dir", dest="outdir", help="Set the output path, default is ./html_export", default="html_export") - parser.add_option("-t", "--template", metavar="template", dest="template", + parser.add_option("-t", "--template-dir", metavar="template", dest="template", help="Use a different template, default is empty", default=None) parser.add_option("-v", "--verbose", action="store_true", metavar="verbose", dest="verbose", help="Verbose output, default is no", default=False) @@ -134,35 +134,283 @@ class BEHTMLGen(): self.template = "default" else: self.template = template - FI = open("./templates/%s/style.css"%self.template) - self.css_file = FI.read() - FI.close() + + self.css_file = """ + body { + font-family: "lucida grande", "sans serif"; + color: #333; + width: auto; + margin: auto; + } + + + div.main { + padding: 20px; + margin: auto; + padding-top: 0; + margin-top: 1em; + background-color: #fcfcfc; + } + + .comment { + padding: 20px; + margin: auto; + padding-top: 20px; + margin-top: 0; + } + + .commentF { + padding: 0px; + margin: auto; + padding-top: 0px; + paddin-bottom: 20px; + margin-top: 0; + } + + tb { + border = 1; + } + + .wishlist-row { + background-color: #B4FF9B; + width: auto; + } + + .minor-row { + background-color: #FCFF98; + width: auto; + } + + + .serious-row { + background-color: #FFB648; + width: auto; + } + + .critical-row { + background-color: #FF752A; + width: auto; + } + + .fatal-row { + background-color: #FF3300; + width: auto; + } + + .person { + font-family: courier; + } + + a, a:visited { + background: inherit; + text-decoration: none; + } + + a { + color: #003d41; + } + + a:visited { + color: #553d41; + } + + ul { + list-style-type: none; + padding: 0; + } + + p { + width: auto; + } + + .inline-status-image { + position: relative; + top: 0.2em; + } + + .dimmed { + color: #bbb; + } + + table { + border-style: 10px solid #313131; + border-spacing: 0; + width: auto; + } + + table.log { + } + + td { + border-width: 0; + border-style: none; + padding-right: 0.5em; + padding-left: 0.5em; + width: auto; + } + + .td_sel { + background-color: #afafaf; + border: 1px solid #afafaf; + font-weight:bold; + padding-right: 1em; + padding-left: 1em; + + } + + .td_nsel { + border: 0px; + padding-right: 1em; + padding-left: 1em; + } + + tr { + vertical-align: top; + width: auto; + } + + h1 { + padding: 0.5em; + background-color: #305275; + margin-top: 0; + margin-bottom: 0; + color: #fff; + margin-left: -20px; + margin-right: -20px; + } + + wid { + text-transform: uppercase; + font-size: smaller; + margin-top: 1em; + margin-left: -0.5em; + /*background: #fffbce;*/ + /*background: #628a0d;*/ + padding: 5px; + color: #305275; + } + + .attrname { + text-align: right; + font-size: smaller; + } + + .attrval { + color: #222; + } + + .issue-closed-fixed { + background-image: "green-check.png"; + } + + .issue-closed-wontfix { + background-image: "red-check.png"; + } + + .issue-closed-reorg { + background-image: "blue-check.png"; + } + + .inline-issue-link { + text-decoration: underline; + } + + img { + border: 0; + } + + + div.footer { + font-size: small; + padding-left: 20px; + padding-right: 20px; + padding-top: 5px; + padding-bottom: 5px; + margin: auto; + background: #305275; + color: #fffee7; + } + + .footer a { + color: #508d91; + } + + + .header { + font-family: "lucida grande", "sans serif"; + font-size: smaller; + background-color: #a9a9a9; + text-align: left; + + padding-right: 0.5em; + padding-left: 0.5em; + + } + + + .selected-cell { + background-color: #e9e9e2; + } + + .plain-cell { + background-color: #f9f9f9; + } + + + .logcomment { + padding-left: 4em; + font-size: smaller; + } + + .id { + font-family: courier; + } + + .table_bug { + background-color: #afafaf; + border: 2px solid #afafaf; + } + + .message { + } + + .progress-meter-done { + background-color: #03af00; + } + + .progress-meter-undone { + background-color: #ddd; + } + + .progress-meter { + } + """ self.index_first = """ - - - - BugsEverywhere Issue Tracker - - - - - - -
-

BugsEverywhere Bug List

-

-
Comments: + Comments: """ @@ -452,7 +476,7 @@ class BEHTMLGen(): """ - def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid): + def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): try: os.stat(out_dir_path) except: @@ -461,7 +485,7 @@ class BEHTMLGen(): except: raise cmdutil.UsageError, "Cannot create output directory." try: - FO = open(out_dir_path+"/style.css", "w") + FO = codecs.open(out_dir_path+"/style.css", "w", encoding) FO.write(self.css_file) FO.close() except: @@ -474,10 +498,10 @@ class BEHTMLGen(): try: if fileid == "active": - FO = open(out_dir_path+"/index.html", "w") + FO = codecs.open(out_dir_path+"/index.html", "w", encoding) FO.write(self.index_first%('td_sel','td_nsel')) if fileid == "inactive": - FO = open(out_dir_path+"/index_inactive.html", "w") + FO = codecs.open(out_dir_path+"/index_inactive.html", "w", encoding) FO.write(self.index_first%('td_nsel','td_sel')) except: raise cmdutil.UsageError, "Cannot create the index.html file." @@ -485,25 +509,25 @@ class BEHTMLGen(): c = 0 t = len(bugs) - 1 for l in range(t, -1, -1): - line = self.bug_line%(bugs[l].severity, - bugs[l].uuid, bugs[l].uuid[0:3], - bugs[l].uuid, bugs[l].status, - bugs[l].uuid, bugs[l].severity, - bugs[l].uuid, bugs[l].summary, - bugs[l].uuid, bugs[l].time_string - ) + line = self.bug_line%(escape(bugs[l].severity), + escape(bugs[l].uuid), escape(bugs[l].uuid[0:3]), + escape(bugs[l].uuid), escape(bugs[l].status), + escape(bugs[l].uuid), escape(bugs[l].severity), + escape(bugs[l].uuid), escape(bugs[l].summary), + escape(bugs[l].uuid), escape(bugs[l].time_string) + ) FO.write(line) c += 1 - self.create_detail_file(bugs[l], out_dir_path, fileid) + self.create_detail_file(bugs[l], out_dir_path, fileid, encoding) when = time.ctime() FO.write(self.index_last%when) - def create_detail_file(self, bug, out_dir_path, fileid): + def create_detail_file(self, bug, out_dir_path, fileid, encoding): f = "%s.html"%bug.uuid p = out_dir_path+"/bugs/"+f try: - FD = open(p, "w") + FD = codecs.open(p, "w", encoding) except: raise cmdutil.UsageError, "Cannot create the detail html file." @@ -519,53 +543,41 @@ class BEHTMLGen(): bug_.load_comments(load_full=True) FD.write(self.detail_line%("ID : ", bug.uuid)) - FD.write(self.detail_line%("Short name : ", bug.uuid[0:3])) - FD.write(self.detail_line%("Severity : ", bug.severity)) - FD.write(self.detail_line%("Status : ", bug.status)) - FD.write(self.detail_line%("Assigned : ", bug.assigned)) - FD.write(self.detail_line%("Target : ", bug.target)) - FD.write(self.detail_line%("Reporter : ", bug.reporter)) - FD.write(self.detail_line%("Creator : ", bug.creator)) - FD.write(self.detail_line%("Created : ", bug.time_string)) - FD.write(self.detail_line%("Summary : ", bug.summary)) - FD.write("


- - - - - - -
Active BugsInactive Bugs
- - + + + + BugsEverywhere Issue Tracker + + + + + + +
+

BugsEverywhere Bug List

+

+
+ + + + + + +
Active BugsInactive Bugs
+ + """ % self.bd.encoding self.bug_line =""" @@ -195,8 +443,6 @@ class BEHTMLGen(): """ % self.bd.encoding - - self.detail_line =""" @@ -241,6 +487,45 @@ class BEHTMLGen(): """ + if template != None: + try: + FI = open("%s/style.css"%self.template) + self.css_file = FI.read() + FI.close() + except: + pass + try: + FI = open("%s/index_first.tpl"%self.template) + self.index_first = FI.read() + FI.close() + except: + pass + try: + FI.open("%s/bug_line.tpl"%self.template) + self.bug_line = FI.read() + FI.close() + except: + pass + try: + FI.open("%s/detail_first.tpl"%self.template) + self.detail_first = FI.read() + FI.close() + except: + pass + try: + FI = open("%s/index_last.tpl"%self.template) + self.index_last = FI.read() + FI.close() + except: + pass + try: + FI = open("%s/detail_last.tpl"%self.template) + self.d_last = FI.read() + FI.close() + except: + pass + + def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): try: -- cgit From b4cb35d3ab73d50881b2ebac0a4368baf84ca2b7 Mon Sep 17 00:00:00 2001 From: Gianluca Montecchi Date: Thu, 8 Oct 2009 01:17:03 +0200 Subject: Partially moved to a newer, better and simpler template system --- becommands/html.py | 148 +++++++++++++++++++++++++---------------------------- 1 file changed, 70 insertions(+), 78 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 084aa64..38b6012 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -386,7 +386,7 @@ class BEHTMLGen(): } """ - self.index_first = """ + self.index_file = """ @@ -404,14 +404,26 @@ class BEHTMLGen():
%s%s
- - + +
Active BugsInactive BugsActive BugsInactive Bugs
- """ % self.bd.encoding + + %s + + +
+ + + + + + + + """ self.bug_line =""" @@ -423,7 +435,7 @@ class BEHTMLGen(): """ - self.detail_first = """ + self.detail_file = """ @@ -437,30 +449,32 @@ class BEHTMLGen():

BugsEverywhere Bug List

-
Back to Index
+
Back to Index

Bug: _bug_id_

- """ % self.bd.encoding - self.detail_line =""" - - - - """ + %s + - self.index_last = """
%s%s
-
- - - +
Back to Index
+ + """ + self.detail_line =""" + + %s%s + + """ + + + self.comment_section = """ """ @@ -476,17 +490,7 @@ class BEHTMLGen(): """ - - self.detail_last = """ - - - -
Back to Index
- - - - """ - + if template != None: try: FI = open("%s/style.css"%self.template) @@ -495,39 +499,22 @@ class BEHTMLGen(): except: pass try: - FI = open("%s/index_first.tpl"%self.template) + FI = open("%s/index_file.tpl"%self.template) self.index_first = FI.read() FI.close() except: pass + try: - FI.open("%s/bug_line.tpl"%self.template) - self.bug_line = FI.read() - FI.close() - except: - pass - try: - FI.open("%s/detail_first.tpl"%self.template) + FI.open("%s/detail_file.tpl"%self.template) self.detail_first = FI.read() FI.close() except: pass - try: - FI = open("%s/index_last.tpl"%self.template) - self.index_last = FI.read() - FI.close() - except: - pass - try: - FI = open("%s/detail_last.tpl"%self.template) - self.d_last = FI.read() - FI.close() - except: - pass - - + def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): + try: os.stat(out_dir_path) except: @@ -552,34 +539,43 @@ class BEHTMLGen(): if self.verbose: print "Creating active bug index..." FO = codecs.open(out_dir_path+"/index.html", "w", encoding) - FO.write(self.index_first%('td_sel','td_nsel')) if fileid == "inactive": if self.verbose: print "Creating inactive bug index..." FO = codecs.open(out_dir_path+"/index_inactive.html", "w", encoding) - FO.write(self.index_first%('td_nsel','td_sel')) except: raise cmdutil.UsageError, "Cannot create the index.html file." c = 0 t = len(bugs) - 1 + line = "" for l in range(t, -1, -1): if self.verbose: print "Creating bug entry: %s"%escape(bugs[l].uuid[0:3]) - line = self.bug_line%(escape(bugs[l].severity), + line += self.bug_line%(escape(bugs[l].severity), escape(bugs[l].uuid), escape(bugs[l].uuid[0:3]), escape(bugs[l].uuid), escape(bugs[l].status), escape(bugs[l].uuid), escape(bugs[l].severity), escape(bugs[l].uuid), escape(bugs[l].summary), escape(bugs[l].uuid), escape(bugs[l].time_string) ) - FO.write(line) c += 1 if self.verbose: print "\tCreating detail entry for bug: %s"%escape(bugs[l].uuid[0:3]) self.create_detail_file(bugs[l], out_dir_path, fileid, encoding) when = time.ctime() - FO.write(self.index_last%when) + + try: + if fileid == "active": + if self.verbose: + print "Writing active bug index..." + FO.write(self.index_file%(encoding, 'td_sel','td_nsel', line, when)) + if fileid == "inactive": + if self.verbose: + print "Writing inactive bug index..." + FO.write(self.index_file%(encoding,'td_nsel','td_sel', line, when)) + except: + raise cmdutil.UsageError, "Cannot create the index.html file." def create_detail_file(self, bug, out_dir_path, fileid, encoding): @@ -590,28 +586,28 @@ class BEHTMLGen(): except: raise cmdutil.UsageError, "Cannot create the detail html file." - detail_first_ = re.sub('_bug_id_', bug.uuid[0:3], self.detail_first) - if fileid == "active": - FD.write(detail_first_%"../index.html") - if fileid == "inactive": - FD.write(detail_first_%"../index_inactive.html") - - - + detail_file_ = re.sub('_bug_id_', bug.uuid[0:3], self.detail_file) + bug_ = self.bd.bug_from_shortname(bug.uuid) bug_.load_comments(load_full=True) + det_line = "" + det_line += self.detail_line%("ID : ", bug.uuid) + det_line += self.detail_line%("Short name : ", escape(bug.uuid[0:3])) + det_line += self.detail_line%("Severity : ", escape(bug.severity)) + det_line += self.detail_line%("Status : ", escape(bug.status)) + det_line += self.detail_line%("Assigned : ", escape(bug.assigned)) + det_line += self.detail_line%("Target : ", escape(bug.target)) + det_line += self.detail_line%("Reporter : ", escape(bug.reporter)) + det_line += self.detail_line%("Creator : ", escape(bug.creator)) + det_line += self.detail_line%("Created : ", escape(bug.time_string)) + det_line += self.detail_line%("Summary : ", escape(bug.summary)) + det_line += """
""" - FD.write(self.detail_line%("ID : ", bug.uuid)) - FD.write(self.detail_line%("Short name : ", escape(bug.uuid[0:3]))) - FD.write(self.detail_line%("Severity : ", escape(bug.severity))) - FD.write(self.detail_line%("Status : ", escape(bug.status))) - FD.write(self.detail_line%("Assigned : ", escape(bug.assigned))) - FD.write(self.detail_line%("Target : ", escape(bug.target))) - FD.write(self.detail_line%("Reporter : ", escape(bug.reporter))) - FD.write(self.detail_line%("Creator : ", escape(bug.creator))) - FD.write(self.detail_line%("Created : ", escape(bug.time_string))) - FD.write(self.detail_line%("Summary : ", escape(bug.summary))) - FD.write("
") + if fileid == "active": + FD.write(detail_file_%(encoding, "../index.html", det_line, "../index.html")) + if fileid == "inactive": + FD.write(detail_file_%(encoding, "../index_inactive.html", det_line, "../index_inactive.html")) + FD.write(self.begin_comment_section) tr = [] b = '' @@ -638,10 +634,6 @@ class BEHTMLGen(): stack.pop(-1) FD.write("\n") # close every remaining
Date: Thu, 8 Oct 2009 22:18:50 +0200 Subject: Reworked the html command template system --- becommands/html.py | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'becommands') diff --git a/becommands/html.py b/becommands/html.py index 38b6012..d5c4771 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -456,7 +456,7 @@ class BEHTMLGen(): %s - + %s
@@ -472,21 +472,14 @@ class BEHTMLGen(): %s%s """ - - self.comment_section = """ - """ - - self.begin_comment_section =""" + self.comment_section =""" Comments: - """ - - - self.end_comment_section =""" + %s """ @@ -511,7 +504,12 @@ class BEHTMLGen(): FI.close() except: pass - + try: + FI.open("%s/comment_section.tpl"%self.template) + self.comment_section = FI.read() + FI.close() + except: + pass def create_index_file(self, out_dir_path, summary, bugs, ordered_bug, fileid, encoding): @@ -602,21 +600,16 @@ class BEHTMLGen(): det_line += self.detail_line%("Created : ", escape(bug.time_string)) det_line += self.detail_line%("Summary : ", escape(bug.summary)) det_line += """
""" - - if fileid == "active": - FD.write(detail_file_%(encoding, "../index.html", det_line, "../index.html")) - if fileid == "inactive": - FD.write(detail_file_%(encoding, "../index_inactive.html", det_line, "../index_inactive.html")) - - FD.write(self.begin_comment_section) + tr = [] b = '' level = 0 stack = [] + com = "" for depth,comment in bug_.comment_root.thread(flatten=False): while len(stack) > depth: stack.pop(-1) # pop non-parents off the stack - FD.write("\n") # close non-parent
\n" # close non-parent
') + com += '
' else: - FD.write('
') - FD.write("
\n".join(lines)+"
\n") + com += '
' + #FD.write("
\n".join(lines)+"
\n") + com += "
\n".join(lines)+"
\n" while len(stack) > 0: stack.pop(-1) - FD.write("
\n") # close every remaining
\n" # close every remaining