## -*- coding: utf-8 -*- ## ## ## Copyright 2010, 2013 Oracle and/or its affiliates. All rights reserved. ## <%! import cgi import itertools import pkg.actions as actions import pkg.query_parser as qp import pkg.server.api_errors as api_errors import pkg.version as version import re import urllib import urlparse %>\ <%inherit file="layout.shtml"/>\ <%page args="g_vars"/>\ <% catalog = g_vars["catalog"] request = g_vars["request"] http_depot = g_vars["http_depot"] %>\ <%def name="page_title(g_vars)"><% return "Package Search" %>\ <%def name="get_search_criteria(request)"><% # Based on the request parameters, return a dict representing the # search criteria. criteria = { "token": request.params.get("token", ""), "query_error": request.params.get("qe", ""), } criteria["searched"] = len(criteria["token"]) show = request.params.get("show", "p") if show == "p" or show not in ("a", "p"): criteria["return_type"] = qp.Query.RETURN_PACKAGES elif show == "a": criteria["return_type"] = qp.Query.RETURN_ACTIONS for name, default in (("rpp", 50), ("start", 0), ("failed", 0), ("sav", 0), ("cs", 0)): val = request.params.get(name, default) try: val = int(val) except ValueError: val = default # Force boolean type for these parameters. if name in ("cs", "sav"): if val: val = True else: val = False criteria[name] = val return criteria %>\ <%def name="search(catalog, request, criteria)"><% # Gets the search results for the specified catalog based on the # provided search criteria. query_error = None token = criteria["token"] cs = criteria["cs"] rpp = criteria["rpp"] return_type = criteria["return_type"] start_val = criteria["start"] # This criteria is optional, so use get to retrieve it. mver = criteria.get("selected_ver", None) if mver: # Replace leading version components with wildcard so that # matching is only performed using build_release and branch. mver = "*,%s-%s" % (mver.build_release, mver.branch) # Determines whether all versions or only the latest vresion of a # package is shown. This is ignored when the return_type is not # qp.Query.RETURN_PACKAGES. sav = criteria["sav"] try: # Search results are limited to just one more than the # results per page so that a query that exceeds it can be # detected. results = catalog.search(token, case_sensitive=cs, return_type=return_type, start_point=start_val, num_to_return=(rpp + 1), matching_version=mver, return_latest=not sav) except qp.QueryLengthExceeded, e: results = None query_error = str(e) except qp.QueryException, e: results = None query_error = str(e) except Exception, e: results = None query_error = urllib.quote(str(e)) # Before showing the results, the type of results being shown has to be # determined since the user might have overridden the return_type # selection above using query syntax. To do that, the first result will # have to be checked for the real return type. if results: try: result = results.next() except StopIteration: result = None results = None pass if result and result[1] == qp.Query.RETURN_PACKAGES: return_type = result[1] results = itertools.chain([result], results) elif result and result[1] == qp.Query.RETURN_ACTIONS: return_type = result[1] results = itertools.chain([result], results) elif result: return_type = qp.Query.RETURN_PACKAGES query_error = "Only the display of packages or " \ "actions for search results is supported." request.log("Unsupported return_type '%s' " "requested for search query: '%s'." % (return_type, token)) return return_type, results, query_error %>\ <%def name="display_search_form(criteria, request)"><% # Returns an HTML form with all of the elements needed to perform a # search using the specified search criteria and request. token = criteria["token"] search_uri = "advanced_search.shtml" if criteria["searched"]: search_uri = request.url(qs=request.query_string, relative=True) search_uri = search_uri.replace("search.shtml", "advanced_search.shtml") %>\ \ <%def name="get_prev_page_uri(criteria, request)"><% # Returns a URL relative to the current request path with the # starting range of the previous page of search results set. uri = request.url(qs=request.query_string, relative=True) scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) nparams = [] for name, val in request.params.iteritems(): if name == "start": continue nparams.append((name, val)) start = criteria["start"] start = start - criteria["rpp"] if start < 0: start = 0 nparams.append(("start", start)) qs = urllib.urlencode(nparams) uri = urlparse.urlunparse((scheme, netloc, path, params, qs, fragment)) return uri %>\ <%def name="get_next_page_uri(criteria, request, result_count)"><% # Returns a URL relative to the current request path with the # starting range of the next page of search results set. uri = request.url(qs=request.query_string, relative=True) scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) nparams = [] for name, val in request.params.iteritems(): if name == "start": continue nparams.append((name, val)) start = criteria["start"] nparams.append(("start", (start + result_count - 1))) qs = urllib.urlencode(nparams) uri = urlparse.urlunparse((scheme, netloc, path, params, qs, fragment)) return uri %>\ <%def name="display_pagination(criteria, result_count, colspan=1)"><% # Returns a table row with the appropriate pagination controls # based on the provided search criteria. show_prev = criteria["start"] > 0 show_next = result_count > criteria["rpp"] if not (show_prev or show_next): # Nothing to display. return "" %>\ % if show_prev: Previous % else:   % endif % if show_next: Next % else:   % endif \
% if not catalog.search_available:

Search functionality is not available at this time.

% else: <% results = None return_type = None criteria = self.get_search_criteria(request) searched = criteria["searched"] failed = criteria["failed"] query_error = criteria["query_error"] if query_error: # Sanitize query_error to prevent misuse; lines = cgi.escape(query_error, True).splitlines(True) n_qe = "" last_pre = False # Put all lines which start with a \t in
 tags since these
                # contain pre-formatted error descriptions.
                for l in lines:
                        if l.startswith("\t"):
                                if not last_pre:
                                        n_qe += "
"
                                n_qe += l
                                last_pre = True
                        else:
                                if last_pre:
                                        n_qe += "
" last_pre = False n_qe += l.replace("\n","
") else: if last_pre: last_pre = False n_qe += "
" query_error = n_qe if not failed and searched: return_type, results, query_error = self.search( catalog, request, criteria) if query_error or not results: # Reload the page with a few extra query parameters set # so that failed searches can be detected in the server # logs (including that of any proxies in front of the # depot server). uri = request.url(qs=request.query_string, relative=True) if http_depot: # if using the http-depot, we need to redirect # to the appropriate repository within the # webapp. lang = request.path_info.split("/")[1] uri = "/depot/%s/%s/%s" % (http_depot, lang, uri) scheme, netloc, path, params, query, \ fragment = urlparse.urlparse(uri) nparams = [] for name, val in request.params.iteritems(): if name in ("failed", "query_error"): continue nparams.append((name, val)) nparams.append(("failed", 1)) if query_error: nparams.append(("qe", query_error)) qs = urllib.urlencode(nparams) uri = urlparse.urlunparse((scheme, netloc, path, params, qs, fragment)) raise api_errors.RedirectException(uri) rpp = criteria["rpp"] result_count = 0 %>\
${self.display_search_form(criteria, request)} % if not searched:

Search Tips:

% endif
% if searched and return_type == qp.Query.RETURN_PACKAGES: ## Showing packages. % for v, return_type, vals in results: <% pfmri = vals if result_count % 2: rclass = ' class="odd"' else: rclass = "" result_count += 1 if result_count > rpp: break stem = pfmri.pkg_name pfmri_str = pfmri.get_fmri(anarchy=True, include_scheme=False) phref = self.shared.rpath(g_vars, "info/0/%s" % ( urllib.quote(pfmri_str, ""))) # XXX the .p5i extension is a bogus hack because # packagemanager requires it and shouldn't. p5ihref = self.shared.rpath(g_vars, "p5i/0/%s.p5i" % ( urllib.quote(stem, ""))) mhref = self.shared.rpath(g_vars, "manifest/0/%s" % pfmri.get_url_path()) %>\ % endfor ${display_pagination(criteria, result_count, colspan=2)}
Package Install Manifest
${pfmri_str} Install Manifest
% elif searched and return_type == qp.Query.RETURN_ACTIONS: % for v, return_type, vals in results: <% pfmri, match, action = vals a = actions.fromstr(action.rstrip()) action = a.name if isinstance(a, actions.attribute.AttributeAction): index = a.attrs.get(a.key_attr) value = match else: index = match value = a.attrs.get(a.key_attr) %> <% if result_count % 2: rclass = ' class="odd"' else: rclass = "" result_count += 1 if result_count > rpp: break pfmri_str = pfmri.get_fmri(anarchy=True, include_scheme=False) phref = self.shared.rpath(g_vars, "info/0/%s" % ( urllib.quote(pfmri_str, ""))) %>\ % endfor ${display_pagination(criteria, result_count, colspan=2)}
Index Action Value Package
${index | h} ${action | h} ${value | h} ${pfmri_str}
% elif query_error: <% token = criteria["token"] %>

Your search - ${token | h} - is not a valid query.

Suggestions:

Details:

${query_error} % elif failed: <% token = criteria["token"] %>

Your search - ${token | h} - did not match any packages.

Suggestions:

% endif
% endif