2 # Copyright 1999-2011 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
5 from __future__ import print_function
9 # This block ensures that ^C interrupts are handled quietly.
12 def exithandler(signum, frame):
13 signal.signal(signal.SIGINT, signal.SIG_IGN)
14 signal.signal(signal.SIGTERM, signal.SIG_IGN)
15 sys.exit(128 + signum)
17 signal.signal(signal.SIGINT, exithandler)
18 signal.signal(signal.SIGTERM, exithandler)
20 except KeyboardInterrupt:
21 sys.exit(128 + signal.SIGINT)
26 # Avoid sandbox violations after python upgrade.
27 pym_path = os.path.join(os.path.dirname(
28 os.path.dirname(os.path.realpath(__file__))), "pym")
29 if os.environ.get("SANDBOX_ON") == "1":
30 sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
31 if pym_path not in sandbox_write:
32 sandbox_write.append(pym_path)
33 os.environ["SANDBOX_WRITE"] = \
34 ":".join(filter(None, sandbox_write))
40 sys.path.insert(0, pym_path)
44 from portage import os
45 from portage.util import writemsg, writemsg_stdout
46 portage.proxy.lazyimport.lazyimport(globals(),
48 '_emerge.Package:Package',
49 '_emerge.RootConfig:RootConfig',
50 'portage.dbapi._expand_new_virt:expand_new_virt',
51 'portage._sets.base:InternalPackageSet',
54 def eval_atom_use(atom):
55 if 'USE' in os.environ:
56 use = frozenset(os.environ['USE'].split())
57 atom = atom.evaluate_conditionals(use)
60 #-----------------------------------------------------------------------------
62 # To add functionality to this tool, add a function below.
64 # The format for functions is:
67 # """<list of options for this function>
68 # <description of the function>
72 # "argv" is an array of the command line parameters provided after the command.
74 # Make sure you document the function in the right format. The documentation
75 # is used to display help on the function.
77 # You do not need to add the function to any lists, this tool is introspective,
78 # and will automaticly add a command by the same name as the function!
81 def has_version(argv):
82 """<root> <category/package>
83 Return code 0 if it's available, 1 otherwise.
86 print("ERROR: insufficient parameters!")
92 atom = portage.dep.Atom(argv[1])
93 except portage.exception.InvalidAtom:
94 if atom_validate_strict:
95 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
101 if atom_validate_strict:
103 atom = portage.dep.Atom(argv[1], eapi=eapi)
104 except portage.exception.InvalidAtom as e:
106 portage._unicode_decode("QA Notice: %s: %s") % \
108 atom = eval_atom_use(atom)
111 elog('eqawarn', warnings)
114 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
121 except portage.exception.InvalidAtom:
122 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
125 has_version.uses_root = True
128 def best_version(argv):
129 """<root> <category/package>
130 Returns category/package-version (without .ebuild).
133 print("ERROR: insufficient parameters!")
139 atom = portage.dep.Atom(argv[1])
140 except portage.exception.InvalidAtom:
141 if atom_validate_strict:
142 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
148 if atom_validate_strict:
150 atom = portage.dep.Atom(argv[1], eapi=eapi)
151 except portage.exception.InvalidAtom as e:
153 portage._unicode_decode("QA Notice: %s: %s") % \
155 atom = eval_atom_use(atom)
158 elog('eqawarn', warnings)
161 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
162 print(portage.best(mylist))
165 best_version.uses_root = True
168 def mass_best_version(argv):
169 """<root> [<category/package>]+
170 Returns category/package-version (without .ebuild).
173 print("ERROR: insufficient parameters!")
176 for pack in argv[1:]:
177 mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
178 print(pack+":"+portage.best(mylist))
181 mass_best_version.uses_root = True
185 print("ERROR: insufficient parameters!", file=sys.stderr)
188 eroot, pkgtype, pkgspec = argv[0:3]
193 "installed":"vartree"}
194 if pkgtype not in type_map:
195 print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
199 values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
201 writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
203 print("Package not found: '%s'" % pkgspec, file=sys.stderr)
206 metadata.__doc__ = """
207 <root> <pkgtype> <category/package> [<key>]+
208 Returns metadata values for the specified package.
210 """ % ','.join(sorted(x for x in portage.auxdbkeys \
211 if not x.startswith('UNUSED_')))
213 metadata.uses_root = True
216 """<root> <category/package>
217 List the files that are installed for a given package, with
218 one file listed on each line. All file names will begin with
222 print("ERROR: expected 2 parameters, got %d!" % len(argv))
226 vartree = portage.db[root]["vartree"]
227 if not vartree.dbapi.cpv_exists(cpv):
228 sys.stderr.write("Package not found: '%s'\n" % cpv)
230 cat, pkg = portage.catsplit(cpv)
231 db = portage.dblink(cat, pkg, root, vartree.settings,
232 treetype="vartree", vartree=vartree)
233 writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
235 contents.uses_root = True
238 """<root> [<filename>]+
239 Given a list of files, print the packages that own the files and which
240 files belong to each package. Files owned by a package are listed on
241 the lines below it, indented by a single tab character (\\t). All file
242 paths must either start with <root> or be a basename alone.
243 Returns 1 if no owners could be found, and 0 otherwise.
246 sys.stderr.write("ERROR: insufficient parameters!\n")
250 from portage import catsplit, dblink
252 vardb = portage.db[eroot]["vartree"].dbapi
253 root = portage.settings['ROOT']
262 orphan_abs_paths = set()
263 orphan_basenames = set()
265 f = portage.normalize_path(f)
266 is_basename = os.sep not in f
267 if not is_basename and f[:1] != os.sep:
269 sys.stderr.write("ERROR: cwd does not exist!\n")
272 f = os.path.join(cwd, f)
273 f = portage.normalize_path(f)
274 if not is_basename and not f.startswith(root):
275 sys.stderr.write("ERROR: file paths must begin with <root>!\n")
280 orphan_basenames.add(f)
282 files.append(f[len(root)-1:])
283 orphan_abs_paths.add(f)
285 owners = vardb._owners.get_owners(files)
288 for pkg, owned_files in owners.items():
290 msg.append("%s\n" % cpv)
291 for f in sorted(owned_files):
292 f_abs = os.path.join(root, f.lstrip(os.path.sep))
293 msg.append("\t%s\n" % (f_abs,))
294 orphan_abs_paths.discard(f_abs)
296 orphan_basenames.discard(os.path.basename(f_abs))
298 writemsg_stdout(''.join(msg), noiselevel=-1)
300 if orphan_abs_paths or orphan_basenames:
302 orphans.extend(orphan_abs_paths)
303 orphans.extend(orphan_basenames)
306 msg.append("None of the installed packages claim these files:\n")
308 msg.append("\t%s\n" % (f,))
309 sys.stderr.write("".join(msg))
316 owners.uses_root = True
318 def is_protected(argv):
320 Given a single filename, return code 0 if it's protected, 1 otherwise.
321 The filename must begin with <root>.
324 sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
328 root, filename = argv
337 f = portage.normalize_path(filename)
338 if not f.startswith(os.path.sep):
340 err.write("ERROR: cwd does not exist!\n")
343 f = os.path.join(cwd, f)
344 f = portage.normalize_path(f)
346 if not f.startswith(root):
347 err.write("ERROR: file paths must begin with <root>!\n")
351 from portage.util import ConfigProtect
353 settings = portage.settings
354 protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
355 protect_mask = portage.util.shlex_split(
356 settings.get("CONFIG_PROTECT_MASK", ""))
357 protect_obj = ConfigProtect(root, protect, protect_mask)
359 if protect_obj.isprotected(f):
363 is_protected.uses_root = True
365 def filter_protected(argv):
367 Read filenames from stdin and write them to stdout if they are protected.
368 All filenames are delimited by \\n and must begin with <root>.
371 sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
384 from portage.util import ConfigProtect
386 settings = portage.settings
387 protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
388 protect_mask = portage.util.shlex_split(
389 settings.get("CONFIG_PROTECT_MASK", ""))
390 protect_obj = ConfigProtect(root, protect, protect_mask)
395 for line in sys.stdin:
396 filename = line.rstrip("\n")
397 f = portage.normalize_path(filename)
398 if not f.startswith(os.path.sep):
400 err.write("ERROR: cwd does not exist!\n")
404 f = os.path.join(cwd, f)
405 f = portage.normalize_path(f)
407 if not f.startswith(root):
408 err.write("ERROR: file paths must begin with <root>!\n")
413 if protect_obj.isprotected(f):
415 out.write("%s\n" % filename)
423 filter_protected.uses_root = True
425 def best_visible(argv):
426 """<root> [pkgtype] <atom>
427 Returns category/package-version (without .ebuild).
428 The pkgtype argument defaults to "ebuild" if unspecified,
429 otherwise it must be one of ebuild, binary, or installed.
432 writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
445 "installed":"vartree"}
447 if pkgtype not in type_map:
448 writemsg("Unrecognized package type: '%s'\n" % pkgtype,
453 db = portage.db[eroot][type_map[pkgtype]].dbapi
456 atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
457 except portage.exception.InvalidAtom:
458 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
462 root_config = RootConfig(portage.settings,
463 portage.db[eroot], None)
465 if hasattr(db, "xmatch"):
466 cpv_list = db.xmatch("match-all-cpv-only", atom)
468 cpv_list = db.match(atom)
471 # reversed, for descending order
473 # verify match, since the atom may match the package
474 # for a given cpv from one repo but not another, and
475 # we can use match-all-cpv-only to avoid redundant
477 atom_set = InternalPackageSet(initial_atoms=(atom,))
479 if atom.repo is None and hasattr(db, "getRepositories"):
480 repo_list = db.getRepositories()
482 repo_list = [atom.repo]
485 for repo in repo_list:
487 metadata = dict(zip(Package.metadata_keys,
488 db.aux_get(cpv, Package.metadata_keys, myrepo=repo)))
491 pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
492 installed=(pkgtype=="installed"), metadata=metadata,
493 root_config=root_config, type_name=pkgtype)
494 if not atom_set.findAtomForPackage(pkg):
498 writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
502 best_visible.uses_root = True
505 def mass_best_visible(argv):
506 """<root> [<category/package>]+
507 Returns category/package-version (without .ebuild).
510 print("ERROR: insufficient parameters!")
513 for pack in argv[1:]:
514 mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
515 print(pack+":"+portage.best(mylist))
518 mass_best_visible.uses_root = True
521 def all_best_visible(argv):
523 Returns all best_visible packages (without .ebuild).
526 sys.stderr.write("ERROR: insufficient parameters!\n")
530 #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
531 for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
532 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
535 all_best_visible.uses_root = True
540 Returns a \\n separated list of category/package-version.
541 When given an empty string, all installed packages will
545 print("ERROR: expected 2 parameters, got %d!" % len(argv))
551 vardb = portage.db[root]["vartree"].dbapi
553 atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
554 except portage.exception.InvalidAtom:
555 # maybe it's valid but missing category
556 atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
558 if atom.extended_syntax:
560 results = vardb.cpv_all()
563 require_metadata = atom.slot or atom.repo
564 for cpv in vardb.cpv_all():
566 if not portage.dep.extended_cp_match(
567 atom.cp, portage.cpv_getkey(cpv)):
571 slot, repo = vardb.aux_get(cpv, ["SLOT", "repository"])
573 if atom.slot is not None and atom.slot != slot:
576 if atom.repo is not None and atom.repo != repo:
583 results = vardb.match(atom)
586 match.uses_root = True
588 def expand_virtual(argv):
590 Returns a \\n separated list of atoms expanded from a
591 given virtual atom (GLEP 37 virtuals only),
592 excluding blocker atoms. Satisfied
593 virtual atoms are not included in the output, since
594 they are expanded to real atoms which are displayed.
595 Unsatisfied virtual atoms are displayed without
596 any expansion. The "match" command can be used to
597 resolve the returned atoms to specific installed
601 writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
608 results = list(expand_new_virt(
609 portage.db[root]["vartree"].dbapi, atom))
610 except portage.exception.InvalidAtom:
611 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
618 writemsg_stdout("%s\n" % (x,))
622 expand_virtual.uses_root = True
626 Returns the path used for the var(installed) package database for the
627 set environment/configuration options.
630 out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
634 def gentoo_mirrors(argv):
636 Returns the mirrors set to use in the portage configuration.
638 print(portage.settings["GENTOO_MIRRORS"])
643 Returns the PORTDIR path.
645 print(portage.settings["PORTDIR"])
648 def config_protect(argv):
650 Returns the CONFIG_PROTECT paths.
652 print(portage.settings["CONFIG_PROTECT"])
655 def config_protect_mask(argv):
657 Returns the CONFIG_PROTECT_MASK paths.
659 print(portage.settings["CONFIG_PROTECT_MASK"])
662 def portdir_overlay(argv):
664 Returns the PORTDIR_OVERLAY path.
666 print(portage.settings["PORTDIR_OVERLAY"])
671 Returns the PKGDIR path.
673 print(portage.settings["PKGDIR"])
678 Returns the DISTDIR path.
680 print(portage.settings["DISTDIR"])
685 Returns a specific environment variable as exists prior to ebuild.sh.
686 Similar to: emerge --verbose --info | egrep '^<variable>='
688 verbose = "-v" in argv
690 argv.pop(argv.index("-v"))
693 print("ERROR: insufficient parameters!")
698 print(arg +"='"+ portage.settings[arg] +"'")
700 print(portage.settings[arg])
704 Returns all repos with names (repo_name file) argv[0] = $ROOT
707 print("ERROR: insufficient parameters!")
709 print(" ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories()))
711 def get_repo_path(argv):
713 Returns the path to the repo named argv[1], argv[0] = $ROOT
716 print("ERROR: insufficient parameters!")
719 path = portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg)
724 def list_preserved_libs(argv):
726 Print a list of libraries preserved during a package update in the form
727 package: path. Returns 1 if no preserved libraries could be found,
732 print("ERROR: wrong number of arguments")
734 mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
737 for cpv in sorted(mylibs):
739 for path in mylibs[cpv]:
740 msg.append(' ' + path)
743 writemsg_stdout(''.join(msg), noiselevel=-1)
745 list_preserved_libs.uses_root = True
747 #-----------------------------------------------------------------------------
749 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
752 if not portage.const._ENABLE_PRESERVE_LIBS:
753 del list_preserved_libs
755 non_commands = frozenset(['elog', 'eval_atom_use',
756 'exithandler', 'expand_new_virt', 'main',
757 'usage', 'writemsg', 'writemsg_stdout'])
758 commands = sorted(k for k, v in globals().items() \
759 if k not in non_commands and isinstance(v, types.FunctionType))
762 print(">>> Portage information query tool")
763 print(">>> %s" % portage.VERSION)
764 print(">>> Usage: portageq <command> [<option> ...]")
766 print("Available commands:")
769 # Show our commands -- we do this by scanning the functions in this
770 # file, and formatting each functions documentation.
772 help_mode = '--help' in sys.argv
773 for name in commands:
775 obj = globals()[name]
780 print(" MISSING DOCUMENTATION!")
784 lines = doc.lstrip("\n").split("\n")
785 print(" " + name + " " + lines[0].strip())
786 if (len(sys.argv) > 1):
789 for line in lines[1:]:
790 print(" " + line.strip())
791 if (len(sys.argv) == 1):
792 print("\nRun portageq with --help for info")
794 atom_validate_strict = "EBUILD_PHASE" in os.environ
796 if atom_validate_strict:
797 eapi = os.environ.get('EAPI')
799 def elog(elog_funcname, lines):
800 cmd = "source '%s/isolated-functions.sh' ; " % \
801 os.environ["PORTAGE_BIN_PATH"]
803 cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
804 subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
807 def elog(elog_funcname, lines):
812 nocolor = os.environ.get('NOCOLOR')
813 if nocolor in ('yes', 'true'):
814 portage.output.nocolor()
816 if len(sys.argv) < 2:
818 sys.exit(os.EX_USAGE)
821 if x in ("-h", "--help"):
824 elif x == "--version":
825 print("Portage", portage.VERSION)
829 function = globals().get(cmd)
830 if function is None or cmd not in commands:
832 sys.exit(os.EX_USAGE)
833 function = globals()[cmd]
834 uses_root = getattr(function, "uses_root", False) and len(sys.argv) > 2
836 if not os.path.isdir(sys.argv[2]):
837 sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
838 sys.stderr.write("Run portageq with --help for info\n")
840 sys.exit(os.EX_USAGE)
841 eprefix = os.environ.get("__PORTAGE_TEST_EPREFIX")
842 eroot = portage.util.normalize_path(sys.argv[2])
844 root = eroot[:1-len(eprefix)]
847 os.environ["ROOT"] = root
850 if args and sys.hexversion < 0x3000000 and not isinstance(args[0], unicode):
851 for i in range(len(args)):
852 args[i] = portage._unicode_decode(args[i])
856 args[0] = portage.settings['EROOT']
857 retval = function(args)
860 except portage.exception.PermissionDenied as e:
861 sys.stderr.write("Permission denied: '%s'\n" % str(e))
863 except portage.exception.ParseError as e:
864 sys.stderr.write("%s\n" % str(e))
866 except portage.exception.AmbiguousPackageName as e:
867 # Multiple matches thrown from cpv_expand
869 # An error has occurred so we writemsg to stderr and exit nonzero.
870 portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
872 portage.writemsg("* %s\n" % pkg, noiselevel=-1)
873 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
878 #-----------------------------------------------------------------------------