# Copyright (C) 2005-2010 Aaron Bentley and Panometrics, Inc. # Gianluca Montecchi # Oleg Romanyshyn # 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. import os import re import libbe import libbe.bug import libbe.command import libbe.command.depend import libbe.command.target import libbe.command.util # get a list of * for cmp_*() comparing two bugs. AVAILABLE_CMPS = [fn[4:] for fn in dir(libbe.bug) if fn[:4] == 'cmp_'] AVAILABLE_CMPS.remove('attr') # a cmp_* template. 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 else: for string in bug.extra_strings: for regexp in self.extra_strings_regexps: if not regexp.match(string): return False return True class List (libbe.command.Command): """List bugs >>> import sys >>> import libbe.bugdir >>> bd = libbe.bugdir.SimpleBugDir(memory=False) >>> io = libbe.command.StringInputOutput() >>> io.stdout = sys.stdout >>> ui = libbe.command.UserInterface(io=io) >>> ui.storage_callbacks.set_storage(bd.storage) >>> cmd = List(ui=ui) >>> ret = ui.run(cmd) abc/a:om: Bug A >>> ret = ui.run(cmd, {'status':'closed'}) abc/b:cm: Bug B >>> bd.storage.writeable True >>> ui.cleanup() >>> bd.cleanup() """ name = 'list' def __init__(self, *args, **kwargs): libbe.command.Command.__init__(self, *args, **kwargs) self.options.extend([ libbe.command.Option(name='status', help='Only show bugs matching the STATUS specifier', arg=libbe.command.Argument( name='status', metavar='STATUS', default='active', completion_callback=libbe.command.util.complete_status)), libbe.command.Option(name='severity', help='Only show bugs matching the SEVERITY specifier', arg=libbe.command.Argument( name='severity', metavar='SEVERITY', default='all', completion_callback=libbe.command.util.complete_severity)), libbe.command.Option(name='assigned', short_name='a', help='Only show bugs matching ASSIGNED', arg=libbe.command.Argument( name='assigned', metavar='ASSIGNED', default='all', completion_callback=libbe.command.util.complete_assigned)), libbe.command.Option(name='extra-strings', short_name='e', help='Only show bugs matching STRINGS, e.g. --extra-strings' ' TAG:working,TAG:xml', arg=libbe.command.Argument( name='extra-strings', metavar='STRINGS', default=None, completion_callback=libbe.command.util.complete_extra_strings)), libbe.command.Option(name='sort', short_name='S', help='Adjust bug-sort criteria with comma-separated list ' 'SORT. e.g. "--sort creator,time". ' 'Available criteria: %s' % ','.join(AVAILABLE_CMPS), arg=libbe.command.Argument( name='sort', metavar='SORT', default=None, completion_callback=libbe.command.util.Completer(AVAILABLE_CMPS))), libbe.command.Option(name='ids', short_name='i', help='Only print the bug IDS'), libbe.command.Option(name='xml', short_name='x', help='Dump output in XML format'), ]) # 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 ids and xml are special cases of long forms # ("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")) # 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, default=False) # return parser # # ]) def _run(self, **params): bugdir = self._get_bugdir() writeable = bugdir.storage.writeable bugdir.storage.writeable = False cmp_list, status, severity, assigned, extra_strings_regexps = \ self._parse_params(params) filter = Filter(status, severity, assigned, extra_strings_regexps=extra_strings_regexps) bugs = [bugdir.bug_from_uuid(uuid) for uuid in bugdir.uuids()] bugs = [b for b in bugs if filter(bugdir, b) == True] self.result = bugs if len(bugs) == 0 and params['xml'] == False: print >> self.stdout, "No matching bugs found" # sort bugs bugs = self._sort_bugs(bugs, cmp_list) # print list of bugs if params['ids'] == True: for bug in bugs: print >> self.stdout, bug.id.user() else: self._list_bugs(bugs, xml=params['xml']) bugdir.storage.writeable = writeable return 0 def _parse_params(self, params): cmp_list = [] if params['sort'] != None: for cmp in params['sort'].sort_by.split(','): if cmp not in AVAILABLE_CMPS: raise libbe.command.UserError( "Invalid sort on '%s'.\nValid sorts:\n %s" % (cmp, '\n '.join(AVAILABLE_CMPS))) cmp_list.append(eval('libbe.bug.cmp_%s' % cmp)) # select status if params['status'] == 'all': status = libbe.bug.status_values elif params['status'] == 'active': status = list(libbe.bug.active_status_values) elif params['status'] == 'inactive': status = list(libbe.bug.inactive_status_values) else: status = libbe.command.util.select_values( params['status'], libbe.bug.status_values) # select severity if params['severity'] == 'all': severity = libbe.bug.severity_values elif params['important'] == True: serious = libbe.bug.severity_values.index('serious') severity.append(list(libbe.bug.severity_values[serious:])) else: severity = libbe.command.util.select_values( params['severity'], bug.severity_values) # select assigned if params['assigned'] == "all": assigned = "all" else: assigned = libbe.command.util.select_values( params['assigned'], libbe.command.util.assignees()) for i in range(len(assigned)): if assigned[i] == '-': assigned[i] = params['user-id'] if params['extra-strings'] == None: extra_strings_regexps = [] else: extra_strings_regexps = [re.compile(x) for x in params['extra-strings'].split(',')] return (cmp_list, status, severity, assigned, extra_strings_regexps) def _sort_bugs(self, bugs, cmp_list=[]): cmp_list.extend(libbe.bug.DEFAULT_CMP_FULL_CMP_LIST) cmp_fn = libbe.bug.BugCompoundComparator(cmp_list=cmp_list) bugs.sort(cmp_fn) return bugs def _list_bugs(self, bugs, xml=False): if xml == True: print >> self.stdout, \ '' % self.stdout.encoding print >> self.stdout, '' if len(bugs) > 0: for bug in bugs: if xml == True: print >> self.stdout, bug.xml(show_comments=True) else: print >> self.stdout, bug.string(shortlist=True) if xml == True: print >> self.stdout, '' def _long_help(self): return """ 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) 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. As with the --status and --severity options for `be depend`, starting the list with a minus sign makes your selections a blacklist instead of the default whitelist. status %s severity %s assigned free form, with the string '-' being a shortcut for yourself. In addition, there are some shortcut options that set boolean flags. The boolean options are ignored if the matching string option is used. """ % (','.join(libbe.bug.status_values), ','.join(libbe.bug.severity_values))