diff options
Diffstat (limited to 'becommands')
-rw-r--r-- | becommands/assign.py | 12 | ||||
-rw-r--r-- | becommands/close.py | 7 | ||||
-rw-r--r-- | becommands/comment.py | 24 | ||||
-rw-r--r-- | becommands/depend.py | 13 | ||||
-rw-r--r-- | becommands/diff.py | 52 | ||||
-rw-r--r-- | becommands/help.py | 6 | ||||
-rw-r--r-- | becommands/init.py | 12 | ||||
-rw-r--r-- | becommands/list.py | 14 | ||||
-rw-r--r-- | becommands/merge.py | 7 | ||||
-rw-r--r-- | becommands/new.py | 7 | ||||
-rw-r--r-- | becommands/open.py | 7 | ||||
-rw-r--r-- | becommands/remove.py | 7 | ||||
-rw-r--r-- | becommands/set.py | 15 | ||||
-rw-r--r-- | becommands/severity.py | 13 | ||||
-rw-r--r-- | becommands/show.py | 9 | ||||
-rw-r--r-- | becommands/status.py | 16 | ||||
-rw-r--r-- | becommands/subscribe.py | 368 | ||||
-rw-r--r-- | becommands/tag.py | 21 | ||||
-rw-r--r-- | becommands/target.py | 17 |
19 files changed, 514 insertions, 113 deletions
diff --git a/becommands/assign.py b/becommands/assign.py index 81aac2b..7b32bdd 100644 --- a/becommands/assign.py +++ b/becommands/assign.py @@ -20,7 +20,7 @@ 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() @@ -28,17 +28,17 @@ def execute(args, test=False): >>> 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 @@ -53,8 +53,10 @@ 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 elif len(args) == 2: diff --git a/becommands/close.py b/becommands/close.py index 327817a..12848b2 100644 --- a/becommands/close.py +++ b/becommands/close.py @@ -20,7 +20,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import bugdir >>> import os @@ -28,7 +28,7 @@ def execute(args, test=False): >>> 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 @@ -41,7 +41,8 @@ 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) + 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 4221ef8..14872a3 100644 --- a/becommands/comment.py +++ b/becommands/comment.py @@ -25,12 +25,12 @@ 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() >>> 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 = cmdutil.bug_from_shortname(bd, "a") >>> bug.load_comments(load_full=False) @@ -38,7 +38,7 @@ def execute(args, test=False): >>> print comment.body This is a comment about a <BLANKLINE> - >>> comment.From == bd.user_id + >>> comment.author == bd.user_id True >>> comment.time <= int(time.time()) True @@ -47,12 +47,12 @@ 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 = cmdutil.bug_from_shortname(bd, "b") >>> bug.load_comments(load_full=False) @@ -68,10 +68,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,9 +79,9 @@ def execute(args, test=False): else: bugname = shortname is_reply = False - + bd = bugdir.BugDir(from_disk=True, - manipulate_encodings=not test) + manipulate_encodings=manipulate_encodings) bug = cmdutil.bug_from_shortname(bd, bugname) bug.load_comments(load_full=False) if is_reply: @@ -89,7 +89,7 @@ def execute(args, test=False): 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: @@ -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/depend.py b/becommands/depend.py index d22ed2d..fd38bd1 100644 --- a/becommands/depend.py +++ b/becommands/depend.py @@ -18,22 +18,22 @@ 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.save() >>> os.chdir(bd.root) - >>> execute(["a", "b"], test=True) + >>> execute(["a", "b"], manipulate_encodings=False) Blocks on a: b - >>> execute(["a"], test=True) + >>> execute(["a"], manipulate_encodings=False) Blocks on a: b - >>> execute(["--show-status", "a"], test=True) # doctest: +NORMALIZE_WHITESPACE + >>> execute(["--show-status", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE Blocks on a: b closed - >>> execute(["-r", "a", "b"], test=True) + >>> execute(["-r", "a", "b"], manipulate_encodings=False) """ parser = get_parser() options, args = parser.parse_args(args) @@ -47,7 +47,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) bugA = cmdutil.bug_from_shortname(bd, args[0]) if len(args) == 2: bugB = cmdutil.bug_from_shortname(bd, args[1]) diff --git a/becommands/diff.py b/becommands/diff.py index 13402c0..1ab2135 100644 --- a/becommands/diff.py +++ b/becommands/diff.py @@ -20,7 +20,7 @@ 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() @@ -31,12 +31,23 @@ def execute(args, test=False): >>> changed = bd.rcs.commit("Closed bug a") >>> os.chdir(bd.root) >>> if bd.rcs.versioned == True: - ... execute([original], test=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.rcs.versioned == True: + ... execute(["--modified", original], manipulate_encodings=False) + ... else: + ... print "a" + a + >>> if bd.rcs.versioned == False: + ... execute([original], manipulate_encodings=False) + ... else: + ... print "This directory is not revision-controlled." + This directory is not revision-controlled. """ parser = get_parser() options, args = parser.parse_args(args) @@ -47,28 +58,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) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) if bd.rcs.versioned == False: print "This directory is not revision-controlled." else: + if revision == None: # get the most recent revision + revision = bd.rcs.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,7 +99,7 @@ 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=""" 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] <BLANKLINE> diff --git a/becommands/init.py b/becommands/init.py index 5b2a416..4156a26 100644 --- a/becommands/init.py +++ b/becommands/init.py @@ -19,7 +19,7 @@ import os.path from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import utility, rcs >>> import os @@ -29,7 +29,7 @@ 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) @@ -40,17 +40,17 @@ def execute(args, test=False): >>> rcs.init('.') >>> print rcs.name Arch - >>> execute([], test=True) + >>> execute([], manipulate_encodings=False) Using Arch for revision control. Directory initialized. >>> rcs.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,7 +64,7 @@ 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: diff --git a/becommands/list.py b/becommands/list.py index 5ba1821..50038e6 100644 --- a/becommands/list.py +++ b/becommands/list.py @@ -26,14 +26,14 @@ __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() >>> 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 """ @@ -46,11 +46,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 633067c..6651869 100644 --- a/becommands/merge.py +++ b/becommands/merge.py @@ -18,7 +18,7 @@ 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() @@ -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") @@ -133,7 +133,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) bugA = cmdutil.bug_from_shortname(bd, args[0]) bugA.load_comments() bugB = cmdutil.bug_from_shortname(bd, args[1]) diff --git a/becommands/new.py b/becommands/new.py index af599d7..2487bac 100644 --- a/becommands/new.py +++ b/becommands/new.py @@ -19,14 +19,14 @@ 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() >>> 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() >>> bug = bd.bug_from_uuid("X") @@ -44,7 +44,8 @@ def execute(args, test=False): 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 242ceb2..bfb54ea 100644 --- a/becommands/open.py +++ b/becommands/open.py @@ -20,14 +20,14 @@ 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() >>> 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 @@ -40,7 +40,8 @@ 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) + bd = bugdir.BugDir(from_disk=True, + manipulate_encodings=manipulate_encodings) bug = cmdutil.bug_from_shortname(bd, args[0]) bug.status = "open" diff --git a/becommands/remove.py b/becommands/remove.py index 7193119..bc7b5ed 100644 --- a/becommands/remove.py +++ b/becommands/remove.py @@ -17,7 +17,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, test=False): +def execute(args, manipulate_encodings=True): """ >>> from libbe import mapfile >>> import os @@ -25,7 +25,7 @@ def execute(args, test=False): >>> 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: @@ -40,7 +40,8 @@ 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) + 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..f7fca54 100644 --- a/becommands/set.py +++ b/becommands/set.py @@ -32,18 +32,18 @@ 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() >>> 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 """ parser = get_parser() @@ -51,7 +51,8 @@ def execute(args, test=False): 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() diff --git a/becommands/severity.py b/becommands/severity.py index 74f241d..a14a96b 100644 --- a/becommands/severity.py +++ b/becommands/severity.py @@ -20,17 +20,17 @@ 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() >>> 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 """ @@ -39,7 +39,8 @@ def execute(args, test=False): complete(options, args, parser) if len(args) not in (1,2): raise cmdutil.UsageError - 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]) if len(args) == 1: print bug.severity diff --git a/becommands/show.py b/becommands/show.py index 6c942fe..bb16fe5 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() >>> 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 <BLANKLINE> - >>> execute (["--xml", "a"], test=True) # doctest: +ELLIPSIS + >>> execute (["--xml", "a"], manipulate_encodings=False) # doctest: +ELLIPSIS <?xml version="1.0" encoding="..." ?> <bug> <uuid>a</uuid> @@ -57,7 +57,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 '<?xml version="1.0" encoding="%s" ?>' % bd.encoding for shortname in args: diff --git a/becommands/status.py b/becommands/status.py index bff0626..e4db787 100644 --- a/becommands/status.py +++ b/becommands/status.py @@ -17,17 +17,17 @@ 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() >>> 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 """ @@ -36,7 +36,8 @@ def execute(args, test=False): complete(options, args, parser) if len(args) not in (1,2): raise cmdutil.UsageError - 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]) if len(args) == 1: print bug.status @@ -55,7 +56,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..64a2867 --- /dev/null +++ b/becommands/subscribe.py @@ -0,0 +1,368 @@ +# Copyright (C) 2009 W. Trevor King <wking@drexel.edu> +# +# 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 "<SubscriptionType: %s>" % 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.simple_bug_dir() + >>> bd.set_sync_with_disk(True) + >>> os.chdir(bd.root) + >>> a = bd.bug_from_shortname("a") + >>> print a.extra_strings + [] + >>> execute(["-s","John Doe <j@doe.com>", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + John Doe <j@doe.com> all * + >>> bd._clear_bugs() # resync our copy of bug + >>> a = bd.bug_from_shortname("a") + >>> print a.extra_strings + ['SUBSCRIBE:John Doe <j@doe.com>\\tall\\t*'] + >>> execute(["-s","Jane Doe <J@doe.com>", "-S", "a.com,b.net", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe <J@doe.com> all a.com,b.net + John Doe <j@doe.com> all * + >>> execute(["-s","Jane Doe <J@doe.com>", "-S", "a.edu", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe <J@doe.com> all a.com,a.edu,b.net + John Doe <j@doe.com> all * + >>> execute(["-u", "-s","Jane Doe <J@doe.com>", "-S", "a.com", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe <J@doe.com> all a.edu,b.net + John Doe <j@doe.com> all * + >>> execute(["-s","Jane Doe <J@doe.com>", "-S", "*", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + Jane Doe <J@doe.com> all * + John Doe <j@doe.com> all * + >>> execute(["-u", "-s","Jane Doe <J@doe.com>", "a"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for a: + John Doe <j@doe.com> all * + >>> execute(["-u", "-s","John Doe <j@doe.com>", "a"], manipulate_encodings=False) + >>> execute(["-s","Jane Doe <J@doe.com>", "-t", "new", "DIR"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for bug directory: + Jane Doe <J@doe.com> new * + >>> execute(["-s","Jane Doe <J@doe.com>", "DIR"], manipulate_encodings=False) # doctest: +NORMALIZE_WHITESPACE + Subscriptions for bug directory: + Jane Doe <J@doe.com> all * + """ + 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 + + types = [type_from_name(name, type_root, default=INVALID_TYPE, + default_ok=options.unsubscribe) + for name in types] + estrs = entity.extra_strings + 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 + + 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("-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 <j@doe.com>", [BUGDIR_TYPE_ALL], ["a.com"], BUGDIR_TYPE_ALL) + >>> es = subscribe(es, "Jane Doe <J@doe.com>", [BUGDIR_TYPE_NEW], ["*"], BUGDIR_TYPE_ALL) + >>> sgs(es, BUGDIR_TYPE_ALL, "a.com", BUGDIR_TYPE_ALL) + ['John Doe <j@doe.com>'] + >>> sgs(es, BUGDIR_TYPE_ALL, "a.com", BUGDIR_TYPE_ALL, match_descendant_types=True) + ['Jane Doe <J@doe.com>', 'John Doe <j@doe.com>'] + >>> sgs(es, BUGDIR_TYPE_ALL, "b.net", BUGDIR_TYPE_ALL, match_descendant_types=True) + ['Jane Doe <J@doe.com>'] + >>> sgs(es, BUGDIR_TYPE_NEW, "a.com", BUGDIR_TYPE_ALL) + ['Jane Doe <J@doe.com>'] + >>> sgs(es, BUGDIR_TYPE_NEW, "a.com", BUGDIR_TYPE_ALL, match_ancestor_types=True) + ['Jane Doe <J@doe.com>', 'John Doe <j@doe.com>'] + """ + for string in extra_strings: + 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 == ["*"]: + 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). + + >>> bd = bugdir.simple_bug_dir() + >>> a = bd.bug_from_shortname("a") + >>> bd.extra_strings = subscribe(bd.extra_strings, "John Doe <j@doe.com>", [BUGDIR_TYPE_ALL], ["a.com"], BUGDIR_TYPE_ALL) + >>> bd.extra_strings = subscribe(bd.extra_strings, "Jane Doe <J@doe.com>", [BUGDIR_TYPE_NEW], ["*"], BUGDIR_TYPE_ALL) + >>> a.extra_strings = subscribe(a.extra_strings, "John Doe <j@doe.com>", [BUG_TYPE_ALL], ["a.com"], BUG_TYPE_ALL) + >>> subscribers = get_bugdir_subscribers(bd, "a.com") + >>> subscribers["Jane Doe <J@doe.com>"]["DIR"] + [<SubscriptionType: new>] + >>> subscribers["John Doe <j@doe.com>"]["DIR"] + [<SubscriptionType: all>] + >>> subscribers["John Doe <j@doe.com>"]["a"] + [<SubscriptionType: all>] + >>> get_bugdir_subscribers(bd, "b.net") + {'Jane Doe <J@doe.com>': {'DIR': [<SubscriptionType: new>]}} + """ + 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 08247cd..e749a31 100644 --- a/becommands/tag.py +++ b/becommands/tag.py @@ -18,7 +18,7 @@ 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() @@ -27,25 +27,25 @@ def execute(args, test=False): >>> 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,15 @@ 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) """ parser = get_parser() options, args = parser.parse_args(args) @@ -78,7 +78,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 = [] diff --git a/becommands/target.py b/becommands/target.py index ec10ed6..5d0453a 100644 --- a/becommands/target.py +++ b/becommands/target.py @@ -22,20 +22,20 @@ 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() >>> 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. """ parser = get_parser() @@ -46,7 +46,8 @@ 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): |