aboutsummaryrefslogblamecommitdiffstats
path: root/becommands/list.py
blob: 12e1e29966199ba8372f39c0037cac8c23d956e7 (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                             
 



                                                                      
 



                                                                 
 


                                                                         
               
                                      
         
         

                  



                                                                
                                             

                 
                                  
                         
                                               
               
                                                                

               
                    
       

                                           
                                       
                     
                                                       



                                              


                                                               
                                                     
    

                                                                 
                      


                                   
                                      




                                              
                                                         






                                                
                                             


                                     
                                          






                                                  

                                                                
                                                  
                                          













                                                  
                                    








                                              
                                    

                                                
                                     

                                                                                        
                    




                                                              
                        
                                                        
                        
                                         

                                                                             
                                            


                                                   
                   
 
                                        
                                               
                                      
    
                                                                     
                       
                                                                      
                          
                             
                                              
                                               
                               


                                                    
                                 
                     
                                                   

                           






                                                         
                                                              


                                                         
                                                                        
                                                                     
                                                                              
                                                                       
                                                                              
                                                                       
                                                                        


                                                                                                                                                             

                                                                                                                                                                                         
                                                                             

                                                                     

                                                                        
                                                           


                                                        

                                                                     




                                    

                                                           

                 


                










                                                                


















                                                                      

                                     
                                             




                                                                     
                                                               
                                      
                                                                 


                                                                         
# Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc.
#                         Chris Ball <cjb@laptop.org>
#                         Oleg Romanyshyn <oromanyshyn@panoramicfeedback.com>
#                         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.
"""List bugs"""
from libbe import cmdutil, bugdir, bug
import os
import re
__desc__ = __doc__

# get a list of * for cmp_*() comparing two bugs. 
AVAILABLE_CMPS = [fn[4:] for fn in dir(bug) if fn[:4] == 'cmp_']
AVAILABLE_CMPS.remove("attr") # a cmp_* template.

def execute(args, manipulate_encodings=True):
    """
    >>> import os
    >>> bd = bugdir.SimpleBugDir()
    >>> os.chdir(bd.root)
    >>> execute([], manipulate_encodings=False)
    a:om: Bug A
    >>> 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)
    complete(options, args, parser)    
    if len(args) > 0:
        raise cmdutil.UsageError("Too many arguments.")
    cmp_list = []
    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)))
            cmp_list.append(eval('bug.cmp_%s' % cmp))
    
    bd = bugdir.BugDir(from_disk=True,
                       manipulate_encodings=manipulate_encodings)
    bd.load_all_bugs()
    # select status
    if options.status != None:
        if options.status == "all":
            status = bug.status_values
        else:
            status = options.status.split(',')
    else:
        status = []
        if options.active == True:
            status.extend(list(bug.active_status_values))
        if options.unconfirmed == True:
            status.append("unconfirmed")
        if options.open == True:
            status.append("opened")
        if options.test == True:
            status.append("test")
        if status == []: # set the default value
            status = bug.active_status_values
    # select severity
    if options.severity != None:
        if options.severity == "all":
            severity = bug.severity_values
        else:
            severity = options.severity.split(',')
    else:
        severity = []
        if options.wishlist == True:
            severity.extend("wishlist")
        if options.important == True:
            serious = bug.severity_values.index("serious")
            severity.append(list(bug.severity_values[serious:]))
        if severity == []: # set the default value
            severity = bug.severity_values
    # select assigned
    if options.assigned != None:
        if options.assigned == "all":
            assigned = "all"
        else:
            assigned = options.assigned.split(',')
    else:
        assigned = []
        if options.mine == True:
            assigned.extend('-')
        if assigned == []: # set the default value
            assigned = "all"
    for i in range(len(assigned)):
        if assigned[i] == '-':
            assigned[i] = bd.user_id
    # select target
    if options.target != None:
        if options.target == "all":
            target = "all"
        else:
            target = options.target.split(',')
    else:
        target = []
        if options.cur_target == True:
            target.append(bd.target)
        if target == []: # set the default value
            target = "all"
    if options.extra_strings != None:
        extra_string_regexps = [re.compile(x) for x in options.extra_strings.split(',')]

    def filter(bug):
        if status != "all" and not bug.status in status:
            return False
        if severity != "all" and not bug.severity in severity:
            return False
        if assigned != "all" and not bug.assigned in assigned:
            return False
        if target != "all" and not bug.target in target:
            return False
        if options.extra_strings != None:
            if len(bug.extra_strings) == 0 and len(extra_string_regexps) > 0:
                return False
            for string in bug.extra_strings:
                for regexp in extra_string_regexps:
                    if not regexp.match(string):
                        return False
        return True

    bugs = [b for b in bd if filter(b) ]
    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 '<?xml version="1.0" encoding="%s" ?>' % bd.encoding
            print "<bugs>"
        if len(cur_bugs) > 0:
            if title != None and xml == False:
                print cmdutil.underlined(title)
            for bg in cur_bugs:
                if xml == True:
                    print bg.xml(show_comments=True)
                elif just_uuids:
                    print bg.uuid
                else:
                    print bg.string(shortlist=True)
        if xml == True:
            print "</bugs>"

    # sort bugs
    cmp_list.extend(bug.DEFAULT_CMP_FULL_CMP_LIST)
    cmp_fn = bug.BugCompoundComparator(cmp_list=cmp_list)
    bugs.sort(cmp_fn)

    # print list of bugs
    list_bugs(bugs, just_uuids=options.uuids, xml=options.xml)

def get_parser():
    parser = cmdutil.CmdOptionParser("be list [options]")
    parser.add_option("-s", "--status", metavar="STATUS", dest="status",
                      help="List bugs matching STATUS", default=None)
    parser.add_option("-v", "--severity", metavar="SEVERITY", dest="severity",
                      help="List bugs matching SEVERITY", default=None)
    parser.add_option("-a", "--assigned", metavar="ASSIGNED", dest="assigned",
                      help="List bugs matching ASSIGNED", default=None)
    parser.add_option("-t", "--target", metavar="TARGET", dest="target",
                      help="List bugs matching TARGET", default=None)
    parser.add_option("-e", "--extra-strings", metavar="STRINGS", dest="extra_strings",
                      help="List bugs matching _all_ extra strings in comma-seperated list STRINGS.  e.g. --extra-strings TAG:working,TAG:xml", default=None)
    parser.add_option("-S", "--sort", metavar="SORT-BY", dest="sort_by",
                      help="Adjust bug-sort criteria with comma-separated list SORT-BY.  e.g. \"--sort creator,time\".  Available criteria: %s" % ','.join(AVAILABLE_CMPS), default=None)
    # boolean options.  All but uuids and xml are special cases of long forms
    bools = (("u", "uuids", "Only print the bug UUIDS"),
             ("w", "wishlist", "List bugs with 'wishlist' severity"),
             ("i", "important", "List bugs with >= 'serious' severity"),
             ("A", "active", "List all active bugs"),
             ("U", "unconfirmed", "List unconfirmed bugs"),
             ("o", "open", "List open bugs"),
             ("T", "test", "List bugs in testing"),
             ("m", "mine", "List bugs assigned to you"),
             ("c", "cur-target", "List bugs for the current target"),
             ("x", "xml", "Dump as XML"))
    for s in bools:
        attr = s[1].replace('-','_')
        short = "-%c" % s[0]
        long = "--%s" % s[1]
        help = s[2]
        parser.add_option(short, long, action="store_true",
                          dest=attr, help=help)
    return parser


def help():
    longhelp="""
This command lists bugs.  Normally it prints a short string like
  576:om: Allow attachments
Where
  576   the bug id
  o     the bug status is 'open' (first letter)
  m     the bug severity is 'minor' (first letter)
  Allo... the bug summary string

You can optionally (-u) print only the bug ids.

There are several criteria that you can filter by:
  * status
  * severity
  * assigned (who the bug is assigned to)
  * target   (bugfix deadline)
Allowed values for each criterion may be given in a comma seperated
list.  The special string "all" may be used with any of these options
to match all values of the criterion.

status
  %s
severity
  %s
assigned
  free form, with the string '-' being a shortcut for yourself.
target
  free form

In addition, there are some shortcut options that set boolean flags.
The boolean options are ignored if the matching string option is used.
""" % (','.join(bug.status_values),
       ','.join(bug.severity_values))
    return get_parser().help_str() + longhelp

def complete(options, args, parser):
    for option, value in cmdutil.option_value_pairs(options, parser):
        if value == "--complete":
            if option == "status":
                raise cmdutil.GetCompletions(bug.status_values)
            elif option == "severity":
                raise cmdutil.GetCompletions(bug.severity_values)
            raise cmdutil.GetCompletions()
    if "--complete" in args:
        raise cmdutil.GetCompletions() # no positional arguments for list