Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 162768 Details for
Bug 208376
Missing "Search" Capability on Packages Webpage
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
This is a patch that adds a search feature to the package.g.o website
git.diff (text/plain), 11.16 KB, created by
manuels
on 2008-08-12 17:07:12 UTC
(
hide
)
Description:
This is a patch that adds a search feature to the package.g.o website
Filename:
MIME Type:
Creator:
manuels
Created:
2008-08-12 17:07:12 UTC
Size:
11.16 KB
patch
obsolete
>diff --git a/web/controller.py b/web/controller.py >index 7e56b1e..842cdeb 100644 >--- a/web/controller.py >+++ b/web/controller.py >@@ -1,7 +1,7 @@ > #!/usr/bin/env python > """Packages2 CherryPy Application and launcher""" > >-import os, sys, math >+import os, sys, math, string, re, types > > import cherrypy > >@@ -20,9 +20,11 @@ class Root(object): > """Packages2 CherryPy Application""" > > database = None >+ regexp_atomic = None > > def __init__(self, db): > self.database = db >+ self.regexp_atomic = re.compile(r"(>|>=|=|<=|<)?([a-z0-9-]*/)?([a-z-]*)(-[0-9.]*)?(-r[0-9])?$", re.IGNORECASE) > > > @property >@@ -409,6 +411,78 @@ class Root(object): > > @cherrypy.expose > @template.expire_on_30_min() >+ @template.output('index.html', method='xhtml') >+ def search(self, *args, **kwds): >+ """Search for ebuilds""" >+ return self._search(*args, **kwds) >+ >+ def _search(self, *args, **kwds): >+ """Search for ebuilds""" >+ sstring = string.strip(kwds["searchstring"]) >+ >+ db = self.database >+ entry_filter = filters.EntryFilters(db) >+ >+ sinfo = { >+ "comparator": None, >+ "categories": [], >+ "pkgname": None, >+ "version": None, >+ "anyfield": None, >+ } >+ >+ # process search string >+ match = self.regexp_atomic.match(sstring) >+ if match: >+ [comparator, category, pkgname, version, revision] = match.groups() >+ sinfo["pkgname"] = pkgname >+ >+ # regexp matches single word too, so a single word must not be a package name >+ if pkgname and not (category or version): >+ sinfo["anyfield"] = pkgname >+ sinfo["pkgname"] = None >+ >+ if version: # remove leading divis >+ version = version[1:] >+ if revision: >+ sinfo["version"] = version+revision >+ else: >+ sinfo["version"] = version >+ if not comparator: >+ sinfo["comparator"] = "=" >+ else: >+ sinfo["comparator"] = comparator >+ if category: >+ sinfo["categories"].append(category[:len(category)-1]) #remove tailing slash >+ else: >+ sinfo["anyfield"] = sstring >+ >+ limit = filters.limit_centercount(kwds) >+ >+ search_entries = entry_filter.search_filter(sinfo, limit=None) >+ center_pkgs = build_centerpkg_list(search_entries, >+ db.get_package_details_cpv, None) >+ >+ pagetitle = "/search" >+ >+ arches = filters.limit_arches(kwds) >+ kwds = sanitize_query_string(kwds) >+ latest_entries = self.cache_latest >+ left_daycount = filters.limit_leftcount(kwds) >+ day_list = latest_per_day(latest_entries, left_daycount) >+ left_daycount = filters.limit_leftcount(kwds) >+ arches = filters.limit_arches(kwds) >+ latest_entry = entry_filter.latest_entry() >+ >+ db.close_mc() >+ return template.render(arches = arches, >+ daylist = day_list, center_pkgs = center_pkgs, >+ lastupdate = latest_entry, safeqs = kwds, >+ pagetitle = pagetitle) >+ >+ >+ @cherrypy.expose >+ @template.expire_on_30_min() > @template.output('index.xml', method='xml') > def feed(self, *args, **kwds): > """Render the /feed/<someurl> page as Atom""" >@@ -427,6 +501,8 @@ class Root(object): > return self._category(*args, **kwds) > elif base == "package": > return self._package(*args, **kwds) >+ elif base == "search": >+ return self._search(*args, **kwds) > elif base == "verbump": > return self._verbump(*args, **kwds) > elif base == "newpackage": >diff --git a/web/lib/filters.py b/web/lib/filters.py >index 6afacc1..d7290b5 100644 >--- a/web/lib/filters.py >+++ b/web/lib/filters.py >@@ -82,6 +82,14 @@ class EntryFilters(object): > return [] > return self.package_source.get_latest_cpvs_by_pkgname(pkgname, limit) > >+ def search_filter(self, sinfo, limit=None): >+ """we don't use cache here""" >+ return self._search_filter(sinfo, limit) >+ >+ def _search_filter(self, sinfo, limit=None): >+ """filter packages by search criteria (uncached)""" >+ return self.package_source.get_cpvs_by_searchcriteria(sinfo, limit) >+ > def category_package_filter(self, category, pkgname, limit=None): > """Skip packages not matching pkgname and category""" > key = 'category_package_filter_%r%r%r' % (category, pkgname, limit) >diff --git a/web/lib/query_filter.py b/web/lib/query_filter.py >index afa6fad..5bb72da 100644 >--- a/web/lib/query_filter.py >+++ b/web/lib/query_filter.py >@@ -102,6 +102,8 @@ def create_rel(path): > t = '%s %s' % (m[3], m[2]) > elif path.startswith('/verbump'): > t = 'Version bumps' >+ elif path.startswith('/search'): >+ t = 'Search' > elif path.startswith('/newpackage'): > t = 'New packages' > elif path.startswith('/faq'): >diff --git a/web/model.py b/web/model.py >index dc1301e..418d1e5 100644 >--- a/web/model.py >+++ b/web/model.py >@@ -1,6 +1,6 @@ > from time import localtime, strftime, time > import datetime >-import re, sys >+import re, sys, types > import operator > import cherrypy > >@@ -82,6 +82,7 @@ class PackageDB(object): > columns_category_pn_pv = None > sql = {} > mc = None >+ valid_modes = ['+', '~', 'M', 'M+', 'M~', ''] > > def __init__(self, config=None): > # Do not complain about correct usage of ** magic >@@ -348,6 +349,123 @@ class PackageDB(object): > cursor.close() > return entries > >+ sql['SELECT_get_cpvs_by_searchcriteria'] = """ >+ SELECT __CPV__, versions.mtime >+ FROM versions >+ JOIN packages USING (cp) >+ JOIN categories USING (c) >+ __JOINS__ >+ WHERE __WHERE__ >+ ORDER by versions.mtime DESC >+ LIMIT 0, ? >+ """ >+ def get_cpvs_by_searchcriteria(self, sinfo, limit=None): >+ """return cpvs matching the search criteria""" >+ criteria = [] >+ params = [] >+ joins = [] >+ >+ # strrep produces strings like "(?,?,?,?)" >+ def strrep(chr, delimiter, count): >+ ret = chr >+ for i in range(count-1): >+ ret += delimiter >+ ret += chr >+ return ret >+ >+ def add_criterion(arg, sql, join_info): >+ if type(arg)==types.ListType: >+ if replacer: >+ sql = sql % replacer >+ criteria.append(sql) >+ params.extend(arg) >+ else: >+ criteria.append(sql) >+ params.append(arg) >+ if join_info: >+ if join_info not in joins: >+ joins.append(join_info) >+ return >+ >+ sql_criteria = { >+ "pkgname": "pn LIKE "+self.syntax_placeholder, >+ "categories": "category IN (%s)", >+ "category": "category LIKE "+self.syntax_placeholder, >+ "version_eq": "pv = "+self.syntax_placeholder, >+ "version_gt": "pv > "+self.syntax_placeholder, >+ "version_ge": "pv >= "+self.syntax_placeholder, >+ "version_lt": "pv < "+self.syntax_placeholder, >+ "version_le": "pv <= "+self.syntax_placeholder, >+ "anyfield": "((MATCH (description, changelog) AGAINST ("+self.syntax_placeholder+")) OR (MATCH (pn) AGAINST("+self.syntax_placeholder+")))" >+ } >+ >+ if sinfo["pkgname"]: >+ add_criterion("%"+sinfo["pkgname"]+"%", sql_criteria["pkgname"], None) >+ >+ if sinfo["categories"]: >+ if len(sinfo["categories"]) > 1: >+ add_criterion(sinfo["categories"], sql_criteria["categories"], None, strrep(self.syntax_placeholder, ",", len(sinfo["categories"]))) >+ else: >+ add_criterion("%"+sinfo["categories"][0]+"%", sql_criteria["category"], None) >+ >+ if sinfo["version"]: >+ available_comparators = { >+ ">": sql_criteria["version_gt"], >+ ">=": sql_criteria["version_ge"], >+ "=": sql_criteria["version_eq"], >+ "<=": sql_criteria["version_le"], >+ "<": sql_criteria["version_lt"] >+ } >+ if not sinfo["comparator"]: >+ sinfo["comparator"] = "=" >+ if sinfo["comparator"] not in available_comparators.keys(): >+ return [] >+ add_criterion(sinfo["version"], available_comparators[sinfo["comparator"]], None) >+ >+ if sinfo["anyfield"]: >+ add_criterion(sinfo["anyfield"], sql_criteria["anyfield"], ["metadata", "cp"]) >+ params.append(sinfo["anyfield"]) >+ >+ if limit is None: >+ limit = 1000 >+ try: >+ limit = int(limit) >+ except ValueError: >+ return [] >+ params.append(limit) >+ >+ >+ # build sql query string >+ criteria_str = "" >+ i = 0 >+ for c in criteria: >+ if (i > 0) and i < len(criteria): >+ criteria_str += " AND " >+ criteria_str += c >+ i += 1 >+ joins_str = "" >+ for j in joins: >+ joins_str += "JOIN %s USING (%s) " % (j[0], j[1]) >+ print joins_str >+ >+ sql = self.sql['SELECT_get_cpvs_by_searchcriteria'] >+ >+ reps = [] >+ reps.append(('__JOINS__', joins_str)) >+ reps.append(('__WHERE__', criteria_str)) >+ # Only used once >+ spacematch = re.compile(r'(\s+|\n)') >+ for o, n in reps: >+ sql = sql.replace(o, n) >+ sql = spacematch.sub(' ', sql) >+ >+ >+ cursor = self.cursor() >+ cursor.execute(sql, params) >+ entries = cursor.fetchall() >+ cursor.close() >+ return entries >+ > sql['SELECT_get_latest_cpvs_by_arch_mode'] = """ > SELECT __CPV__, versions.mtime > FROM arches >@@ -373,7 +491,7 @@ class PackageDB(object): > def get_latest_cpvs_by_arch(self, arch, mode, limit=None): > """return modified cpvs limited by arch and mode""" > >- valid_modes = ['+', '~', 'M', 'M+', 'M~', ''] >+ valid_modes = self.valid_modes > params = () > if mode not in valid_modes or arch not in self.arches: > return [] >diff --git a/web/static/style.css b/web/static/style.css >index 84a0174..a0e0476 100644 >--- a/web/static/style.css >+++ b/web/static/style.css >@@ -212,6 +212,10 @@ a:visited { > background: #dddaec; > } > >+#rightcontent input.search { >+ width: 8em; >+} >+ > #rightcontent p, #rightcontent ul { > /* margin: 1em; */ > } >diff --git a/web/templates/layout.html b/web/templates/layout.html >index 6ca22ee..2aca77d 100644 >--- a/web/templates/layout.html >+++ b/web/templates/layout.html >@@ -56,7 +56,16 @@ def alpha_url(baseurl): > <p class="update"> > Last update:<br />${HTML(lastmodified_rightcontent(lastupdate))} > </p> >- >+ >+ <div> >+ <span class="left-legend">Search</span> >+ >+ <form action="search" method="get"> >+ <input class="search" type="text" name="searchstring" /> >+ <input type="submit" value="Go!" /> >+ </form> >+ </div> >+ > <div> > <span class="left-legend">Legend</span> > <ul class="legend left-bar-list"
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 208376
: 162768 |
222389
|
222497