Bumped to version 1.0.0
[be.git] / libbe / command / depend.py
index b9f6354c04978ad6a4d2a22b31bfa7df1c4c1346..39d80424b8138fbf2ded1c3710c27021aec7f37d 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2010 Gianluca Montecchi <gian@grys.it>
+# Copyright (C) 2009-2011 Gianluca Montecchi <gian@grys.it>
 #                         W. Trevor King <wking@drexel.edu>
 #
 # This file is part of Bugs Everywhere.
@@ -28,14 +28,81 @@ import libbe.util.tree
 BLOCKS_TAG="BLOCKS:"
 BLOCKED_BY_TAG="BLOCKED-BY:"
 
+
+class Filter (object):
+    def __init__(self, status='all', severity='all', assigned='all',
+                 target='all', extra_strings_regexps=[]):
+        self.status = status
+        self.severity = severity
+        self.assigned = assigned
+        self.target = target
+        self.extra_strings_regexps = extra_strings_regexps
+
+    def __call__(self, bugdir, bug):
+        if self.status != 'all' and not bug.status in self.status:
+            return False
+        if self.severity != 'all' and not bug.severity in self.severity:
+            return False
+        if self.assigned != 'all' and not bug.assigned in self.assigned:
+            return False
+        if self.target == 'all':
+            pass
+        else:
+            target_bug = libbe.command.target.bug_target(bugdir, bug)
+            if self.target in ['none', None]:
+                if target_bug.summary != None:
+                    return False
+            else:
+                if target_bug.summary != self.target:
+                    return False
+        if len(bug.extra_strings) == 0:
+            if len(self.extra_strings_regexps) > 0:
+                return False
+        elif len(self.extra_strings_regexps) > 0:
+            matched = False
+            for string in bug.extra_strings:
+                for regexp in self.extra_strings_regexps:
+                    if regexp.match(string):
+                        matched = True
+                        break
+                if matched == True:
+                    break
+            if matched == False:
+                return False
+        return True
+
+def parse_status(status):
+    if status == 'all':
+        status = libbe.bug.status_values
+    elif status == 'active':
+        status = list(libbe.bug.active_status_values)
+    elif status == 'inactive':
+        status = list(libbe.bug.inactive_status_values)
+    else:
+        status = libbe.command.util.select_values(
+            status, libbe.bug.status_values)
+    return status
+
+def parse_severity(severity, important=False):
+    if severity == 'all':
+        severity = libbe.bug.severity_values
+    elif important == True:
+        serious = libbe.bug.severity_values.index('serious')
+        severity.append(list(libbe.bug.severity_values[serious:]))
+    else:
+        severity = libbe.command.util.select_values(
+            severity, libbe.bug.severity_values)
+    return severity
+
+
 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)
+                % (blocking_bug.id.user(), blocked_bug.id.user())
         else:
             msg = "Missing link: %s blocked by %s" \
-                % (blocked_bug.uuid, blocking_bug.uuid)
+                % (blocked_bug.id.user(), blocking_bug.id.user())
         Exception.__init__(self, msg)
         self.blocked_bug = blocked_bug
         self.blocking_bug = blocking_bug
@@ -53,28 +120,33 @@ class Depend (libbe.command.Command):
     >>> cmd = Depend(ui=ui)
 
     >>> ret = ui.run(cmd, args=['/a', '/b'])
-    a blocked by:
-    b
+    abc/a blocked by:
+    abc/b
     >>> ret = ui.run(cmd, args=['/a'])
-    a blocked by:
-    b
+    abc/a blocked by:
+    abc/b
     >>> ret = ui.run(cmd, {'show-status':True}, ['/a']) # doctest: +NORMALIZE_WHITESPACE
-    a blocked by:
-    b closed
+    abc/a blocked by:
+    abc/b closed
     >>> ret = ui.run(cmd, args=['/b', '/a'])
-    b blocked by:
-    a
-    b blocks:
-    a
+    abc/b blocked by:
+    abc/a
+    abc/b blocks:
+    abc/a
     >>> ret = ui.run(cmd, {'show-status':True}, ['/a']) # doctest: +NORMALIZE_WHITESPACE
-    a blocked by:
-    b closed
-    a blocks:
-    b closed
+    abc/a blocked by:
+    abc/b closed
+    abc/a blocks:
+    abc/b closed
+    >>> ret = ui.run(cmd, {'show-summary':True}, ['/a']) # doctest: +NORMALIZE_WHITESPACE
+    abc/a blocked by:
+    abc/b       Bug B
+    abc/a blocks:
+    abc/b       Bug B
     >>> ret = ui.run(cmd, {'repair':True})
     >>> ret = ui.run(cmd, {'remove':True}, ['/b', '/a'])
-    b blocks:
-    a
+    abc/b blocks:
+    abc/a
     >>> ret = ui.run(cmd, {'remove':True}, ['/a', '/b'])
     >>> ui.cleanup()
     >>> bd.cleanup()
@@ -88,6 +160,8 @@ class Depend (libbe.command.Command):
                     help='Remove dependency (instead of adding it)'),
                 libbe.command.Option(name='show-status', short_name='s',
                     help='Show status of blocking bugs'),
+                libbe.command.Option(name='show-summary', short_name='S',
+                    help='Show summary of blocking bugs'),
                 libbe.command.Option(name='status',
                     help='Only show bugs matching the STATUS specifier',
                     arg=libbe.command.Argument(
@@ -119,14 +193,14 @@ class Depend (libbe.command.Command):
 
     def _run(self, **params):
         if params['repair'] == True and params['bug-id'] != None:
-            raise libbe.command.UsageError(
+            raise libbe.command.UserError(
                 'No arguments with --repair calls.')
         if params['repair'] == False and params['bug-id'] == None:
-            raise libbe.command.UsageError(
+            raise libbe.command.UserError(
                 'Must specify either --repair or a BUG-ID')
         if params['tree-depth'] != None \
                 and params['blocking-bug-id'] != None:
-            raise libbe.command.UsageError(
+            raise libbe.command.UserError(
                 'Only one bug id used in tree mode.')
         bugdir = self._get_bugdir()
         if params['repair'] == True:
@@ -135,37 +209,32 @@ class Depend (libbe.command.Command):
             if len(fixed) > 0:
                 print >> self.stdout, 'Fixed the following links:'
                 print >> self.stdout, \
-                    '\n'.join(['%s |-- %s' % (blockee.uuid, blocker.uuid)
+                    '\n'.join(['%s |-- %s' % (blockee.id.user(), blocker.id.user())
                                for blockee,blocker in fixed])
             return 0
-        allowed_status_values = \
-            libbe.command.util.select_values(
-                params['status'], libbe.bug.status_values)
-        allowed_severity_values = \
-            libbe.command.util.select_values(
-                params['severity'], libbe.bug.severity_values)
+        status = parse_status(params['status'])
+        severity = parse_severity(params['severity'])
+        filter = Filter(status, severity)
 
         bugA, dummy_comment = libbe.command.util.bug_comment_from_user_id(
             bugdir, params['bug-id'])
 
         if params['tree-depth'] != None:
-            dtree = DependencyTree(bugdir, bugA, params['tree-depth'],
-                                   allowed_status_values,
-                                   allowed_severity_values)
+            dtree = DependencyTree(bugdir, bugA, params['tree-depth'], filter)
             if len(dtree.blocked_by_tree()) > 0:
-                print >> self.stdout, '%s blocked by:' % bugA.uuid
+                print >> self.stdout, '%s blocked by:' % bugA.id.user()
                 for depth,node in dtree.blocked_by_tree().thread():
                     if depth == 0: continue
-                    print >> self.stdout, \
-                        '%s%s' % (' '*(depth),
-                        node.bug.string(shortlist=True))
+                    print >> self.stdout, (
+                        '%s%s'
+                        % (' '*(depth), self.bug_string(node.bug, params)))
             if len(dtree.blocks_tree()) > 0:
-                print >> self.stdout, '%s blocks:' % bugA.uuid
+                print >> self.stdout, '%s blocks:' % bugA.id.user()
                 for depth,node in dtree.blocks_tree().thread():
                     if depth == 0: continue
-                    print >> self.stdout, \
-                        '%s%s' % (' '*(depth),
-                        node.bug.string(shortlist=True))
+                    print >> self.stdout, (
+                        '%s%s'
+                        % (' '*(depth), self.bug_string(node.bug, params)))
             return 0
 
         if params['blocking-bug-id'] != None:
@@ -177,27 +246,28 @@ class Depend (libbe.command.Command):
                 add_block(bugA, bugB)
 
         blocked_by = get_blocked_by(bugdir, bugA)
+
         if len(blocked_by) > 0:
-            print >> self.stdout, '%s blocked by:' % bugA.uuid
-            if params['show-status'] == True:
-                print >> self.stdout, \
-                    '\n'.join(['%s\t%s' % (_bug.uuid, _bug.status)
-                               for _bug in blocked_by])
-            else:
-                print >> self.stdout, \
-                    '\n'.join([_bug.uuid for _bug in blocked_by])
+            print >> self.stdout, '%s blocked by:' % bugA.id.user()
+            print >> self.stdout, \
+                '\n'.join([self.bug_string(_bug, params)
+                           for _bug in blocked_by])
         blocks = get_blocks(bugdir, bugA)
         if len(blocks) > 0:
-            print >> self.stdout, '%s blocks:' % bugA.uuid
-            if params['show-status'] == True:
-                print >> self.stdout, \
-                    '\n'.join(['%s\t%s' % (_bug.uuid, _bug.status)
-                               for _bug in blocks])
-            else:
-                print >> self.stdout, \
-                    '\n'.join([_bug.uuid for _bug in blocks])
+            print >> self.stdout, '%s blocks:' % bugA.id.user()
+            print >> self.stdout, \
+                '\n'.join([self.bug_string(_bug, params)
+                           for _bug in blocks])
         return 0
 
+    def bug_string(self, _bug, params):
+        fields = [_bug.id.user()]
+        if params['show-status'] == True:
+            fields.append(_bug.status)
+        if params['show-summary'] == True:
+            fields.append(_bug.summary)
+        return '\t'.join(fields)
+
     def _long_help(self):
         return """
 Set a dependency with the second bug (B) blocking the first bug (A).
@@ -366,17 +436,14 @@ class DependencyTree (object):
     """
     Note: should probably be DependencyDiGraph.
     """
-    def __init__(self, bugdir, root_bug, depth_limit=0,
-                 allowed_status_values=None,
-                 allowed_severity_values=None):
+    def __init__(self, bugdir, root_bug, depth_limit=0, filter=None):
         self.bugdir = bugdir
         self.root_bug = root_bug
         self.depth_limit = depth_limit
-        self.allowed_status_values = allowed_status_values
-        self.allowed_severity_values = allowed_severity_values
+        self.filter = filter
 
     def _build_tree(self, child_fn):
-        root = tree.Tree()
+        root = libbe.util.tree.Tree()
         root.bug = self.root_bug
         root.depth = 0
         stack = [root]
@@ -385,13 +452,9 @@ class DependencyTree (object):
             if self.depth_limit > 0 and node.depth == self.depth_limit:
                 continue
             for bug in child_fn(self.bugdir, node.bug):
-                if self.allowed_status_values != None \
-                        and not bug.status in self.allowed_status_values:
-                    continue
-                if self.allowed_severity_values != None \
-                        and not bug.severity in self.allowed_severity_values:
+                if not self.filter(self.bugdir, bug):
                     continue
-                child = tree.Tree()
+                child = libbe.util.tree.Tree()
                 child.bug = bug
                 child.depth = node.depth+1
                 node.append(child)