aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pym/gentoolkit/equery/has.py220
-rw-r--r--pym/gentoolkit/query.py33
2 files changed, 243 insertions, 10 deletions
diff --git a/pym/gentoolkit/equery/has.py b/pym/gentoolkit/equery/has.py
new file mode 100644
index 0000000..e40a766
--- /dev/null
+++ b/pym/gentoolkit/equery/has.py
@@ -0,0 +1,220 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+#
+# $Header: $
+
+"""List all installed packages that match for a given ENVIRONMENT variable"""
+
+from __future__ import print_function
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+from portage import auxdbkeys
+
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage, CONFIG
+from gentoolkit.package import PackageFormatter, FORMAT_TMPL_VARS
+from gentoolkit.query import Query
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "in_installed": True,
+ "in_porttree": False,
+ "in_overlay": False,
+ "include_masked": True,
+ "show_progress": False,
+ "package_format": None,
+ "package_filter": None,
+ "env_var": None
+}
+
+AUXDBKEYS = set(auxdbkeys)
+AUXDBKEYS.difference_update(['UNUSED_0{0}'.format(x) for x in range(6)])
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print(__doc__.strip())
+ print()
+ print(mod_usage(mod_name="has", arg="env_var [expr]"))
+ print()
+ print(pp.command("options"))
+ print(format_options((
+ (" -h, --help", "display this help message"),
+ (" -I, --exclude-installed",
+ "exclude installed packages from search path"),
+ (" -o, --overlay-tree", "include overlays in search path"),
+ (" -p, --portage-tree", "include entire portage tree in search path"),
+ (" -F, --format=TMPL", "specify a custom output format"),
+ (" TMPL",
+ "a format template using (see man page):")
+ )))
+ print(" " * 24, ', '.join(pp.emph(x) for x in FORMAT_TMPL_VARS))
+ print()
+ print(pp.command("env_var"))
+ print("", ', '.join(pp.emph(x) for x in AUXDBKEYS))
+ print(" other env_vars provided by eclasses may be available")
+
+
+def query_in_env(query, env_var, pkg):
+ """Check if the query is in the pkg's environment."""
+
+ try:
+ if env_var in ("USE", "IUSE"):
+ results = set(
+ [x.lstrip("+-") for x in pkg.environment(env_var).split()]
+ )
+ else:
+ results = set(pkg.environment(env_var).split())
+ except errors.GentoolkitFatalError:
+ # aux_get KeyError or other unexpected result
+ return False
+
+ if query in results:
+ return True
+
+ return False
+
+
+def display_pkg(query, env_var, pkg):
+ """Display information for a given package."""
+
+ if CONFIG['verbose']:
+ pkgstr = PackageFormatter(
+ pkg,
+ do_format=True,
+ custom_format=QUERY_OPTS["package_format"]
+ )
+ else:
+ pkgstr = PackageFormatter(
+ pkg,
+ do_format=False,
+ custom_format=QUERY_OPTS["package_format"]
+ )
+
+ if (QUERY_OPTS["in_installed"] and
+ not QUERY_OPTS["in_porttree"] and
+ not QUERY_OPTS["in_overlay"]):
+ if not 'I' in pkgstr.location:
+ return False
+ if (QUERY_OPTS["in_porttree"] and
+ not QUERY_OPTS["in_overlay"]):
+ if not 'P' in pkgstr.location:
+ return False
+ if (QUERY_OPTS["in_overlay"] and
+ not QUERY_OPTS["in_porttree"]):
+ if not 'O' in pkgstr.location:
+ return False
+ pp.uprint(pkgstr)
+
+ return True
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update QUERY_OPTS"""
+
+ # Parse module options
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-I', '--exclue-installed'):
+ QUERY_OPTS['in_installed'] = False
+ elif opt in ('-p', '--portage-tree'):
+ QUERY_OPTS['in_porttree'] = True
+ elif opt in ('-o', '--overlay-tree'):
+ QUERY_OPTS['in_overlay'] = True
+ elif opt in ('-F', '--format'):
+ QUERY_OPTS["package_format"] = posarg
+ elif opt in ('--package'):
+ QUERY_OPTS["package_filter"] = posarg
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hiIpoF:" # -i was option for default action
+ # --installed is no longer needed, kept for compatibility (djanderson '09)
+ long_opts = ('help', 'installed', 'exclude-installed', 'portage-tree',
+ 'overlay-tree', 'format=', 'package=')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError as err:
+ sys.stderr.write(pp.error("Module %s" % err))
+ print()
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ query_scope = QUERY_OPTS['package_filter'] or '*'
+ matches = Query(query_scope).smart_find(**QUERY_OPTS)
+ matches.sort()
+
+ # split out the first query since it is suppose to be the env_var
+ QUERY_OPTS['env_var'] = queries.pop(0)
+ env_var = QUERY_OPTS['env_var']
+
+ #
+ # Output
+ #
+
+ if not queries:
+ if not QUERY_OPTS['package_filter']:
+ err = "Used ENV_VAR without match_expression or --package"
+ raise errors.GentoolkitFatalError(err, is_serious=False)
+ else:
+ if len(matches) > 1:
+ raise errors.AmbiguousPackageName(matches)
+ for match in matches:
+ env = QUERY_OPTS['env_var']
+ print(match.environment(env))
+
+ first_run = True
+ got_match = False
+ for query in queries:
+ if not first_run:
+ print()
+
+ if CONFIG['verbose']:
+ status = " * Searching for {0} {1} ... "
+ pp.uprint(status.format(env_var, pp.emph(query)))
+
+ for pkg in matches:
+ if query_in_env(query, env_var, pkg):
+ display_pkg(query, env_var, pkg)
+ got_match = True
+ first_run = False
+
+ if not got_match:
+ sys.exit(1)
+
+# vim: set ts=4 sw=4 tw=79:
diff --git a/pym/gentoolkit/query.py b/pym/gentoolkit/query.py
index c18d19e..9ad9017 100644
--- a/pym/gentoolkit/query.py
+++ b/pym/gentoolkit/query.py
@@ -27,6 +27,7 @@ from gentoolkit import CONFIG
from gentoolkit import errors
from gentoolkit import helpers
from gentoolkit import pprinter as pp
+from gentoolkit.atom import Atom
from gentoolkit.cpv import CPV
from gentoolkit.dbapi import PORTDB, VARDB
from gentoolkit.package import Package
@@ -36,7 +37,7 @@ from gentoolkit.sets import get_set_atoms, SETPREFIX
# Classes
# =======
-class Query(object):
+class Query(CPV):
"""Provides common methods on a package query."""
def __init__(self, query, is_regex=False):
@@ -60,6 +61,16 @@ class Query(object):
self.is_regex = is_regex
self.query_type = self._get_query_type()
+ # Name the rest of the chunks, if possible
+ if self.query_type != "set":
+ try:
+ atom = Atom(self.query)
+ self.__dict__.update(atom.__dict__)
+ except errors.GentoolkitInvalidAtom:
+ CPV.__init__(self, self.query)
+ self.operator = ''
+ self.atom = self.cpv
+
def __repr__(self):
rx = ''
if self.is_regex:
@@ -79,8 +90,7 @@ class Query(object):
cat_str = ""
pkg_str = pp.emph(self.query)
else:
- cpv = CPV(self.query)
- cat, pkg = cpv.category, cpv.name + cpv.fullversion
+ cat, pkg = self.category, self.name + self.fullversion
if cat and not self.is_regex:
cat_str = "in %s " % pp.emph(cat.lstrip('><=~!'))
else:
@@ -185,7 +195,9 @@ class Query(object):
if in_installed:
matches.extend(VARDB.match(self.query))
except portage.exception.InvalidAtom as err:
- raise errors.GentoolkitInvalidAtom(str(err))
+ message = "query.py: find(), query=%s, InvalidAtom=%s" %(
+ self.query, str(err))
+ raise errors.GentoolkitInvalidAtom(message)
return [Package(x) for x in set(matches)]
@@ -221,7 +233,9 @@ class Query(object):
try:
best = PORTDB.xmatch("bestmatch-visible", self.query)
except portage.exception.InvalidAtom as err:
- raise errors.GentoolkitInvalidAtom(err)
+ message = "query.py: find_best(), bestmatch-visible, " + \
+ "query=%s, InvalidAtom=%s" %(self.query, str(err))
+ raise errors.GentoolkitInvalidAtom(message)
# xmatch can return an empty string, so checking for None is not enough
if not best:
if not (include_keyworded or include_masked):
@@ -229,7 +243,9 @@ class Query(object):
try:
matches = PORTDB.xmatch("match-all", self.query)
except portage.exception.InvalidAtom as err:
- raise errors.GentoolkitInvalidAtom(err)
+ message = "query.py: find_best(), match-all, query=%s, InvalidAtom=%s" %(
+ self.query, str(err))
+ raise errors.GentoolkitInvalidAtom(message)
masked = portage.best(matches)
keywordable = []
for m in matches:
@@ -302,10 +318,7 @@ class Query(object):
cat_re = cat
else:
cat_re = fnmatch.translate(cat)
- # [::-1] reverses a sequence, so we're emulating an ".rreplace()"
- # except we have to put our "new" string on backwards
- cat_re = cat_re[::-1].replace('$', '*./', 1)[::-1]
- predicate = lambda x: re.match(cat_re, x)
+ predicate = lambda x: re.match(cat_re, x.split("/", 1)[0])
pre_filter = self.package_finder(predicate=predicate)
# Post-filter