#!/usr/bin/python # bugzilla - a commandline frontend for the python bugzilla module # # Copyright (C) 2007 Red Hat Inc. # Author: Will Woods # # 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. See http://www.gnu.org/copyleft/gpl.html for # the full text of the license. import bugzilla, optparse import os, sys, glob import logging version = '0.1' # Change this once we're ready for actual use default_bz = 'https://partner-bugzilla.redhat.com/xmlrpc.cgi' def findcookie(): globs = ['~/.mozilla/firefox/*default*/cookies.txt'] for g in globs: cookiefiles = glob.glob(os.path.expanduser(g)) if cookiefiles: # return the first one we find. # TODO: find all cookiefiles, sort by age, use newest return cookiefiles[0] def setup_parser(): u = "usage: %prog info|query|new|modify [options]" p = optparse.OptionParser(usage=u) # General bugzilla connection options p.add_option('--bugzilla',default=default_bz, help="bugzilla XMLRPC URI. default: %s" % default_bz) p.add_option('--user', help="username. Will attempt to use Firefox cookie if not specified.") p.add_option('--password', help="password") p.add_option('--cookiefile', help="cookie file to use for bugzilla authentication - default: %s" % findcookie()) return p def modify_parser(parser,action): p = parser if action == 'query': # TODO: product and version could default to current system # info (read from /etc/redhat-release?) p.add_option('-p','--product', help="product name (list with 'bugzilla info -p')") p.add_option('-v','--version', help="version string to search for") p.add_option('-c','--component', help="component name (list with 'bugzilla info -c PRODUCT')") p.add_option('-l','--long_desc', help="search inside bug comments") p.add_option('-s','--short_desc', help="search bug summaries") p.add_option('-b','--bug_id', help="select an individual bug ID") # output modifiers # FIXME: these should overwrite each other: store_const in output_type p.add_option('-f','--full',action='store_true', help="Give full bug info") p.add_option('-i','--ids',action='store_true', help="Just list bug IDs") elif action == 'info': p.add_option('-p','--products',action='store_true', help='Get a list of products') p.add_option('-c','--components',metavar="PRODUCT", help='List the components in the given product') p.add_option('-v','--versions',metavar="PRODUCT", help='List the versions for the given product') return p if __name__ == '__main__': log = logging.getLogger("bugzilla") # Set up parser parser = setup_parser() # Get our action if len(sys.argv) > 1 and sys.argv[1] in ('info','query','new','modify'): action = sys.argv[1] else: parser.error("you must specify an action") # Add the action-specific args and such parser = modify_parser(parser,action) # Parse the commandline, woo (opt,args) = parser.parse_args() # Connect to bugzilla log.info('Connecting to %s',opt.bugzilla) bz=bugzilla.Bugzilla(url=opt.bugzilla) if opt.user and opt.password: bz.login(opt.user,opt.password) elif opt.cookiefile: bz.readcookiefile(opt.cookiefile) else: cookiefile = findcookie() if cookiefile: bz.readcookiefile(cookiefile) else: parser.error("Could not find a Firefox cookie file. Try --user/--password.") # And now we actually execute the given command if action == 'info': if opt.products: for k in sorted(bz.products): print k if opt.components: for c in sorted(bz.getcomponents(opt.components)): print c if opt.versions: for p in bz.querydata['product']: if p['name'] == opt.versions: for v in p['versions']: print v elif action == 'query': # Construct the query from the list of queryable options q = dict() for a in ('product', 'component', 'version', 'long_desc', 'bug_id', 'short_desc'): if hasattr(opt,a): i = getattr(opt,a) if i: q[a] = i buglist = bz.query(q) if opt.ids: for b in buglist: print b.bug_id elif not opt.full: for b in buglist: print b else: fullbuglist = bz.getbugs([b.bug_id for b in buglist]) for b in fullbuglist: print b print "CC: %s" % b.cc for c in b.longdescs: print "* %s - %s (%s):\n %s\n" % (c['time'],c['name'],c['email'] or c['safe_email'],c['body']) else: print "Sorry - '%s' not implemented yet." % action