blob: 332122fc357ff4d6c6023b3b76b6b18d87306937 [file] [log] [blame]
#!/usr/bin/python -bO
# Copyright 1999-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from __future__ import print_function, unicode_literals
import signal
import sys
# This block ensures that ^C interrupts are handled quietly.
try:
def exithandler(signum, _frame):
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
sys.exit(128 + signum)
signal.signal(signal.SIGINT, exithandler)
signal.signal(signal.SIGTERM, exithandler)
except KeyboardInterrupt:
sys.exit(128 + signal.SIGINT)
import os
import types
# Avoid sandbox violations after python upgrade.
pym_path = os.path.join(os.path.dirname(
os.path.dirname(os.path.realpath(__file__))), "pym")
if os.environ.get("SANDBOX_ON") == "1":
sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
if pym_path not in sandbox_write:
sandbox_write.append(pym_path)
os.environ["SANDBOX_WRITE"] = \
":".join(filter(None, sandbox_write))
del sandbox_write
sys.path.insert(0, pym_path)
import portage
portage._internal_caller = True
from portage import os
from portage.eapi import eapi_has_repo_deps
from portage.util import writemsg, writemsg_stdout
from portage.util._argparse import ArgumentParser
portage.proxy.lazyimport.lazyimport(globals(),
're',
'subprocess',
'_emerge.Package:Package',
'_emerge.RootConfig:RootConfig',
'_emerge.is_valid_package_atom:insert_category_into_atom',
'portage.dbapi._expand_new_virt:expand_new_virt',
'portage._sets.base:InternalPackageSet',
'portage.xml.metadata:MetaDataXML'
)
def eval_atom_use(atom):
if 'USE' in os.environ:
use = frozenset(os.environ['USE'].split())
atom = atom.evaluate_conditionals(use)
return atom
def uses_eroot(function):
function.uses_eroot = True
return function
#-----------------------------------------------------------------------------
#
# To add functionality to this tool, add a function below.
#
# The format for functions is:
#
# def function(argv):
# """<list of options for this function>
# <description of the function>
# """
# <code>
#
# "argv" is an array of the command line parameters provided after the command.
#
# Make sure you document the function in the right format. The documentation
# is used to display help on the function.
#
# You do not need to add the function to any lists, this tool is introspective,
# and will automaticly add a command by the same name as the function!
#
@uses_eroot
def has_version(argv):
"""<eroot> <category/package>
Return code 0 if it's available, 1 otherwise.
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
return 3
warnings = []
allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
try:
atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
except portage.exception.InvalidAtom:
if atom_validate_strict:
portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
noiselevel=-1)
return 2
else:
atom = argv[1]
else:
if atom_validate_strict:
try:
atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
except portage.exception.InvalidAtom as e:
warnings.append("QA Notice: %s: %s" % ('has_version', e))
atom = eval_atom_use(atom)
if warnings:
elog('eqawarn', warnings)
try:
mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
if mylist:
return 0
else:
return 1
except KeyError:
return 1
except portage.exception.InvalidAtom:
portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
noiselevel=-1)
return 2
@uses_eroot
def best_version(argv):
"""<eroot> <category/package>
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
return 3
warnings = []
allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
try:
atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
except portage.exception.InvalidAtom:
if atom_validate_strict:
portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
noiselevel=-1)
return 2
else:
atom = argv[1]
else:
if atom_validate_strict:
try:
atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
except portage.exception.InvalidAtom as e:
warnings.append("QA Notice: %s: %s" % ('best_version', e))
atom = eval_atom_use(atom)
if warnings:
elog('eqawarn', warnings)
try:
mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
print(portage.best(mylist))
except KeyError:
return 1
@uses_eroot
def mass_best_version(argv):
"""<eroot> [<category/package>]+
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
return 2
try:
for pack in argv[1:]:
mylist = portage.db[argv[0]]['vartree'].dbapi.match(pack)
print('%s:%s' % (pack, portage.best(mylist)))
except KeyError:
return 1
@uses_eroot
def metadata(argv):
if (len(argv) < 4):
print('ERROR: insufficient parameters!', file=sys.stderr)
return 2
eroot, pkgtype, pkgspec = argv[0:3]
metakeys = argv[3:]
type_map = {
'ebuild': 'porttree',
'binary': 'bintree',
'installed': 'vartree'
}
if pkgtype not in type_map:
print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
return 1
trees = portage.db
repo = portage.dep.dep_getrepo(pkgspec)
pkgspec = portage.dep.remove_slot(pkgspec)
try:
values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
pkgspec, metakeys, myrepo=repo)
writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
except KeyError:
print("Package not found: '%s'" % pkgspec, file=sys.stderr)
return 1
metadata.__doc__ = """
<eroot> <pkgtype> <category/package> [<key>]+
Returns metadata values for the specified package.
Available keys: %s
""" % ','.join(sorted(x for x in portage.auxdbkeys \
if not x.startswith('UNUSED_')))
@uses_eroot
def contents(argv):
"""<eroot> <category/package>
List the files that are installed for a given package, with
one file listed on each line. All file names will begin with
<eroot>.
"""
if len(argv) != 2:
print("ERROR: expected 2 parameters, got %d!" % len(argv))
return 2
root, cpv = argv
vartree = portage.db[root]["vartree"]
if not vartree.dbapi.cpv_exists(cpv):
sys.stderr.write("Package not found: '%s'\n" % cpv)
return 1
cat, pkg = portage.catsplit(cpv)
db = portage.dblink(cat, pkg, root, vartree.settings,
treetype="vartree", vartree=vartree)
writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
noiselevel=-1)
@uses_eroot
def owners(argv):
"""<eroot> [<filename>]+
Given a list of files, print the packages that own the files and which
files belong to each package. Files owned by a package are listed on
the lines below it, indented by a single tab character (\\t). All file
paths must either start with <eroot> or be a basename alone.
Returns 1 if no owners could be found, and 0 otherwise.
"""
if len(argv) < 2:
sys.stderr.write("ERROR: insufficient parameters!\n")
sys.stderr.flush()
return 2
eroot = argv[0]
vardb = portage.db[eroot]["vartree"].dbapi
root = portage.settings['ROOT']
cwd = None
try:
cwd = os.getcwd()
except OSError:
pass
files = []
orphan_abs_paths = set()
orphan_basenames = set()
for f in argv[1:]:
f = portage.normalize_path(f)
is_basename = os.sep not in f
if not is_basename and f[:1] != os.sep:
if cwd is None:
sys.stderr.write("ERROR: cwd does not exist!\n")
sys.stderr.flush()
return 2
f = os.path.join(cwd, f)
f = portage.normalize_path(f)
if not is_basename and not f.startswith(eroot):
sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
sys.stderr.flush()
return 2
if is_basename:
files.append(f)
orphan_basenames.add(f)
else:
files.append(f[len(root)-1:])
orphan_abs_paths.add(f)
owners = vardb._owners.get_owners(files)
msg = []
for pkg, owned_files in owners.items():
cpv = pkg.mycpv
msg.append("%s\n" % cpv)
for f in sorted(owned_files):
f_abs = os.path.join(root, f.lstrip(os.path.sep))
msg.append("\t%s\n" % (f_abs,))
orphan_abs_paths.discard(f_abs)
if orphan_basenames:
orphan_basenames.discard(os.path.basename(f_abs))
writemsg_stdout(''.join(msg), noiselevel=-1)
if orphan_abs_paths or orphan_basenames:
orphans = []
orphans.extend(orphan_abs_paths)
orphans.extend(orphan_basenames)
orphans.sort()
msg = []
msg.append("None of the installed packages claim these files:\n")
for f in orphans:
msg.append("\t%s\n" % (f,))
sys.stderr.write("".join(msg))
sys.stderr.flush()
if owners:
return 0
return 1
@uses_eroot
def is_protected(argv):
"""<eroot> <filename>
Given a single filename, return code 0 if it's protected, 1 otherwise.
The filename must begin with <eroot>.
"""
if len(argv) != 2:
sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
sys.stderr.flush()
return 2
root, filename = argv
err = sys.stderr
cwd = None
try:
cwd = os.getcwd()
except OSError:
pass
f = portage.normalize_path(filename)
if not f.startswith(os.path.sep):
if cwd is None:
err.write("ERROR: cwd does not exist!\n")
err.flush()
return 2
f = os.path.join(cwd, f)
f = portage.normalize_path(f)
if not f.startswith(root):
err.write("ERROR: file paths must begin with <eroot>!\n")
err.flush()
return 2
from portage.util import ConfigProtect
settings = portage.settings
protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
protect_mask = portage.util.shlex_split(
settings.get("CONFIG_PROTECT_MASK", ""))
protect_obj = ConfigProtect(root, protect, protect_mask)
if protect_obj.isprotected(f):
return 0
return 1
@uses_eroot
def filter_protected(argv):
"""<eroot>
Read filenames from stdin and write them to stdout if they are protected.
All filenames are delimited by \\n and must begin with <eroot>.
"""
if len(argv) != 1:
sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
sys.stderr.flush()
return 2
root, = argv
out = sys.stdout
err = sys.stderr
cwd = None
try:
cwd = os.getcwd()
except OSError:
pass
from portage.util import ConfigProtect
settings = portage.settings
protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
protect_mask = portage.util.shlex_split(
settings.get("CONFIG_PROTECT_MASK", ""))
protect_obj = ConfigProtect(root, protect, protect_mask)
errors = 0
for line in sys.stdin:
filename = line.rstrip("\n")
f = portage.normalize_path(filename)
if not f.startswith(os.path.sep):
if cwd is None:
err.write("ERROR: cwd does not exist!\n")
err.flush()
errors += 1
continue
f = os.path.join(cwd, f)
f = portage.normalize_path(f)
if not f.startswith(root):
err.write("ERROR: file paths must begin with <eroot>!\n")
err.flush()
errors += 1
continue
if protect_obj.isprotected(f):
out.write("%s\n" % filename)
out.flush()
if errors:
return 2
return 0
@uses_eroot
def best_visible(argv):
"""<eroot> [pkgtype] <atom>
Returns category/package-version (without .ebuild).
The pkgtype argument defaults to "ebuild" if unspecified,
otherwise it must be one of ebuild, binary, or installed.
"""
if (len(argv) < 2):
writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
return 2
pkgtype = "ebuild"
if len(argv) > 2:
pkgtype = argv[1]
atom = argv[2]
else:
atom = argv[1]
type_map = {
"ebuild":"porttree",
"binary":"bintree",
"installed":"vartree"}
if pkgtype not in type_map:
writemsg("Unrecognized package type: '%s'\n" % pkgtype,
noiselevel=-1)
return 2
eroot = argv[0]
db = portage.db[eroot][type_map[pkgtype]].dbapi
try:
atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
except portage.exception.InvalidAtom:
writemsg("ERROR: Invalid atom: '%s'\n" % atom,
noiselevel=-1)
return 2
root_config = RootConfig(portage.settings, portage.db[eroot], None)
if hasattr(db, "xmatch"):
cpv_list = db.xmatch("match-all-cpv-only", atom)
else:
cpv_list = db.match(atom)
if cpv_list:
# reversed, for descending order
cpv_list.reverse()
# verify match, since the atom may match the package
# for a given cpv from one repo but not another, and
# we can use match-all-cpv-only to avoid redundant
# metadata access.
atom_set = InternalPackageSet(initial_atoms=(atom,))
if atom.repo is None and hasattr(db, "getRepositories"):
repo_list = db.getRepositories()
else:
repo_list = [atom.repo]
for cpv in cpv_list:
for repo in repo_list:
try:
metadata = dict(zip(Package.metadata_keys,
db.aux_get(cpv, Package.metadata_keys, myrepo=repo)))
except KeyError:
continue
pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
installed=(pkgtype=="installed"), metadata=metadata,
root_config=root_config, type_name=pkgtype)
if not atom_set.findAtomForPackage(pkg):
continue
if pkg.visible:
writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
return os.EX_OK
# No package found, write out an empty line.
writemsg_stdout("\n", noiselevel=-1)
return 1
@uses_eroot
def mass_best_visible(argv):
"""<eroot> [<type>] [<category/package>]+
Returns category/package-version (without .ebuild).
The pkgtype argument defaults to "ebuild" if unspecified,
otherwise it must be one of ebuild, binary, or installed.
"""
type_map = {
"ebuild":"porttree",
"binary":"bintree",
"installed":"vartree"}
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
return 2
try:
root = argv.pop(0)
pkgtype = "ebuild"
if argv[0] in type_map:
pkgtype = argv.pop(0)
for pack in argv:
writemsg_stdout("%s:" % pack, noiselevel=-1)
best_visible([root, pkgtype, pack])
except KeyError:
return 1
@uses_eroot
def all_best_visible(argv):
"""<eroot>
Returns all best_visible packages (without .ebuild).
"""
if len(argv) < 1:
sys.stderr.write("ERROR: insufficient parameters!\n")
sys.stderr.flush()
return 2
#print portage.db[argv[0]]["porttree"].dbapi.cp_all()
for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
if mybest:
print(mybest)
@uses_eroot
def match(argv):
"""<eroot> <atom>
Returns a \\n separated list of category/package-version.
When given an empty string, all installed packages will
be listed.
"""
if len(argv) != 2:
print("ERROR: expected 2 parameters, got %d!" % len(argv))
return 2
root, atom = argv
if not atom:
atom = "*/*"
vardb = portage.db[root]["vartree"].dbapi
try:
atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
except portage.exception.InvalidAtom:
# maybe it's valid but missing category
atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
if atom.extended_syntax:
if atom == "*/*":
results = vardb.cpv_all()
else:
results = []
require_metadata = atom.slot or atom.repo
for cpv in vardb.cpv_all():
if not portage.match_from_list(atom, [cpv]):
continue
if require_metadata:
try:
cpv = vardb._pkg_str(cpv, atom.repo)
except (KeyError, portage.exception.InvalidData):
continue
if not portage.match_from_list(atom, [cpv]):
continue
results.append(cpv)
results.sort()
else:
results = vardb.match(atom)
for cpv in results:
print(cpv)
@uses_eroot
def expand_virtual(argv):
"""<eroot> <atom>
Returns a \\n separated list of atoms expanded from a
given virtual atom (GLEP 37 virtuals only),
excluding blocker atoms. Satisfied
virtual atoms are not included in the output, since
they are expanded to real atoms which are displayed.
Unsatisfied virtual atoms are displayed without
any expansion. The "match" command can be used to
resolve the returned atoms to specific installed
packages.
"""
if len(argv) != 2:
writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
noiselevel=-1)
return 2
root, atom = argv
try:
results = list(expand_new_virt(
portage.db[root]["vartree"].dbapi, atom))
except portage.exception.InvalidAtom:
writemsg("ERROR: Invalid atom: '%s'\n" % atom,
noiselevel=-1)
return 2
results.sort()
for x in results:
if not x.blocker:
writemsg_stdout("%s\n" % (x,))
return os.EX_OK
def vdb_path(_argv):
"""
Returns the path used for the var(installed) package database for the
set environment/configuration options.
"""
out = sys.stdout
out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
out.flush()
return os.EX_OK
def gentoo_mirrors(_argv):
"""
Returns the mirrors set to use in the portage configuration.
"""
print(portage.settings["GENTOO_MIRRORS"])
@uses_eroot
def repositories_configuration(argv):
"""<eroot>
Returns the configuration of repositories.
"""
if len(argv) < 1:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
sys.stdout.write(portage.db[argv[0]]["vartree"].settings.repositories.config_string())
sys.stdout.flush()
@uses_eroot
def repos_config(argv):
"""
<eroot>
This is an alias for the repositories_configuration command.
"""
return repositories_configuration(argv)
def portdir(_argv):
"""
Returns the PORTDIR path.
Deprecated in favor of repositories_configuration command.
"""
print("WARNING: 'portageq portdir' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr)
print(portage.settings["PORTDIR"])
def config_protect(_argv):
"""
Returns the CONFIG_PROTECT paths.
"""
print(portage.settings["CONFIG_PROTECT"])
def config_protect_mask(_argv):
"""
Returns the CONFIG_PROTECT_MASK paths.
"""
print(portage.settings["CONFIG_PROTECT_MASK"])
def portdir_overlay(_argv):
"""
Returns the PORTDIR_OVERLAY path.
Deprecated in favor of repositories_configuration command.
"""
print("WARNING: 'portageq portdir_overlay' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr)
print(portage.settings["PORTDIR_OVERLAY"])
def pkgdir(_argv):
"""
Returns the PKGDIR path.
"""
print(portage.settings["PKGDIR"])
def distdir(_argv):
"""
Returns the DISTDIR path.
"""
print(portage.settings["DISTDIR"])
def colormap(_argv):
"""
Display the color.map as environment variables.
"""
print(portage.output.colormap())
def envvar(argv):
"""<variable>+
Returns a specific environment variable as exists prior to ebuild.sh.
Similar to: emerge --verbose --info | egrep '^<variable>='
"""
verbose = "-v" in argv
if verbose:
argv.pop(argv.index("-v"))
if len(argv) == 0:
print("ERROR: insufficient parameters!")
return 2
for arg in argv:
if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"):
print("WARNING: 'portageq envvar %s' is deprecated. Use 'portageq repositories_configuration' instead." % arg, file=sys.stderr)
if verbose:
print(arg + "=" + portage._shell_quote(portage.settings[arg]))
else:
print(portage.settings[arg])
@uses_eroot
def get_repos(argv):
"""<eroot>
Returns all repos with names (repo_name file) argv[0] = $EROOT
"""
if len(argv) < 1:
print("ERROR: insufficient parameters!")
return 2
print(" ".join(reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order)))
@uses_eroot
def master_repositories(argv):
"""<eroot> <repo_id>+
Returns space-separated list of master repositories for specified repository.
"""
if len(argv) < 2:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
for arg in argv[1:]:
if portage.dep._repo_name_re.match(arg) is None:
print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
return 2
try:
repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
except KeyError:
print("")
return 1
else:
print(" ".join(x.name for x in repo.masters))
@uses_eroot
def master_repos(argv):
"""<eroot> <repo_id>+
This is an alias for the master_repositories command.
"""
return master_repositories(argv)
@uses_eroot
def get_repo_path(argv):
"""<eroot> <repo_id>+
Returns the path to the repo named argv[1], argv[0] = $EROOT
"""
if len(argv) < 2:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
for arg in argv[1:]:
if portage.dep._repo_name_re.match(arg) is None:
print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
return 2
path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
if path is None:
print("")
return 1
print(path)
@uses_eroot
def available_eclasses(argv):
"""<eroot> <repo_id>+
Returns space-separated list of available eclasses for specified repository.
"""
if len(argv) < 2:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
for arg in argv[1:]:
if portage.dep._repo_name_re.match(arg) is None:
print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
return 2
try:
repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
except KeyError:
print("")
return 1
else:
print(" ".join(sorted(repo.eclass_db.eclasses)))
@uses_eroot
def eclass_path(argv):
"""<eroot> <repo_id> <eclass>+
Returns the path to specified eclass for specified repository.
"""
if len(argv) < 3:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
if portage.dep._repo_name_re.match(argv[1]) is None:
print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
return 2
try:
repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
except KeyError:
print("")
return 1
else:
retval = 0
for arg in argv[2:]:
try:
eclass = repo.eclass_db.eclasses[arg]
except KeyError:
print("")
retval = 1
else:
print(eclass.location)
return retval
@uses_eroot
def license_path(argv):
"""<eroot> <repo_id> <license>+
Returns the path to specified license for specified repository.
"""
if len(argv) < 3:
print("ERROR: insufficient parameters!", file=sys.stderr)
return 3
if portage.dep._repo_name_re.match(argv[1]) is None:
print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
return 2
try:
repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
except KeyError:
print("")
return 1
else:
retval = 0
for arg in argv[2:]:
eclass_path = ""
paths = reversed([os.path.join(x.location, 'licenses', arg) for x in list(repo.masters) + [repo]])
for path in paths:
if os.path.exists(path):
eclass_path = path
break
if eclass_path == "":
retval = 1
print(eclass_path)
return retval
@uses_eroot
def list_preserved_libs(argv):
"""<eroot>
Print a list of libraries preserved during a package update in the form
package: path. Returns 1 if no preserved libraries could be found,
0 otherwise.
"""
if len(argv) != 1:
print("ERROR: wrong number of arguments")
return 2
mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
rValue = 1
msg = []
for cpv in sorted(mylibs):
msg.append(cpv)
for path in mylibs[cpv]:
msg.append(' ' + path)
rValue = 0
msg.append('\n')
writemsg_stdout(''.join(msg), noiselevel=-1)
return rValue
class MaintainerEmailMatcher(object):
def __init__(self, maintainer_emails):
self._re = re.compile("^(%s)$" % "|".join(maintainer_emails))
def __call__(self, metadata_xml):
match = False
matcher = self._re.match
for x in metadata_xml.maintainers():
if x.email is not None and matcher(x.email) is not None:
match = True
break
return match
class HerdMatcher(object):
def __init__(self, herds):
self._herds = frozenset(herds)
def __call__(self, metadata_xml):
herds = self._herds
return any(x in herds for x in metadata_xml.herds())
def pquery(parser, opts, args):
"""[options] [atom]+
Emulates a subset of Pkgcore's pquery tool.
"""
portdb = portage.db[portage.root]['porttree'].dbapi
root_config = RootConfig(portdb.settings,
portage.db[portage.root], None)
def _pkg(cpv, repo_name):
try:
metadata = dict(zip(
Package.metadata_keys,
portdb.aux_get(cpv,
Package.metadata_keys,
myrepo=repo_name)))
except KeyError:
raise portage.exception.PackageNotFound(cpv)
return Package(built=False, cpv=cpv,
installed=False, metadata=metadata,
root_config=root_config,
type_name="ebuild")
need_metadata = False
atoms = []
for arg in args:
if "/" not in arg.split(":")[0]:
atom = insert_category_into_atom(arg, '*')
if atom is None:
writemsg("ERROR: Invalid atom: '%s'\n" % arg,
noiselevel=-1)
return 2
else:
atom = arg
try:
atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
except portage.exception.InvalidAtom:
writemsg("ERROR: Invalid atom: '%s'\n" % arg,
noiselevel=-1)
return 2
if atom.slot is not None:
need_metadata = True
atoms.append(atom)
if "*/*" in atoms:
del atoms[:]
need_metadata = False
if not opts.no_filters:
need_metadata = True
xml_matchers = []
if opts.maintainer_email:
maintainer_emails = []
for x in opts.maintainer_email:
maintainer_emails.extend(x.split(","))
xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
if opts.herd is not None:
herds = []
for x in opts.herd:
herds.extend(x.split(","))
xml_matchers.append(HerdMatcher(herds))
repos = []
if opts.all_repos:
repos.extend(portdb.repositories.get_repo_for_location(location)
for location in portdb.porttrees)
elif opts.repo is not None:
repos.append(portdb.repositories[opts.repo])
else:
repos.append(portdb.repositories.mainRepo())
if not atoms:
names = None
categories = list(portdb.categories)
else:
category_wildcard = False
name_wildcard = False
categories = []
names = []
for atom in atoms:
category, name = portage.catsplit(atom.cp)
categories.append(category)
names.append(name)
if "*" in category:
category_wildcard = True
if "*" in name:
name_wildcard = True
if category_wildcard:
categories = list(portdb.categories)
else:
categories = list(set(categories))
if name_wildcard:
names = None
else:
names = sorted(set(names))
no_version = opts.no_version
categories.sort()
for category in categories:
if names is None:
cp_list = portdb.cp_all(categories=(category,))
else:
cp_list = [category + "/" + name for name in names]
for cp in cp_list:
matches = []
for repo in repos:
match = True
if xml_matchers:
metadata_xml_path = os.path.join(
repo.location, cp, 'metadata.xml')
try:
metadata_xml = MetaDataXML(metadata_xml_path, None)
except (EnvironmentError, SyntaxError):
match = False
else:
for matcher in xml_matchers:
if not matcher(metadata_xml):
match = False
break
if not match:
continue
cpv_list = portdb.cp_list(cp, mytree=[repo.location])
if atoms:
for cpv in cpv_list:
pkg = None
for atom in atoms:
if atom.repo is not None and \
atom.repo != repo.name:
continue
if not portage.match_from_list(atom, [cpv]):
continue
if need_metadata:
if pkg is None:
try:
pkg = _pkg(cpv, repo.name)
except portage.exception.PackageNotFound:
continue
if not (opts.no_filters or pkg.visible):
continue
if not portage.match_from_list(atom, [pkg]):
continue
matches.append(cpv)
break
if no_version and matches:
break
elif opts.no_filters:
matches.extend(cpv_list)
else:
for cpv in cpv_list:
try:
pkg = _pkg(cpv, repo.name)
except portage.exception.PackageNotFound:
continue
else:
if pkg.visible:
matches.append(cpv)
if no_version:
break
if no_version and matches:
break
if not matches:
continue
if no_version:
writemsg_stdout("%s\n" % (cp,), noiselevel=-1)
else:
matches = list(set(matches))
portdb._cpv_sort_ascending(matches)
for cpv in matches:
writemsg_stdout("%s\n" % (cpv,), noiselevel=-1)
return os.EX_OK
def use_reduce(argv):
"""<depend_string>
Reduce a dependency string possibly containing use conditionals.
"""
if len(argv) != 1:
print("ERROR: wrong number of arguments")
return 2
from portage.dep import use_reduce as use_internal
print(' '.join(use_internal(argv[0], uselist=os.environ['USE'].split(' '))))
#-----------------------------------------------------------------------------
#
# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
#
non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'main', 'usage', 'uses_eroot'])
commands = sorted(k for k, v in globals().items() \
if k not in non_commands and isinstance(v, types.FunctionType) and v.__module__ == "__main__")
def add_pquery_arguments(parser):
pquery_option_groups = (
(
'Repository matching options',
(
{
"longopt": "--no-filters",
"action": "store_true",
"help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)"
},
{
"longopt": "--repo",
"help": "repo to use (default is PORTDIR if omitted)"
},
{
"longopt": "--all-repos",
"help": "search all repos"
}
)
),
(
'Package matching options',
(
{
"longopt": "--herd",
"action": "append",
"help": "exact match on a herd"
},
{
"longopt": "--maintainer-email",
"action": "append",
"help": "comma-separated list of maintainer email regexes to search for"
}
)
),
(
'Output formatting',
(
{
"shortopt": "-n",
"longopt": "--no-version",
"action": "store_true",
"help": "collapse multiple matching versions together"
},
)
),
)
for group_title, opt_data in pquery_option_groups:
arg_group = parser.add_argument_group(group_title)
for opt_info in opt_data:
pargs = []
try:
pargs.append(opt_info["shortopt"])
except KeyError:
pass
try:
pargs.append(opt_info["longopt"])
except KeyError:
pass
kwargs = {}
try:
kwargs["action"] = opt_info["action"]
except KeyError:
pass
try:
kwargs["help"] = opt_info["help"]
except KeyError:
pass
arg_group.add_argument(*pargs, **portage._native_kwargs(kwargs))
def usage(argv):
print(">>> Portage information query tool")
print(">>> %s" % portage.VERSION)
print(">>> Usage: portageq <command> [<option> ...]")
print("")
print("Available commands:")
#
# Show our commands -- we do this by scanning the functions in this
# file, and formatting each functions documentation.
#
help_mode = '--help' in argv
for name in commands:
# Drop non-functions
obj = globals()[name]
doc = obj.__doc__
if (doc == None):
print(" " + name)
print(" MISSING DOCUMENTATION!")
print("")
continue
lines = doc.lstrip("\n").split("\n")
print(" " + name + " " + lines[0].strip())
if len(argv) > 1:
if (not help_mode):
lines = lines[:-1]
for line in lines[1:]:
print(" " + line.strip())
print()
print('Pkgcore pquery compatible options:')
print()
parser = ArgumentParser(add_help=False,
usage='portageq pquery [options] [atom ...]')
add_pquery_arguments(parser)
parser.print_help()
if len(argv) == 1:
print("\nRun portageq with --help for info")
atom_validate_strict = "EBUILD_PHASE" in os.environ
eapi = None
if atom_validate_strict:
eapi = os.environ.get('EAPI')
def elog(elog_funcname, lines):
cmd = "source '%s/isolated-functions.sh' ; " % \
os.environ["PORTAGE_BIN_PATH"]
for line in lines:
cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
else:
def elog(elog_funcname, lines):
pass
def main(argv):
argv = portage._decode_argv(argv)
nocolor = os.environ.get('NOCOLOR')
if nocolor in ('yes', 'true'):
portage.output.nocolor()
parser = ArgumentParser(add_help=False)
# used by envvar
parser.add_argument("-v", dest="verbose", action="store_true")
actions = parser.add_argument_group('Actions')
actions.add_argument("-h", "--help", action="store_true")
actions.add_argument("--version", action="store_true")
add_pquery_arguments(parser)
opts, args = parser.parse_known_args(argv[1:])
if opts.help:
usage(argv)
return os.EX_OK
elif opts.version:
print("Portage", portage.VERSION)
return os.EX_OK
cmd = None
if args and args[0] in commands:
cmd = args[0]
if cmd == 'pquery':
cmd = None
args = args[1:]
if cmd is None:
return pquery(parser, opts, args)
if opts.verbose:
# used by envvar
args.append("-v")
argv = argv[:1] + args
if len(argv) < 2:
usage(argv)
sys.exit(os.EX_USAGE)
function = globals()[cmd]
uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
if uses_eroot:
if not os.path.isdir(argv[2]):
sys.stderr.write("Not a directory: '%s'\n" % argv[2])
sys.stderr.write("Run portageq with --help for info\n")
sys.stderr.flush()
sys.exit(os.EX_USAGE)
eprefix = portage.settings["EPREFIX"]
eroot = portage.util.normalize_path(argv[2])
if eprefix:
if not eroot.endswith(eprefix):
sys.stderr.write("ERROR: This version of portageq"
" only supports <eroot>s ending in"
" '%s'. The provided <eroot>, '%s',"
" doesn't.\n" % (eprefix, eroot))
sys.stderr.flush()
sys.exit(os.EX_USAGE)
root = eroot[:1 - len(eprefix)]
else:
root = eroot
os.environ["ROOT"] = root
args = argv[2:]
try:
if uses_eroot:
args[0] = portage.settings['EROOT']
retval = function(args)
if retval:
sys.exit(retval)
except portage.exception.PermissionDenied as e:
sys.stderr.write("Permission denied: '%s'\n" % str(e))
sys.exit(e.errno)
except portage.exception.ParseError as e:
sys.stderr.write("%s\n" % str(e))
sys.exit(1)
except portage.exception.AmbiguousPackageName as e:
# Multiple matches thrown from cpv_expand
pkgs = e.args[0]
# An error has occurred so we writemsg to stderr and exit nonzero.
portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
for pkg in pkgs:
portage.writemsg("* %s\n" % pkg, noiselevel=-1)
portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
sys.exit(1)
if __name__ == '__main__':
sys.exit(main(sys.argv))
#-----------------------------------------------------------------------------