blob: 2f254ca81d59a4ff4dbdce31c57fd9a2f917a5f2 [file] [log] [blame]
#!/usr/bin/python -O
# Copyright 1999-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from __future__ import print_function
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 subprocess
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
try:
import portage
except ImportError:
sys.path.insert(0, pym_path)
import portage
del pym_path
from portage import os
from portage.util import writemsg, writemsg_stdout
def eval_atom_use(atom):
if 'USE' in os.environ:
use = frozenset(os.environ['USE'].split())
atom = atom.evaluate_conditionals(use)
return atom
#-----------------------------------------------------------------------------
#
# 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!
#
def has_version(argv):
"""<root> <category/package>
Return code 0 if it's available, 1 otherwise.
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
sys.exit(2)
warnings = []
try:
atom = portage.dep.Atom(argv[1])
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], eapi=eapi)
except portage.exception.InvalidAtom as e:
warnings.append(
portage._unicode_decode("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:
sys.exit(0)
else:
sys.exit(1)
except KeyError:
sys.exit(1)
except portage.exception.InvalidAtom:
portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
noiselevel=-1)
return 2
has_version.uses_root = True
def best_version(argv):
"""<root> <category/package>
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
sys.exit(2)
warnings = []
try:
atom = portage.dep.Atom(argv[1])
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], eapi=eapi)
except portage.exception.InvalidAtom as e:
warnings.append(
portage._unicode_decode("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:
sys.exit(1)
best_version.uses_root = True
def mass_best_version(argv):
"""<root> [<category/package>]+
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
sys.exit(2)
try:
for pack in argv[1:]:
mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
print(pack+":"+portage.best(mylist))
except KeyError:
sys.exit(1)
mass_best_version.uses_root = True
def metadata(argv):
if (len(argv) < 4):
print("ERROR: insufficient parameters!", file=sys.stderr)
sys.exit(2)
root, 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)
sys.exit(1)
trees = portage.db
if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
root = portage.settings["ROOT"] # contains the normalized $ROOT
try:
values = trees[root][type_map[pkgtype]].dbapi.aux_get(
pkgspec, metakeys)
writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
except KeyError:
print("Package not found: '%s'" % pkgspec, file=sys.stderr)
sys.exit(1)
metadata.__doc__ = """
<root> <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
def contents(argv):
"""<root> <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>.
"""
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)
contents.uses_root = True
def owners(argv):
"""<root> [<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 <root> 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
cwd = None
try:
cwd = os.getcwd()
except OSError:
pass
files = []
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(root):
sys.stderr.write("ERROR: file paths must begin with <root>!\n")
sys.stderr.flush()
return 2
if is_basename:
files.append(f)
else:
files.append(f[len(root)-1:])
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):
msg.append("\t%s\n" % \
os.path.join(root, f.lstrip(os.path.sep)))
writemsg_stdout(''.join(msg), noiselevel=-1)
if owners:
return 0
sys.stderr.write("None of the installed packages claim the file(s).\n")
sys.stderr.flush()
return 1
owners.uses_root = True
def is_protected(argv):
"""<root> <filename>
Given a single filename, return code 0 if it's protected, 1 otherwise.
The filename must begin with <root>.
"""
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 <root>!\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
is_protected.uses_root = True
def filter_protected(argv):
"""<root>
Read filenames from stdin and write them to stdout if they are protected.
All filenames are delimited by \\n and must begin with <root>.
"""
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)
protected = 0
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 <root>!\n")
err.flush()
errors += 1
continue
if protect_obj.isprotected(f):
protected += 1
out.write("%s\n" % filename)
out.flush()
if errors:
return 2
return 0
filter_protected.uses_root = True
def best_visible(argv):
"""<root> [<category/package>]+
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
sys.exit(2)
try:
mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1])
visible=portage.best(mylist)
if visible:
print(visible)
sys.exit(0)
else:
sys.exit(1)
except KeyError:
sys.exit(1)
best_visible.uses_root = True
def mass_best_visible(argv):
"""<root> [<category/package>]+
Returns category/package-version (without .ebuild).
"""
if (len(argv) < 2):
print("ERROR: insufficient parameters!")
sys.exit(2)
try:
for pack in argv[1:]:
mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
print(pack+":"+portage.best(mylist))
except KeyError:
sys.exit(1)
mass_best_visible.uses_root = True
def all_best_visible(argv):
"""<root>
Returns all best_visible packages (without .ebuild).
"""
if (len(argv) < 1):
print("ERROR: insufficient parameters!")
#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
def match(argv):
"""<root> <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)
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()
results.sort()
for cpv in results:
print(cpv)
match.uses_root = True
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"])
def portdir(argv):
"""
Returns the PORTDIR path.
"""
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.
"""
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 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!")
sys.exit(2)
for arg in argv:
if verbose:
print(arg +"='"+ portage.settings[arg] +"'")
else:
print(portage.settings[arg])
def get_repos(argv):
"""<root>
Returns all repos with names (repo_name file) argv[0] = $ROOT
"""
if len(argv) < 1:
print("ERROR: insufficient parameters!")
sys.exit(2)
print(" ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories()))
def get_repo_path(argv):
"""<root> <repo_id>+
Returns the path to the repo named argv[1], argv[0] = $ROOT
"""
if len(argv) < 2:
print("ERROR: insufficient parameters!")
sys.exit(2)
for arg in argv[1:]:
print(portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg))
def list_preserved_libs(argv):
"""<root>
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")
sys.exit(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
list_preserved_libs.uses_root = True
#-----------------------------------------------------------------------------
#
# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
#
if not portage.const._ENABLE_PRESERVE_LIBS:
del list_preserved_libs
non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'main',
'usage', 'writemsg', 'writemsg_stdout'])
commands = sorted(k for k, v in globals().items() \
if type(v) is types.FunctionType and k not in non_commands)
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 sys.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.split("\n")
print(" " + name + " " + lines[0].strip())
if (len(sys.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")
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():
nocolor = os.environ.get('NOCOLOR')
if nocolor in ('yes', 'true'):
portage.output.nocolor()
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)
cmd = sys.argv[1]
function = globals().get(cmd)
if function is None or cmd not in commands:
usage(sys.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])
sys.stderr.write("Run portageq with --help for info\n")
sys.stderr.flush()
sys.exit(os.EX_USAGE)
os.environ["ROOT"] = sys.argv[2]
args = sys.argv[2:]
if args and sys.hexversion < 0x3000000 and not isinstance(args[0], unicode):
for i in range(len(args)):
args[i] = portage._unicode_decode(args[i])
try:
if uses_root:
args[0] = portage.settings["ROOT"]
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)
main()
#-----------------------------------------------------------------------------