Ran update-copyright.py.
[be.git] / libbe / command / util.py
index 6ce5cc94d692a7d73a3483c17412f22d9c7ca7e2..6f7b92e4782883b36462aa48eaee0cb46f609bab 100644 (file)
@@ -1,4 +1,20 @@
-# Copyright
+# Copyright (C) 2009-2012 Chris Ball <cjb@laptop.org>
+#                         W. Trevor King <wking@tremily.us>
+#
+# This file is part of Bugs Everywhere.
+#
+# Bugs Everywhere 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.
+#
+# Bugs Everywhere 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
+# Bugs Everywhere.  If not, see <http://www.gnu.org/licenses/>.
 
 import glob
 import os.path
@@ -9,7 +25,7 @@ import libbe.command
 class Completer (object):
     def __init__(self, options):
         self.options = options
-    def __call__(self, bugdir, fragment=None):
+    def __call__(self, bugdirs, fragment=None):
         return [fragment]
 
 def complete_command(command, argument, fragment=None):
@@ -18,30 +34,117 @@ def complete_command(command, argument, fragment=None):
 
     command argument is not used.
     """
-    return list(libbe.command.commands())
+    return list(libbe.command.commands(command_names=True))
 
-def complete_path(command, argument, fragment=None):
-    """
-    List possible path completions for fragment.
-
-    command argument is not used.
-    """
+def comp_path(fragment=None):
+    """List possible path completions for fragment."""
     if fragment == None:
         fragment = '.'
     comps = glob.glob(fragment+'*') + glob.glob(fragment+'/*')
     if len(comps) == 1 and os.path.isdir(comps[0]):
         comps.extend(glob.glob(comps[0]+'/*'))
     return comps
-    
+
+def complete_path(command, argument, fragment=None):
+    """List possible path completions for fragment."""
+    return comp_path(fragment)
+
 def complete_status(command, argument, fragment=None):
-    return [fragment]
+    bd = sorted(command._get_bugdirs().items())[1]
+    import libbe.bug
+    return libbe.bug.status_values
+
 def complete_severity(command, argument, fragment=None):
-    return [fragment]
+    bd = sorted(command._get_bugdirs().items())[1]
+    import libbe.bug
+    return libbe.bug.severity_values
+
+def assignees(bugdirs):
+    ret = set()
+    for bugdir in bugdirs.values():
+        bugdir.load_all_bugs()
+        ret.update(set([bug.assigned for bug in bugdir
+                        if bug.assigned != None]))
+    return list(ret)
+
 def complete_assigned(command, argument, fragment=None):
-    return [fragment]
+    return assignees(command._get_bugdirs())
+
 def complete_extra_strings(command, argument, fragment=None):
+    if fragment == None:
+        return []
     return [fragment]
 
+def complete_bugdir_id(command, argument, fragment=None):
+    bugdirs = command._get_bugdirs()
+    return bugdirs.keys()
+
+def complete_bug_id(command, argument, fragment=None):
+    return complete_bug_comment_id(command, argument, fragment,
+                                   comments=False)
+
+def complete_bug_comment_id(command, argument, fragment=None,
+                            active_only=True, comments=True):
+    import libbe.bugdir
+    import libbe.util.id
+    bugdirs = command._get_bugdirs()
+    if fragment == None or len(fragment) == 0:
+        fragment = '/'
+    try:
+        p = libbe.util.id.parse_user(bugdirs, fragment)
+        matches = None
+        root,residual = (fragment, None)
+        if not root.endswith('/'):
+            root += '/'
+    except libbe.util.id.InvalidIDStructure, e:
+        return []
+    except libbe.util.id.NoIDMatches:
+        return []
+    except libbe.util.id.MultipleIDMatches, e:
+        if e.common == None:
+            # choose among bugdirs
+            return e.matches
+        common = e.common
+        matches = e.matches
+        root,residual = libbe.util.id.residual(common, fragment)
+        p = libbe.util.id.parse_user(bugdirs, e.common)
+    bug = None
+    if matches == None: # fragment was complete, get a list of children uuids
+        if p['type'] == 'bugdir':
+            bugdir = bugdirs[p['bugdir']]
+            matches = bugdir.uuids()
+            common = bugdir.id.user()
+        elif p['type'] == 'bug':
+            if comments == False:
+                return [fragment]
+            bugdir = bugdirs[p['bugdir']]
+            bug = bugdir.bug_from_uuid(p['bug'])
+            matches = bug.uuids()
+            common = bug.id.user()
+        else:
+            assert p['type'] == 'comment', p
+            return [fragment]
+    if p['type'] == 'bugdir':
+        bugdir = bugdirs[p['bugdir']]
+        child_fn = bugdir.bug_from_uuid
+    elif p['type'] == 'bug':
+        if comments == False:
+            return[fragment]
+        bugdir = bugdirs[p['bugdir']]
+        if bug == None:
+            bug = bugdir.bug_from_uuid(p['bug'])
+        child_fn = bug.comment_from_uuid
+    elif p['type'] == 'comment':
+        assert matches == None, matches
+        return [fragment]
+    possible = []
+    common += '/'
+    for m in matches:
+        child = child_fn(m)
+        id = child.id.user()
+        possible.append(id.replace(common, root))
+    return possible
+
 def select_values(string, possible_values, name="unkown"):
     """
     This function allows the user to select values from a list of
@@ -83,14 +186,51 @@ def select_values(string, possible_values, name="unkown"):
         blacklisted_values = set(string[1:].split(','))
         for value in blacklisted_values:
             if value not in possible_values:
-                raise UserError('Invalid %s %s\n  %s'
+                raise libbe.command.UserError('Invalid %s %s\n  %s'
                                 % (name, value, possible_values))
             possible_values.remove(value)
     else:
         whitelisted_values = string.split(',')
         for value in whitelisted_values:
             if value not in possible_values:
-                raise UserError('Invalid %s %s\n  %s'
-                                % (name, value, possible_values))
+                raise libbe.command.UserError(
+                    'Invalid %s %s\n  %s'
+                    % (name, value, possible_values))
         possible_values = whitelisted_values
     return possible_values
+
+def bugdir_bug_comment_from_user_id(bugdirs, id):
+    p = libbe.util.id.parse_user(bugdirs, id)
+    if not p['type'] in ['bugdir', 'bug', 'comment']:
+        raise libbe.command.UserError(
+            '{} is a {} id, not a bugdir, bug, or comment id'.format(
+                id, p['type']))
+    if p['bugdir'] not in bugdirs:
+        raise libbe.command.UserError(
+            "{} doesn't belong to any bugdirs in {}".format(
+                id, sorted(bugdirs.keys())))
+    bugdir = bugdirs[p['bugdir']]
+    if p['bugdir'] != bugdir.uuid:
+        raise libbe.command.UserError(
+            "%s doesn't belong to this bugdir (%s)"
+            % (id, bugdir.uuid))
+    if 'bug' in p:
+        bug = bugdir.bug_from_uuid(p['bug'])
+        if 'comment' in p:
+            comment = bug.comment_from_uuid(p['comment'])
+        else:
+            comment = bug.comment_root
+    else:
+        bug = comment = None
+    return (bugdir, bug, comment)
+
+def bug_from_uuid(bugdirs, uuid):
+    error = None
+    for bugdir in bugdirs.values():
+        try:
+            bug = bugdir.bug_from_uuid(uuid)
+        except libbe.bugdir.NoBugMatches as e:
+            error = e
+        else:
+            return bug
+    raise error