| #!/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 = [] |
| 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(root): |
| sys.stderr.write("ERROR: file paths must begin with <root>!\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 |
| |
| 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() |
| |
| #----------------------------------------------------------------------------- |