mirror of
https://github.com/openSUSE/osc.git
synced 2024-11-10 06:46:15 +01:00
- added initial search support (some ideas are taken from the webclient):
* when searching a package/project it is also possible to search for the search term in the <title /> and <description /> elements of a package/project. * show only exact matches * etc. - please tell me if the usability is too "complex" or if the output of the results is too weird.
This commit is contained in:
parent
5a4f1e4d42
commit
cf3727b70c
@ -1505,7 +1505,7 @@ class Osc(cmdln.Cmdln):
|
||||
def do_wipebinaries(self, subcmd, opts, *args):
|
||||
"""${cmd_name}: Delete all binary packages of a certain project/package
|
||||
|
||||
With the optional arguement <package> you can specify a certain package
|
||||
With the optional argument <package> you can specify a certain package
|
||||
otherwise all binary packages in the project will be deleted.
|
||||
|
||||
usage:
|
||||
@ -1527,6 +1527,70 @@ class Osc(cmdln.Cmdln):
|
||||
print wipebinaries(conf.config['apiurl'], args[0], package, opts.arch, opts.repo, opts.build_disabled)
|
||||
|
||||
|
||||
@cmdln.option('-e', '--enable-exact', action='store_true',
|
||||
help='show only exact matches')
|
||||
@cmdln.option('--package', action='store_true',
|
||||
help='search for a package')
|
||||
@cmdln.option('--project', action='store_true',
|
||||
help='search for a project')
|
||||
@cmdln.option('--title', action='store_true',
|
||||
help='search for matches in the \'title\' element')
|
||||
@cmdln.option('--description', action='store_true',
|
||||
help='search for matches in the \'description\' element')
|
||||
@cmdln.option('-v', '--verbose', action='store_true',
|
||||
help='show more information')
|
||||
def do_search(self, subcmd, opts, *args):
|
||||
"""${cmd_name}: search for a project and/or package.
|
||||
|
||||
If no option is specified osc will search for projects and
|
||||
packages which contains the \'search term\' in their name,
|
||||
title or description.
|
||||
|
||||
usage:
|
||||
osc search \'search term\' <options>
|
||||
${cmd_option_list}
|
||||
"""
|
||||
|
||||
if len(args) > 1:
|
||||
print >>sys.stderr, 'too many arguments'
|
||||
sys.exit(1)
|
||||
elif len(args) < 1:
|
||||
print >>sys.stderr, 'too few arguments'
|
||||
sys.exit(1)
|
||||
|
||||
search_list = []
|
||||
search_for = []
|
||||
if opts.title:
|
||||
search_list.append('title')
|
||||
if opts.description:
|
||||
search_list.append('description')
|
||||
if opts.package:
|
||||
search_list.append('@name')
|
||||
search_for.append('package')
|
||||
if opts.project:
|
||||
search_list.append('@name')
|
||||
search_for.append('project')
|
||||
|
||||
if not search_list:
|
||||
search_list = ['title', 'description', '@name']
|
||||
if not search_for:
|
||||
search_for = [ 'project', 'package' ]
|
||||
for kind in search_for:
|
||||
result = search(conf.config['apiurl'], set(search_list), kind, args[0], opts.verbose, opts.enable_exact)
|
||||
if result:
|
||||
if kind == 'package':
|
||||
headline = [ '# Package', '# Project' ]
|
||||
else:
|
||||
headline = [ '# Project' ]
|
||||
if opts.verbose:
|
||||
headline.append('# Title')
|
||||
if len(search_for) > 1:
|
||||
print '#' * 68
|
||||
print 'matches for \'%s\' in %ss:\n' % (args[0], kind)
|
||||
for row in build_table(len(headline), result, headline, 2):
|
||||
print row
|
||||
else:
|
||||
print 'No matches found for \'%s\' in %ss' % (args[0], kind)
|
||||
|
||||
# load subcommands plugged-in locally
|
||||
plugin_dirs = ['/var/lib/osc-plugins', os.path.expanduser('~/.osc-plugins')]
|
||||
|
95
osc/core.py
95
osc/core.py
@ -1662,3 +1662,98 @@ def checkRevision(prj, pac, revision):
|
||||
return True
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
|
||||
def build_xpath_predicate(search_list, search_term, exact_matches):
|
||||
"""
|
||||
Builds and returns a xpath predicate
|
||||
"""
|
||||
|
||||
predicate = ['[']
|
||||
for i, elem in enumerate(search_list):
|
||||
if i > 0 and i < len(search_list):
|
||||
predicate.append(' or ')
|
||||
if exact_matches:
|
||||
predicate.append('%s=\'%s\'' % (elem, search_term))
|
||||
else:
|
||||
predicate.append('contains(%s, \'%s\')' % (elem, search_term))
|
||||
predicate.append(']')
|
||||
return predicate
|
||||
|
||||
def build_table(col_num, data = [], headline = [], width=1):
|
||||
"""
|
||||
This method builds a simple table.
|
||||
Example1: build_table(2, ['foo', 'bar', 'suse', 'osc'], ['col1', 'col2'], 2)
|
||||
col1 col2
|
||||
foo bar
|
||||
suse osc
|
||||
"""
|
||||
|
||||
longest_col = []
|
||||
for i in range(col_num):
|
||||
longest_col.append(0)
|
||||
if headline:
|
||||
data[0:0] = headline
|
||||
# find longest entry in each column
|
||||
i = 0
|
||||
for itm in data:
|
||||
if longest_col[i] < len(itm):
|
||||
longest_col[i] = len(itm)
|
||||
if i == col_num - 1:
|
||||
i = 0
|
||||
else:
|
||||
i += 1
|
||||
# calculate length for each column
|
||||
for i, row in enumerate(longest_col):
|
||||
longest_col[i] = row + width
|
||||
# build rows
|
||||
row = []
|
||||
table = []
|
||||
i = 0
|
||||
for itm in data:
|
||||
if i % col_num == 0:
|
||||
if row:
|
||||
table.append(''.join(row))
|
||||
i = 0
|
||||
row = [itm.ljust(longest_col[i])]
|
||||
else:
|
||||
# there is no need to justify the entries of the last column
|
||||
if i == col_num -1:
|
||||
row.append(itm)
|
||||
else:
|
||||
row.append(itm.ljust(longest_col[i]))
|
||||
i += 1
|
||||
table.append(''.join(row))
|
||||
return table
|
||||
|
||||
def search(apiurl, search_list, kind, search_term, verbose = False, exact_matches = False):
|
||||
"""
|
||||
Perform a search for 'search_term'. A list which contains the
|
||||
results will be returned on success otherwise 'None'. If 'verbose' is true
|
||||
and the title-tag-text (<title>TEXT</title>) is longer than 60 chars it'll we
|
||||
truncated.
|
||||
"""
|
||||
|
||||
predicate = build_xpath_predicate(search_list, search_term, exact_matches)
|
||||
u = makeurl(apiurl, ['search', kind], ['match=%s' % quote_plus(''.join(predicate))])
|
||||
f = http_GET(u)
|
||||
root = ET.parse(f).getroot()
|
||||
result = []
|
||||
for node in root.findall(kind):
|
||||
# TODO: clarify if we need to check if node.get() returns 'None'.
|
||||
# If it returns 'None' something is broken anyway...
|
||||
if kind == 'package':
|
||||
project = node.get('project')
|
||||
package = node.get('name')
|
||||
result.append(package)
|
||||
else:
|
||||
project = node.get('name')
|
||||
result.append(project)
|
||||
if verbose:
|
||||
title = node.findtext('title').strip()
|
||||
if len(title) > 60:
|
||||
title = title[:61] + '...'
|
||||
result.append(title)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
Loading…
Reference in New Issue
Block a user