Example #1
0
        def search(self, tokens, case_sensitive=False,
            return_type=qp.Query.RETURN_PACKAGES, start_point=None,
            num_to_return=None, matching_version=None, return_latest=False):
                """Searches the catalog for actions or packages (as determined
                by 'return_type') matching the specified 'tokens'.

                'tokens' is a string using pkg(7) query syntax.

                'case_sensitive' is an optional, boolean value indicating
                whether matching entries must have the same case as that of
                the provided tokens.

                'return_type' is an optional, constant value indicating the
                type of results to be returned.  This constant value should be
                one provided by the pkg.server.query_parser.Query class.

                'start_point' is an optional, integer value indicating how many
                search results should be discarded before returning any results.
                None is interpreted to mean 0.

                'num_to_return' is an optional, integer value indicating how
                many search results should be returned.  None means return all
                results.

                'matching_version' is a string in the format expected by the
                pkg.version.MatchingVersion class that will be used to further
                filter the search results as they are retrieved.

                'return_latest' is an optional, boolean value that will cause
                only the latest versions of packages to be returned.  Ignored
                if 'return_type' is not qp.Query.RETURN_PACKAGES.
                """

                if not tokens:
                        return []

                tokens = tokens.split()
                if not self.search_available:
                        return []

                if start_point is None:
                        start_point = 0

                def filter_results(results, mver):
                        found = 0
                        last_stem = None
                        for result in results:
                                if found and \
                                    ((found - start_point) >= num_to_return):
                                        break

                                if result[1] == qp.Query.RETURN_PACKAGES:
                                        pfmri = result[2]
                                elif result[1] == qp.Query.RETURN_ACTIONS:
                                        pfmri = result[2][0]

                                if mver is not None:
                                        if mver != pfmri.version:
                                                continue

                                if return_latest and \
                                    result[1] == qp.Query.RETURN_PACKAGES:
                                        # Latest version filtering can only be
                                        # done for packages as only they are
                                        # guaranteed to be in version order.
                                        stem = result[2].pkg_name
                                        if last_stem == stem:
                                                continue
                                        else:
                                                last_stem = stem

                                found += 1
                                if found > start_point:
                                        yield result

                def filtered_search(results, mver):
                        try:
                                result = next(results)
                        except StopIteration:
                                return

                        return_type = result[1]
                        results = itertools.chain([result], results)

                        if return_latest and \
                            return_type == qp.Query.RETURN_PACKAGES:
                                def cmp_fmris(resa, resb):
                                        a = resa[2]
                                        b = resb[2]

                                        if a.pkg_name == b.pkg_name:
                                                # Version in descending order.
                                                return misc.cmp(a.version,
                                                    b.version) * -1
                                        return misc.cmp(a, b)
                                return filter_results(sorted(results,
                                    key=cmp_to_key(cmp_fmris)), mver)

                        return filter_results(results, mver)

                if matching_version or return_latest:
                        # Additional filtering needs to be performed and
                        # the results yielded one by one.
                        mver = None
                        if matching_version:
                                mver = version.MatchingVersion(matching_version,
                                    None)

                        # Results should be retrieved here so that an exception
                        # can be immediately raised.
                        query = qp.Query(" ".join(tokens), case_sensitive,
                            return_type, None, None)
                        res_list = self._depot.repo.search([str(query)],
                            pub=self._pub)
                        if not res_list:
                                return

                        return filtered_search(res_list[0], mver)

                query = qp.Query(" ".join(tokens), case_sensitive,
                    return_type, num_to_return, start_point)
                res_list = self._depot.repo.search([str(query)],
                    pub=self._pub)
                if not res_list:
                        return
                return res_list[0]
Example #2
0
def extract_matching_fmris(pkgs,
                           patterns=None,
                           matcher=None,
                           constraint=None,
                           counthash=None,
                           versions=None):
    """Iterate through the given list of PkgFmri objects,
        looking for packages matching 'pattern' in 'patterns', based on the
        function in 'matcher' and the versioning constraint described by
        'constraint'.  If 'matcher' is None, uses fmri subset matching
        as the default.  If 'patterns' is None, 'versions' may be specified,
        and looks for packages matching the patterns specified in 'versions'.
        When using 'version', the 'constraint' parameter is ignored.

        'versions' should be a list of strings of the format:
            release,build_release-branch:datetime 

        ...with a value of '*' provided for any component to be ignored. '*' or
        '?' may be used within each component value and will act as wildcard
        characters ('*' for one or more characters, '?' for a single character).

        Returns a sorted list of PkgFmri objects, newest versions first.  If
        'counthash' is a dictionary, instead store the number of matched fmris
        for each package that matches."""

    if not matcher:
        matcher = fmri.fmri_match

    if patterns is None:
        patterns = []
    elif not isinstance(patterns, list):
        patterns = [patterns]

    if versions is None:
        versions = []
    elif not isinstance(versions, list):
        versions = [version.MatchingVersion(versions, None)]
    else:
        for i, ver in enumerate(versions):
            versions[i] = version.MatchingVersion(ver, None)

    # 'pattern' may be a partially or fully decorated fmri; we want
    # to extract its name and version to match separately against
    # the catalog.
    # XXX "5.11" here needs to be saner
    tuples = {}

    for pattern in patterns:
        if isinstance(pattern, fmri.PkgFmri):
            tuples[pattern] = pattern.tuple()
        else:
            assert pattern != None
            tuples[pattern] = \
                fmri.PkgFmri(pattern, "5.11").tuple()

    def by_pattern(p):
        cat_pub, cat_name, cat_version = p.tuple()
        for pattern in patterns:
            pat_pub, pat_name, pat_version = tuples[pattern]
            if (fmri.is_same_publisher(pat_pub, cat_pub) or not \
                pat_pub) and matcher(cat_name, pat_name):
                if not pat_version or \
                    p.version.is_successor(
                    pat_version, constraint) or \
                    p.version == pat_version:
                    if counthash is not None:
                        if pattern in counthash:
                            counthash[pattern] += 1
                        else:
                            counthash[pattern] = 1

                    if pat_pub:
                        p.set_publisher(pat_pub)
                    return p

    def by_version(p):
        for ver in versions:
            if ver == p.version:
                if counthash is not None:
                    sver = str(ver)
                    if sver in counthash:
                        counthash[sver] += 1
                    else:
                        counthash[sver] = 1
                return p

    ret = []
    if patterns:
        for p in pkgs:
            res = by_pattern(p)
            if res is not None:
                ret.append(res)
    elif versions:
        for p in pkgs:
            res = by_version(p)
            if res is not None:
                ret.append(res)

    return sorted(ret, reverse=True)