-#!/usr/bin/python -O
-# Copyright 1999-2006 Gentoo Foundation
+#!/usr/bin/python -bbO
+# Copyright 1999-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-# $Id$
+from __future__ import print_function, unicode_literals
+
+import signal
import sys
# This block ensures that ^C interrupts are handled quietly.
try:
- import signal
- def exithandler(signum, frame):
+ def exithandler(signum, _frame):
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
- sys.exit(1)
+ sys.exit(128 + signum)
signal.signal(signal.SIGINT, exithandler)
signal.signal(signal.SIGTERM, exithandler)
except KeyboardInterrupt:
- sys.exit(1)
+ 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.
# and will automaticly add a command by the same name as the function!
#
+@uses_eroot
def has_version(argv):
- """<root> <category/package>
+ """<eroot> <category/package>
Return code 0 if it's available, 1 otherwise.
"""
if (len(argv) < 2):
- print "ERROR: insufficient parameters!"
- sys.exit(2)
- if atom_validate_strict and not portage.isvalidatom(argv[1]):
- portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
- noiselevel=-1)
- return 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(argv[1])
+ mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
if mylist:
- sys.exit(0)
+ return 0
else:
- sys.exit(1)
+ return 1
except KeyError:
- sys.exit(1)
-has_version.uses_root = True
+ 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):
- """<root> <category/package>
+ """<eroot> <category/package>
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
- print "ERROR: insufficient parameters!"
- sys.exit(2)
- if atom_validate_strict and not portage.isvalidatom(argv[1]):
- portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
- noiselevel=-1)
- return 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(argv[1])
- print portage.best(mylist)
+ mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
+ print(portage.best(mylist))
except KeyError:
- sys.exit(1)
-best_version.uses_root = True
+ return 1
+@uses_eroot
def mass_best_version(argv):
- """<root> [<category/package>]+
+ """<eroot> [<category/package>]+
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
- print "ERROR: insufficient parameters!"
- sys.exit(2)
+ print("ERROR: insufficient parameters!")
+ return 2
try:
for pack in argv[1:]:
- mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
- print pack+":"+portage.best(mylist)
+ mylist = portage.db[argv[0]]['vartree'].dbapi.match(pack)
+ print('%s:%s' % (pack, portage.best(mylist)))
except KeyError:
- sys.exit(1)
-mass_best_version.uses_root = True
+ return 1
+
+@uses_eroot
def metadata(argv):
- """<root> <pkgtype> <category/package> [<key>]+
- Returns metadata values for the specified package.
- """
if (len(argv) < 4):
- print >> sys.stderr, "ERROR: insufficient parameters!"
- sys.exit(2)
+ print('ERROR: insufficient parameters!', file=sys.stderr)
+ return 2
- root, pkgtype, pkgspec = argv[0:3]
+ eroot, pkgtype, pkgspec = argv[0:3]
metakeys = argv[3:]
type_map = {
- "ebuild":"porttree",
- "binary":"bintree",
- "installed":"vartree"}
+ 'ebuild': 'porttree',
+ 'binary': 'bintree',
+ 'installed': 'vartree'
+ }
if pkgtype not in type_map:
- print >> sys.stderr, "Unrecognized package type: '%s'" % pkgtype
- sys.exit(1)
+ print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
+ return 1
trees = portage.db
- if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
- root = portage.settings["ROOT"] # contains the normalized $ROOT
+ repo = portage.dep.dep_getrepo(pkgspec)
+ pkgspec = portage.dep.remove_slot(pkgspec)
try:
- values = trees[root][type_map[pkgtype]].dbapi.aux_get(
- pkgspec, metakeys)
- for value in values:
- print value
+ 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 >> sys.stderr, "Package not found: '%s'" % pkgspec
- sys.exit(1)
+ 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_')))
-metadata.uses_root = True
+@uses_eroot
def contents(argv):
- """<root> <category/package>
+ """<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
- <root>.
+ <eroot>.
"""
if len(argv) != 2:
- print "ERROR: expected 2 parameters, got %d!" % len(argv)
+ print("ERROR: expected 2 parameters, got %d!" % len(argv))
return 2
root, cpv = argv
cat, pkg = portage.catsplit(cpv)
db = portage.dblink(cat, pkg, root, vartree.settings,
treetype="vartree", vartree=vartree)
- file_list = db.getcontents().keys()
- file_list.sort()
- for f in file_list:
- sys.stdout.write("%s\n" % f)
- sys.stdout.flush()
-contents.uses_root = True
+ writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
+ noiselevel=-1)
+
+@uses_eroot
def owners(argv):
- """<root> [<filename>]+
+ """<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 start with <root>. Returns 1 if no owners could be found,
- and 0 otherwise.
+ 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
- from portage import catsplit, dblink
- settings = portage.settings
- root = settings["ROOT"]
- vardb = portage.db[root]["vartree"].dbapi
+ eroot = argv[0]
+ vardb = portage.db[eroot]["vartree"].dbapi
+ root = portage.settings['ROOT']
cwd = None
try:
pass
files = []
+ orphan_abs_paths = set()
+ orphan_basenames = set()
for f in argv[1:]:
f = portage.normalize_path(f)
- if not f.startswith(os.path.sep):
+ 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 f.startswith(root):
- sys.stderr.write("ERROR: file paths must begin with <root>!\n")
+ 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
- files.append(f[len(root):])
+ 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)
- for pkg, owned_files in owners.iteritems():
+ msg = []
+ for pkg, owned_files in owners.items():
cpv = pkg.mycpv
- sys.stdout.write("%s\n" % cpv)
+ msg.append("%s\n" % cpv)
for f in sorted(owned_files):
- sys.stdout.write("\t%s\n" % \
- os.path.join(root, f.lstrip(os.path.sep)))
+ 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:
- sys.stdout.flush()
return 0
-
- sys.stderr.write("None of the installed packages claim the file(s).\n")
- sys.stderr.flush()
return 1
-owners.uses_root = True
+@uses_eroot
def is_protected(argv):
- """<root> <filename>
+ """<eroot> <filename>
Given a single filename, return code 0 if it's protected, 1 otherwise.
- The filename must begin with <root>.
+ The filename must begin with <eroot>.
"""
if len(argv) != 2:
- sys.stderr.write("ERROR: expeced 2 parameters, got %d!\n" % len(argv))
+ sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
sys.stderr.flush()
return 2
f = portage.normalize_path(f)
if not f.startswith(root):
- err.write("ERROR: file paths must begin with <root>!\n")
+ err.write("ERROR: file paths must begin with <eroot>!\n")
err.flush()
return 2
- import shlex
from portage.util import ConfigProtect
settings = portage.settings
- protect = shlex.split(settings.get("CONFIG_PROTECT", ""))
- protect_mask = shlex.split(settings.get("CONFIG_PROTECT_MASK", ""))
+ 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
-is_protected.uses_root = True
+@uses_eroot
def filter_protected(argv):
- """<root>
+ """<eroot>
Read filenames from stdin and write them to stdout if they are protected.
- All filenames are delimited by \\n and must begin with <root>.
+ All filenames are delimited by \\n and must begin with <eroot>.
"""
if len(argv) != 1:
- sys.stderr.write("ERROR: expeced 1 parameters, got %d!\n" % len(argv))
+ sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
sys.stderr.flush()
return 2
except OSError:
pass
- import shlex
from portage.util import ConfigProtect
settings = portage.settings
- protect = shlex.split(settings.get("CONFIG_PROTECT", ""))
- protect_mask = shlex.split(settings.get("CONFIG_PROTECT_MASK", ""))
+ 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)
- protected = 0
errors = 0
for line in sys.stdin:
f = portage.normalize_path(f)
if not f.startswith(root):
- err.write("ERROR: file paths must begin with <root>!\n")
+ err.write("ERROR: file paths must begin with <eroot>!\n")
err.flush()
errors += 1
continue
if protect_obj.isprotected(f):
- protected += 1
out.write("%s\n" % filename)
out.flush()
return 0
-filter_protected.uses_root = True
+@uses_eroot
def best_visible(argv):
- """<root> [<category/package>]+
+ """<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):
- print "ERROR: insufficient parameters!"
- sys.exit(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:
- mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1])
- visible=portage.best(mylist)
- if visible:
- print visible
- sys.exit(0)
+ 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:
- sys.exit(1)
- except KeyError:
- sys.exit(1)
-best_visible.uses_root = True
+ 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):
- """<root> [<category/package>]+
+ """<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!"
- sys.exit(2)
+ print("ERROR: insufficient parameters!")
+ return 2
try:
- for pack in argv[1:]:
- mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
- print pack+":"+portage.best(mylist)
+ 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:
- sys.exit(1)
-mass_best_visible.uses_root = True
+ return 1
+@uses_eroot
def all_best_visible(argv):
- """<root>
+ """<eroot>
Returns all best_visible packages (without .ebuild).
"""
- if (len(argv) < 1):
- print "ERROR: insufficient parameters!"
-
+ 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
-all_best_visible.uses_root = True
+ print(mybest)
+@uses_eroot
def match(argv):
- """<root> <atom>
+ """<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)
- sys.exit(2)
+ print("ERROR: expected 2 parameters, got %d!" % len(argv))
+ return 2
root, atom = argv
- if atom:
- if atom_validate_strict and not portage.isvalidatom(atom):
- portage.writemsg("ERROR: Invalid atom: '%s'\n" % atom,
- noiselevel=-1)
- return 2
- results = portage.db[root]["vartree"].dbapi.match(atom)
- else:
- results = portage.db[root]["vartree"].dbapi.cpv_all()
+ 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
-match.uses_root = True
+ 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,))
-def vdb_path(argv):
+ 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["ROOT"], portage.VDB_PATH) + "\n")
+ out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
out.flush()
return os.EX_OK
-def gentoo_mirrors(argv):
+def gentoo_mirrors(_argv):
"""
Returns the mirrors set to use in the portage configuration.
"""
- print portage.settings["GENTOO_MIRRORS"]
+ 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):
+def portdir(_argv):
"""
Returns the PORTDIR path.
+ Deprecated in favor of repositories_configuration command.
"""
- print portage.settings["PORTDIR"]
+ print("WARNING: 'portageq portdir' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr)
+ print(portage.settings["PORTDIR"])
-def config_protect(argv):
+def config_protect(_argv):
"""
Returns the CONFIG_PROTECT paths.
"""
- print portage.settings["CONFIG_PROTECT"]
+ print(portage.settings["CONFIG_PROTECT"])
-def config_protect_mask(argv):
+def config_protect_mask(_argv):
"""
Returns the CONFIG_PROTECT_MASK paths.
"""
- print portage.settings["CONFIG_PROTECT_MASK"]
+ print(portage.settings["CONFIG_PROTECT_MASK"])
-def portdir_overlay(argv):
+def portdir_overlay(_argv):
"""
Returns the PORTDIR_OVERLAY path.
+ Deprecated in favor of repositories_configuration command.
"""
- print portage.settings["PORTDIR_OVERLAY"]
+ print("WARNING: 'portageq portdir_overlay' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr)
+ print(portage.settings["PORTDIR_OVERLAY"])
-def pkgdir(argv):
+def pkgdir(_argv):
"""
Returns the PKGDIR path.
"""
- print portage.settings["PKGDIR"]
+ print(portage.settings["PKGDIR"])
-def distdir(argv):
+def distdir(_argv):
"""
Returns the DISTDIR path.
"""
- print portage.settings["DISTDIR"]
+ print(portage.settings["DISTDIR"])
+
+
+def colormap(_argv):
+ """
+ Display the color.map as environment variables.
+ """
+ print(portage.output.colormap())
def envvar(argv):
argv.pop(argv.index("-v"))
if len(argv) == 0:
- print "ERROR: insufficient parameters!"
- sys.exit(2)
+ 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.settings[arg] +"'"
+ print(arg + "=" + portage._shell_quote(portage.settings[arg]))
else:
- print portage.settings[arg]
+ print(portage.settings[arg])
+
+@uses_eroot
def get_repos(argv):
- """<root>
- Returns all repos with names (repo_name file) argv[0] = $ROOT
+ """<eroot>
+ Returns all repos with names (repo_name file) argv[0] = $EROOT
"""
if len(argv) < 1:
- print "ERROR: insufficient parameters!"
- sys.exit(2)
- print " ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories())
+ 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):
- """<root> <repo_id>+
- Returns the path to the repo named argv[1], argv[0] = $ROOT
+ """<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!"
- sys.exit(2)
+ print("ERROR: insufficient parameters!", file=sys.stderr)
+ return 3
for arg in argv[1:]:
- print portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg)
+ 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):
- """<root>
+ """<eroot>
Print a list of libraries preserved during a package update in the form
- package: path. Returns 0 if no preserved libraries could be found,
- 1 otherwise.
+ package: path. Returns 1 if no preserved libraries could be found,
+ 0 otherwise.
"""
if len(argv) != 1:
- print "ERROR: wrong number of arguments"
- sys.exit(2)
- mylibs = portage.db[argv[0]]["vartree"].dbapi.plib_registry.getPreservedLibs()
- rValue = 0
- for cpv in mylibs:
- print cpv,
+ 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]:
- print path,
- rValue = 1
- print
+ msg.append(' ' + path)
+ rValue = 0
+ msg.append('\n')
+ writemsg_stdout(''.join(msg), noiselevel=-1)
return rValue
-list_preserved_libs.uses_root = True
+
+
+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
+
#-----------------------------------------------------------------------------
#
# 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 ">>> $Id$"
- print ">>> Usage: portageq <command> [<option> ...]"
- print ""
- print "Available commands:"
+ 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.
#
- commands = [x for x in globals() if x not in \
- ("usage", "__doc__", "__name__", "main", "os", "portage", \
- "sys", "__builtins__", "types", "string","exithandler")]
- commands.sort()
-
+ help_mode = '--help' in argv
for name in commands:
# Drop non-functions
obj = globals()[name]
- if (type(obj) != types.FunctionType):
- continue
doc = obj.__doc__
if (doc == None):
- print " "+name
- print " MISSING DOCUMENTATION!"
- print ""
+ print(" " + name)
+ print(" MISSING DOCUMENTATION!")
+ print("")
continue
- lines = doc.split("\n")
- print " "+name+" "+lines[0].strip()
- if (len(sys.argv) > 1):
- if ("--help" not in sys.argv):
+ 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()
- if (len(sys.argv) == 1):
- print "\nRun portageq with --help for info"
+ 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():
- if "-h" in sys.argv or "--help" in sys.argv:
- usage(sys.argv)
- sys.exit(os.EX_OK)
- elif len(sys.argv) < 2:
- usage(sys.argv)
- sys.exit(os.EX_USAGE)
+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)
- cmd = sys.argv[1]
- function = globals().get(cmd)
- if function is None:
- usage(sys.argv)
+ 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_root = getattr(function, "uses_root", False) and len(sys.argv) > 2
- if uses_root:
- if not os.path.isdir(sys.argv[2]):
- sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
+ 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)
- os.environ["ROOT"] = sys.argv[2]
-
- # Avoid sandbox violations after python upgrade.
- from os import path as osp
- pym_path = osp.join(osp.dirname(
- osp.dirname(osp.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))
-
- global portage
- try:
- import portage
- except ImportError:
- sys.path.insert(0, pym_path)
- import portage
+ 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_root:
- sys.argv[2] = portage.settings["ROOT"]
- retval = function(sys.argv[2:])
+ if uses_eroot:
+ args[0] = portage.settings['EROOT']
+ retval = function(args)
if retval:
sys.exit(retval)
- except portage.exception.PermissionDenied, e:
+ except portage.exception.PermissionDenied as e:
sys.stderr.write("Permission denied: '%s'\n" % str(e))
sys.exit(e.errno)
- except portage.exception.ParseError, e:
+ except portage.exception.ParseError as e:
sys.stderr.write("%s\n" % str(e))
sys.exit(1)
- except ValueError, e:
- if not e.args or \
- not hasattr(e.args[0], "__len__") or \
- len(e.args[0]) < 2:
- raise
+ 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("\nPlease use a more specific atom.\n", noiselevel=-1)
sys.exit(1)
-main()
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
#-----------------------------------------------------------------------------