From 49a7771336ce09f6d42c7699ef32aecea0e83182 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 7 Dec 2009 20:07:55 -0500 Subject: Initial directory restructuring to clarify dependencies --- libbe/command/merge.py | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 libbe/command/merge.py (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py new file mode 100644 index 0000000..ac09b40 --- /dev/null +++ b/libbe/command/merge.py @@ -0,0 +1,166 @@ +# Copyright (C) 2008-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 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. +"""Merge duplicate bugs""" +from libbe import cmdutil, bugdir +import os, copy +__desc__ = __doc__ + +def execute(args, manipulate_encodings=True, restrict_file_access=False, + dir="."): + """ + >>> from libbe import utility + >>> bd = bugdir.SimpleBugDir() + >>> bd.set_sync_with_disk(True) + >>> a = bd.bug_from_shortname("a") + >>> a.comment_root.time = 0 + >>> dummy = a.new_comment("Testing") + >>> dummy.time = 1 + >>> dummy = dummy.new_reply("Testing...") + >>> dummy.time = 2 + >>> b = bd.bug_from_shortname("b") + >>> b.status = "open" + >>> b.comment_root.time = 0 + >>> dummy = b.new_comment("1 2") + >>> dummy.time = 1 + >>> dummy = dummy.new_reply("1 2 3 4") + >>> dummy.time = 2 + >>> os.chdir(bd.root) + >>> execute(["a", "b"], manipulate_encodings=False) + Merging bugs a and b + >>> bd._clear_bugs() + >>> a = bd.bug_from_shortname("a") + >>> a.load_comments() + >>> mergeA = a.comment_from_shortname(":3") + >>> mergeA.time = 3 + >>> print a.string(show_comments=True) # doctest: +ELLIPSIS + ID : a + Short name : a + Severity : minor + Status : open + Assigned : + Reporter : + Creator : John Doe + Created : ... + Bug A + --------- Comment --------- + Name: a:1 + From: ... + Date: ... + + Testing + --------- Comment --------- + Name: a:2 + From: ... + Date: ... + + Testing... + --------- Comment --------- + Name: a:3 + From: ... + Date: ... + + Merged from bug b + --------- Comment --------- + Name: a:4 + From: ... + Date: ... + + 1 2 + --------- Comment --------- + Name: a:5 + From: ... + Date: ... + + 1 2 3 4 + >>> b = bd.bug_from_shortname("b") + >>> b.load_comments() + >>> mergeB = b.comment_from_shortname(":3") + >>> mergeB.time = 3 + >>> print b.string(show_comments=True) # doctest: +ELLIPSIS + ID : b + Short name : b + Severity : minor + Status : closed + Assigned : + Reporter : + Creator : Jane Doe + Created : ... + Bug B + --------- Comment --------- + Name: b:1 + From: ... + Date: ... + + 1 2 + --------- Comment --------- + Name: b:2 + From: ... + Date: ... + + 1 2 3 4 + --------- Comment --------- + Name: b:3 + From: ... + Date: ... + + Merged into bug a + >>> print b.status + closed + >>> 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, + 1: lambda bug : bug.active==True}) + + if len(args) < 2: + raise cmdutil.UsageError("Please specify two bug ids.") + if len(args) > 2: + help() + raise cmdutil.UsageError("Too many arguments.") + + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings, + root=dir) + bugA = cmdutil.bug_from_id(bd, args[0]) + bugA.load_comments() + bugB = cmdutil.bug_from_id(bd, args[1]) + bugB.load_comments() + mergeA = bugA.new_comment("Merged from bug %s" % bugB.uuid) + newCommTree = copy.deepcopy(bugB.comment_root) + for comment in newCommTree.traverse(): # all descendant comments + comment.bug = bugA + 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" + print "Merging bugs %s and %s" % (bugA.uuid, bugB.uuid) + +def get_parser(): + parser = cmdutil.CmdOptionParser("be merge BUG-ID BUG-ID") + return parser + +longhelp=""" +The second bug (B) is merged into the first (A). This adds merge +comments to both bugs, closes B, and appends B's comment tree to A's +merge comment. +""" + +def help(): + return get_parser().help_str() + longhelp -- cgit From 0f87a22c20a019f49455005542d4c60216ce39d2 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 14 Dec 2009 20:13:30 -0500 Subject: Transitioned merge to Command-format --- libbe/command/merge.py | 164 +++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 72 deletions(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index ac09b40..4624ab7 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -14,41 +14,52 @@ # 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 -__desc__ = __doc__ -def execute(args, manipulate_encodings=True, restrict_file_access=False, - dir="."): - """ - >>> from libbe import utility - >>> bd = bugdir.SimpleBugDir() - >>> bd.set_sync_with_disk(True) - >>> a = bd.bug_from_shortname("a") +import copy +import os + +import libbe +import libbe.command +import libbe.command.util + + +class Merge (libbe.command.Command): + """Merge duplicate bugs + + >>> import sys + >>> import libbe.bugdir + >>> import libbe.comment + >>> bd = libbe.bugdir.SimpleBugDir(memory=False) + >>> cmd = Merge() + >>> cmd._setup_io = lambda i_enc,o_enc : None + >>> cmd.stdout = sys.stdout + + >>> a = bd.bug_from_uuid('a') >>> a.comment_root.time = 0 - >>> dummy = a.new_comment("Testing") + >>> dummy = a.new_comment('Testing') >>> dummy.time = 1 - >>> dummy = dummy.new_reply("Testing...") + >>> dummy = dummy.new_reply('Testing...') >>> dummy.time = 2 - >>> b = bd.bug_from_shortname("b") - >>> b.status = "open" + >>> b = bd.bug_from_uuid('b') + >>> b.status = 'open' >>> b.comment_root.time = 0 - >>> dummy = b.new_comment("1 2") + >>> dummy = b.new_comment('1 2') >>> dummy.time = 1 - >>> dummy = dummy.new_reply("1 2 3 4") + >>> dummy = dummy.new_reply('1 2 3 4') >>> dummy.time = 2 - >>> os.chdir(bd.root) - >>> execute(["a", "b"], manipulate_encodings=False) - Merging bugs a and b - >>> bd._clear_bugs() - >>> a = bd.bug_from_shortname("a") + + >>> ret = cmd.run(bd.storage, bd, {}, ['/a', '/b']) + Merged bugs #abc/a# and #abc/b# + >>> bd.flush_reload() + >>> a = bd.bug_from_uuid('a') >>> a.load_comments() - >>> mergeA = a.comment_from_shortname(":3") + >>> a_comments = sorted([c for c in a.comments()], + ... cmp=libbe.comment.cmp_time) + >>> mergeA = a_comments[0] >>> mergeA.time = 3 >>> print a.string(show_comments=True) # doctest: +ELLIPSIS ID : a - Short name : a + Short name : abc/a Severity : minor Status : open Assigned : @@ -57,42 +68,44 @@ def execute(args, manipulate_encodings=True, restrict_file_access=False, Created : ... Bug A --------- Comment --------- - Name: a:1 + Name: abc/a/... From: ... Date: ... Testing --------- Comment --------- - Name: a:2 + Name: abc/a/... From: ... Date: ... Testing... --------- Comment --------- - Name: a:3 + Name: abc/a/... From: ... Date: ... - Merged from bug b + Merged from bug #abc/b# --------- Comment --------- - Name: a:4 + Name: abc/a/... From: ... Date: ... 1 2 --------- Comment --------- - Name: a:5 + Name: abc/a/... From: ... Date: ... 1 2 3 4 - >>> b = bd.bug_from_shortname("b") + >>> b = bd.bug_from_uuid('b') >>> b.load_comments() - >>> mergeB = b.comment_from_shortname(":3") + >>> b_comments = sorted([c for c in b.comments()], + ... libbe.comment.cmp_time) + >>> mergeB = b_comments[0] >>> mergeB.time = 3 >>> print b.string(show_comments=True) # doctest: +ELLIPSIS ID : b - Short name : b + Short name : abc/b Severity : minor Status : closed Assigned : @@ -101,66 +114,73 @@ def execute(args, manipulate_encodings=True, restrict_file_access=False, Created : ... Bug B --------- Comment --------- - Name: b:1 + Name: abc/b/... From: ... Date: ... 1 2 --------- Comment --------- - Name: b:2 + Name: abc/b/... From: ... Date: ... 1 2 3 4 --------- Comment --------- - Name: b:3 + Name: abc/b/... From: ... Date: ... - Merged into bug a + Merged into bug #abc/a# >>> print b.status closed >>> 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, - 1: lambda bug : bug.active==True}) + name = 'merge' - if len(args) < 2: - raise cmdutil.UsageError("Please specify two bug ids.") - if len(args) > 2: - help() - raise cmdutil.UsageError("Too many arguments.") - - bd = bugdir.BugDir(from_disk=True, - manipulate_encodings=manipulate_encodings, - root=dir) - bugA = cmdutil.bug_from_id(bd, args[0]) - bugA.load_comments() - bugB = cmdutil.bug_from_id(bd, args[1]) - bugB.load_comments() - mergeA = bugA.new_comment("Merged from bug %s" % bugB.uuid) - newCommTree = copy.deepcopy(bugB.comment_root) - for comment in newCommTree.traverse(): # all descendant comments - comment.bug = bugA - 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" - print "Merging bugs %s and %s" % (bugA.uuid, bugB.uuid) + def __init__(self, *args, **kwargs): + libbe.command.Command.__init__(self, *args, **kwargs) + self.requires_bugdir = True + self.args.extend([ + libbe.command.Argument( + name='bug-id', metavar='BUG-ID', default=None, + completion_callback=libbe.command.util.complete_bug_id), + libbe.command.Argument( + name='bug-id-to-merge', metavar='BUG-ID', default=None, + completion_callback=libbe.command.util.complete_bug_id), + ]) -def get_parser(): - parser = cmdutil.CmdOptionParser("be merge BUG-ID BUG-ID") - return parser + def _run(self, storage, bugdir, **params): + bugA,dummy_comment = \ + libbe.command.util.bug_comment_from_user_id( + bugdir, params['bug-id']) + bugA.load_comments() + bugB,dummy_comment = \ + libbe.command.util.bug_comment_from_user_id( + bugdir, params['bug-id-to-merge']) + bugB.load_comments() + mergeA = bugA.new_comment('Merged from bug #%s#' % bugB.id.long_user()) + newCommTree = copy.deepcopy(bugB.comment_root) + for comment in newCommTree.traverse(): # all descendant comments + comment.bug = bugA + # uuids must be unique in storage + if comment.alt_id == None: + comment.storage = None + comment.alt_id = comment.uuid + comment.storage = storage + comment.uuid = libbe.util.id.uuid_gen() + comment.save() # force onto disk under bugA -longhelp=""" + for comment in newCommTree: # just the child comments + mergeA.add_reply(comment, allow_time_inversion=True) + bugB.new_comment('Merged into bug #%s#' % bugA.id.long_user()) + bugB.status = 'closed' + print >> self.stdout, 'Merged bugs #%s# and #%s#' \ + % (bugA.id.user(), bugB.id.user()) + return 0 + + def _long_help(self): + return """ The second bug (B) is merged into the first (A). This adds merge comments to both bugs, closes B, and appends B's comment tree to A's merge comment. """ - -def help(): - return get_parser().help_str() + longhelp -- cgit From 1b9c628529848af370adbc67b5ba298236a1b86d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 14 Dec 2009 23:15:58 -0500 Subject: Transitioned severity to Command-format, also added Command._get_*() The old .requires_* thing was rediculous. The new ._get_*() callbacks allow the caller to provide a means for getting the expensive structures, which the command can use, or not, as required. This will also make it easier to implement the completion callbacks. The callbacks should probably have matching .set_*() methods, to avoid the current cache tweaking cmd._storage = ... etc. But that can wait for now... --- libbe/command/merge.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index 4624ab7..e3bf943 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -31,6 +31,7 @@ class Merge (libbe.command.Command): >>> import libbe.comment >>> bd = libbe.bugdir.SimpleBugDir(memory=False) >>> cmd = Merge() + >>> cmd._storage = bd.storage >>> cmd._setup_io = lambda i_enc,o_enc : None >>> cmd.stdout = sys.stdout @@ -48,7 +49,7 @@ class Merge (libbe.command.Command): >>> dummy = dummy.new_reply('1 2 3 4') >>> dummy.time = 2 - >>> ret = cmd.run(bd.storage, bd, {}, ['/a', '/b']) + >>> ret = cmd.run(args=['/a', '/b']) Merged bugs #abc/a# and #abc/b# >>> bd.flush_reload() >>> a = bd.bug_from_uuid('a') @@ -139,7 +140,6 @@ class Merge (libbe.command.Command): def __init__(self, *args, **kwargs): libbe.command.Command.__init__(self, *args, **kwargs) - self.requires_bugdir = True self.args.extend([ libbe.command.Argument( name='bug-id', metavar='BUG-ID', default=None, @@ -149,7 +149,8 @@ class Merge (libbe.command.Command): completion_callback=libbe.command.util.complete_bug_id), ]) - def _run(self, storage, bugdir, **params): + def _run(self, **params): + bugdir = self._get_bugdir() bugA,dummy_comment = \ libbe.command.util.bug_comment_from_user_id( bugdir, params['bug-id']) @@ -166,7 +167,7 @@ class Merge (libbe.command.Command): if comment.alt_id == None: comment.storage = None comment.alt_id = comment.uuid - comment.storage = storage + comment.storage = bugdir.storage comment.uuid = libbe.util.id.uuid_gen() comment.save() # force onto disk under bugA -- cgit From 89b7a1411e4658e831f5d635534b24355dbb941d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 15 Dec 2009 06:44:20 -0500 Subject: Fixed libbe.command.diff + ugly BugDir.duplicate_bugdir implementation duplicate_bugdir() works, but for the vcs backends, it could require shelling out for _every_ file read. This could, and probably will, be horribly slow. Still it works ;). I'm not sure what a better implementation would be. The old implementation checked out the entire earlier state into a temporary directory pros: single shell out, simple upgrade implementation cons: wouldn't work well for HTTP backens I think a good solution would run along the lines of the currently commented out code in duplicate_bugdir(), where a VersionedStorage.changed_since(revision) call would give you a list of changed files. diff could work off of that directly, without the need to generate a whole duplicate bugdir. I'm stuck on how to handle upgrades though... Also removed trailing whitespace from all python files. --- libbe/command/merge.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index e3bf943..447b4ae 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -63,8 +63,8 @@ class Merge (libbe.command.Command): Short name : abc/a Severity : minor Status : open - Assigned : - Reporter : + Assigned : + Reporter : Creator : John Doe Created : ... Bug A @@ -109,8 +109,8 @@ class Merge (libbe.command.Command): Short name : abc/b Severity : minor Status : closed - Assigned : - Reporter : + Assigned : + Reporter : Creator : Jane Doe Created : ... Bug B @@ -168,7 +168,7 @@ class Merge (libbe.command.Command): comment.storage = None comment.alt_id = comment.uuid comment.storage = bugdir.storage - comment.uuid = libbe.util.id.uuid_gen() + comment.uuid = libbe.util.id.uuid_gen() comment.save() # force onto disk under bugA for comment in newCommTree: # just the child comments -- cgit From 9a62c4beea7c89905dc487bdbe2e46fed4b83f21 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 29 Dec 2009 19:19:15 -0500 Subject: Restored post-colon spaces in doctests --- libbe/command/merge.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index 447b4ae..328351e 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -63,8 +63,8 @@ class Merge (libbe.command.Command): Short name : abc/a Severity : minor Status : open - Assigned : - Reporter : + Assigned : + Reporter : Creator : John Doe Created : ... Bug A @@ -109,8 +109,8 @@ class Merge (libbe.command.Command): Short name : abc/b Severity : minor Status : closed - Assigned : - Reporter : + Assigned : + Reporter : Creator : Jane Doe Created : ... Bug B -- cgit From cfae8a8302f06a84196700138d7ddbb25e91ea31 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 31 Dec 2009 14:32:39 -0500 Subject: Added UserInterface and other improved abstractions for command handling --- libbe/command/merge.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index 328351e..0c34f69 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -30,10 +30,11 @@ class Merge (libbe.command.Command): >>> import libbe.bugdir >>> import libbe.comment >>> bd = libbe.bugdir.SimpleBugDir(memory=False) - >>> cmd = Merge() - >>> cmd._storage = bd.storage - >>> cmd._setup_io = lambda i_enc,o_enc : None - >>> cmd.stdout = sys.stdout + >>> io = libbe.command.StringInputOutput() + >>> io.stdout = sys.stdout + >>> ui = libbe.command.UserInterface(io=io) + >>> ui.storage_callbacks.set_bugdir(bd) + >>> cmd = Merge(ui=ui) >>> a = bd.bug_from_uuid('a') >>> a.comment_root.time = 0 @@ -49,7 +50,7 @@ class Merge (libbe.command.Command): >>> dummy = dummy.new_reply('1 2 3 4') >>> dummy.time = 2 - >>> ret = cmd.run(args=['/a', '/b']) + >>> ret = ui.run(cmd, args=['/a', '/b']) Merged bugs #abc/a# and #abc/b# >>> bd.flush_reload() >>> a = bd.bug_from_uuid('a') @@ -134,6 +135,7 @@ class Merge (libbe.command.Command): Merged into bug #abc/a# >>> print b.status closed + >>> ui.cleanup() >>> bd.cleanup() """ name = 'merge' -- cgit From 4d4283ecd654f1efb058cd7f7dba6be88b70ee92 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 1 Jan 2010 08:11:08 -0500 Subject: Updated copyright information --- libbe/command/merge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/command/merge.py') diff --git a/libbe/command/merge.py b/libbe/command/merge.py index 0c34f69..2dff59c 100644 --- a/libbe/command/merge.py +++ b/libbe/command/merge.py @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2009 Gianluca Montecchi +# Copyright (C) 2008-2010 Gianluca Montecchi # W. Trevor King # # This program is free software; you can redistribute it and/or modify -- cgit