97b5f3f149be2261c1c85d414f63e1c43340eea8
[portage.git] / bin / portageq
1 #!/usr/bin/python -O
2 # Copyright 1999-2012 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 from __future__ import print_function
6
7 import signal
8 import sys
9 # This block ensures that ^C interrupts are handled quietly.
10 try:
11
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)
16
17         signal.signal(signal.SIGINT, exithandler)
18         signal.signal(signal.SIGTERM, exithandler)
19
20 except KeyboardInterrupt:
21         sys.exit(128 + signal.SIGINT)
22
23 import os
24 import types
25
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))
35         del sandbox_write
36
37 sys.path.insert(0, pym_path)
38 import portage
39 from portage import os
40 from portage.eapi import eapi_has_repo_deps
41 from portage.util import writemsg, writemsg_stdout
42 from portage.output import colormap
43 portage.proxy.lazyimport.lazyimport(globals(),
44         'subprocess',
45         '_emerge.Package:Package',
46         '_emerge.RootConfig:RootConfig',
47         'portage.dbapi._expand_new_virt:expand_new_virt',
48         'portage._sets.base:InternalPackageSet',
49 )
50
51 def eval_atom_use(atom):
52         if 'USE' in os.environ:
53                 use = frozenset(os.environ['USE'].split())
54                 atom = atom.evaluate_conditionals(use)
55         return atom
56
57 #-----------------------------------------------------------------------------
58 #
59 # To add functionality to this tool, add a function below.
60 #
61 # The format for functions is:
62 #
63 #   def function(argv):
64 #       """<list of options for this function>
65 #       <description of the function>
66 #       """
67 #       <code>
68 #
69 # "argv" is an array of the command line parameters provided after the command.
70 #
71 # Make sure you document the function in the right format.  The documentation
72 # is used to display help on the function.
73 #
74 # You do not need to add the function to any lists, this tool is introspective,
75 # and will automaticly add a command by the same name as the function!
76 #
77
78 def has_version(argv):
79         """<eroot> <category/package>
80         Return code 0 if it's available, 1 otherwise.
81         """
82         if (len(argv) < 2):
83                 print("ERROR: insufficient parameters!")
84                 return 3
85
86         warnings = []
87
88         allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
89         try:
90                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
91         except portage.exception.InvalidAtom:
92                 if atom_validate_strict:
93                         portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
94                                 noiselevel=-1)
95                         return 2
96                 else:
97                         atom = argv[1]
98         else:
99                 if atom_validate_strict:
100                         try:
101                                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
102                         except portage.exception.InvalidAtom as e:
103                                 warnings.append(
104                                         portage._unicode_decode("QA Notice: %s: %s") % \
105                                         ('has_version', e))
106                 atom = eval_atom_use(atom)
107
108         if warnings:
109                 elog('eqawarn', warnings)
110
111         try:
112                 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
113                 if mylist:
114                         return 0
115                 else:
116                         return 1
117         except KeyError:
118                 return 1
119         except portage.exception.InvalidAtom:
120                 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
121                         noiselevel=-1)
122                 return 2
123 has_version.uses_eroot = True
124
125
126 def best_version(argv):
127         """<eroot> <category/package>
128         Returns category/package-version (without .ebuild).
129         """
130         if (len(argv) < 2):
131                 print("ERROR: insufficient parameters!")
132                 return 3
133
134         warnings = []
135
136         allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
137         try:
138                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
139         except portage.exception.InvalidAtom:
140                 if atom_validate_strict:
141                         portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
142                                 noiselevel=-1)
143                         return 2
144                 else:
145                         atom = argv[1]
146         else:
147                 if atom_validate_strict:
148                         try:
149                                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
150                         except portage.exception.InvalidAtom as e:
151                                 warnings.append(
152                                         portage._unicode_decode("QA Notice: %s: %s") % \
153                                         ('best_version', e))
154                 atom = eval_atom_use(atom)
155
156         if warnings:
157                 elog('eqawarn', warnings)
158
159         try:
160                 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
161                 print(portage.best(mylist))
162         except KeyError:
163                 return 1
164 best_version.uses_eroot = True
165
166
167 def mass_best_version(argv):
168         """<eroot> [<category/package>]+
169         Returns category/package-version (without .ebuild).
170         """
171         if (len(argv) < 2):
172                 print("ERROR: insufficient parameters!")
173                 return 2
174         try:
175                 for pack in argv[1:]:
176                         mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
177                         print(pack+":"+portage.best(mylist))
178         except KeyError:
179                 return 1
180 mass_best_version.uses_eroot = True
181
182 def metadata(argv):
183         if (len(argv) < 4):
184                 print("ERROR: insufficient parameters!", file=sys.stderr)
185                 return 2
186
187         eroot, pkgtype, pkgspec = argv[0:3]
188         metakeys = argv[3:]
189         type_map = {
190                 "ebuild":"porttree",
191                 "binary":"bintree",
192                 "installed":"vartree"}
193         if pkgtype not in type_map:
194                 print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
195                 return 1
196         trees = portage.db
197         repo = portage.dep.dep_getrepo(pkgspec)
198         pkgspec = portage.dep.remove_slot(pkgspec)
199         try:
200                         values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
201                                 pkgspec, metakeys, myrepo=repo)
202                         writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
203         except KeyError:
204                 print("Package not found: '%s'" % pkgspec, file=sys.stderr)
205                 return 1
206
207 metadata.__doc__ = """
208 <eroot> <pkgtype> <category/package> [<key>]+
209 Returns metadata values for the specified package.
210 Available keys: %s
211 """  % ','.join(sorted(x for x in portage.auxdbkeys \
212 if not x.startswith('UNUSED_')))
213
214 metadata.uses_eroot = True
215
216 def contents(argv):
217         """<eroot> <category/package>
218         List the files that are installed for a given package, with
219         one file listed on each line. All file names will begin with
220         <eroot>.
221         """
222         if len(argv) != 2:
223                 print("ERROR: expected 2 parameters, got %d!" % len(argv))
224                 return 2
225
226         root, cpv = argv
227         vartree = portage.db[root]["vartree"]
228         if not vartree.dbapi.cpv_exists(cpv):
229                 sys.stderr.write("Package not found: '%s'\n" % cpv)
230                 return 1
231         cat, pkg = portage.catsplit(cpv)
232         db = portage.dblink(cat, pkg, root, vartree.settings,
233                 treetype="vartree", vartree=vartree)
234         writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
235                 noiselevel=-1)
236 contents.uses_eroot = True
237
238 def owners(argv):
239         """<eroot> [<filename>]+
240         Given a list of files, print the packages that own the files and which
241         files belong to each package. Files owned by a package are listed on
242         the lines below it, indented by a single tab character (\\t). All file
243         paths must either start with <eroot> or be a basename alone.
244         Returns 1 if no owners could be found, and 0 otherwise.
245         """
246         if len(argv) < 2:
247                 sys.stderr.write("ERROR: insufficient parameters!\n")
248                 sys.stderr.flush()
249                 return 2
250
251         from portage import catsplit, dblink
252         eroot = argv[0]
253         vardb = portage.db[eroot]["vartree"].dbapi
254         root = portage.settings['ROOT']
255
256         cwd = None
257         try:
258                 cwd = os.getcwd()
259         except OSError:
260                 pass
261
262         files = []
263         orphan_abs_paths = set()
264         orphan_basenames = set()
265         for f in argv[1:]:
266                 f = portage.normalize_path(f)
267                 is_basename = os.sep not in f
268                 if not is_basename and f[:1] != os.sep:
269                         if cwd is None:
270                                 sys.stderr.write("ERROR: cwd does not exist!\n")
271                                 sys.stderr.flush()
272                                 return 2
273                         f = os.path.join(cwd, f)
274                         f = portage.normalize_path(f)
275                 if not is_basename and not f.startswith(eroot):
276                         sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
277                         sys.stderr.flush()
278                         return 2
279                 if is_basename:
280                         files.append(f)
281                         orphan_basenames.add(f)
282                 else:
283                         files.append(f[len(root)-1:])
284                         orphan_abs_paths.add(f)
285
286         owners = vardb._owners.get_owners(files)
287
288         msg = []
289         for pkg, owned_files in owners.items():
290                 cpv = pkg.mycpv
291                 msg.append("%s\n" % cpv)
292                 for f in sorted(owned_files):
293                         f_abs = os.path.join(root, f.lstrip(os.path.sep))
294                         msg.append("\t%s\n" % (f_abs,))
295                         orphan_abs_paths.discard(f_abs)
296                         if orphan_basenames:
297                                 orphan_basenames.discard(os.path.basename(f_abs))
298
299         writemsg_stdout(''.join(msg), noiselevel=-1)
300
301         if orphan_abs_paths or orphan_basenames:
302                 orphans = []
303                 orphans.extend(orphan_abs_paths)
304                 orphans.extend(orphan_basenames)
305                 orphans.sort()
306                 msg = []
307                 msg.append("None of the installed packages claim these files:\n")
308                 for f in orphans:
309                         msg.append("\t%s\n" % (f,))
310                 sys.stderr.write("".join(msg))
311                 sys.stderr.flush()
312
313         if owners:
314                 return 0
315         return 1
316
317 owners.uses_eroot = True
318
319 def is_protected(argv):
320         """<eroot> <filename>
321         Given a single filename, return code 0 if it's protected, 1 otherwise.
322         The filename must begin with <eroot>.
323         """
324         if len(argv) != 2:
325                 sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
326                 sys.stderr.flush()
327                 return 2
328
329         root, filename = argv
330
331         err = sys.stderr
332         cwd = None
333         try:
334                 cwd = os.getcwd()
335         except OSError:
336                 pass
337
338         f = portage.normalize_path(filename)
339         if not f.startswith(os.path.sep):
340                 if cwd is None:
341                         err.write("ERROR: cwd does not exist!\n")
342                         err.flush()
343                         return 2
344                 f = os.path.join(cwd, f)
345                 f = portage.normalize_path(f)
346
347         if not f.startswith(root):
348                 err.write("ERROR: file paths must begin with <eroot>!\n")
349                 err.flush()
350                 return 2
351
352         from portage.util import ConfigProtect
353
354         settings = portage.settings
355         protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
356         protect_mask = portage.util.shlex_split(
357                 settings.get("CONFIG_PROTECT_MASK", ""))
358         protect_obj = ConfigProtect(root, protect, protect_mask)
359
360         if protect_obj.isprotected(f):
361                 return 0
362         return 1
363
364 is_protected.uses_eroot = True
365
366 def filter_protected(argv):
367         """<eroot>
368         Read filenames from stdin and write them to stdout if they are protected.
369         All filenames are delimited by \\n and must begin with <eroot>.
370         """
371         if len(argv) != 1:
372                 sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
373                 sys.stderr.flush()
374                 return 2
375
376         root, = argv
377         out = sys.stdout
378         err = sys.stderr
379         cwd = None
380         try:
381                 cwd = os.getcwd()
382         except OSError:
383                 pass
384
385         from portage.util import ConfigProtect
386
387         settings = portage.settings
388         protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
389         protect_mask = portage.util.shlex_split(
390                 settings.get("CONFIG_PROTECT_MASK", ""))
391         protect_obj = ConfigProtect(root, protect, protect_mask)
392
393         protected = 0
394         errors = 0
395
396         for line in sys.stdin:
397                 filename = line.rstrip("\n")
398                 f = portage.normalize_path(filename)
399                 if not f.startswith(os.path.sep):
400                         if cwd is None:
401                                 err.write("ERROR: cwd does not exist!\n")
402                                 err.flush()
403                                 errors += 1
404                                 continue
405                         f = os.path.join(cwd, f)
406                         f = portage.normalize_path(f)
407
408                 if not f.startswith(root):
409                         err.write("ERROR: file paths must begin with <eroot>!\n")
410                         err.flush()
411                         errors += 1
412                         continue
413
414                 if protect_obj.isprotected(f):
415                         protected += 1
416                         out.write("%s\n" % filename)
417         out.flush()
418
419         if errors:
420                 return 2
421
422         return 0
423
424 filter_protected.uses_eroot = True
425
426 def best_visible(argv):
427         """<eroot> [pkgtype] <atom>
428         Returns category/package-version (without .ebuild).
429         The pkgtype argument defaults to "ebuild" if unspecified,
430         otherwise it must be one of ebuild, binary, or installed.
431         """
432         if (len(argv) < 2):
433                 writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
434                 return 2
435
436         pkgtype = "ebuild"
437         if len(argv) > 2:
438                 pkgtype = argv[1]
439                 atom = argv[2]
440         else:
441                 atom = argv[1]
442
443         type_map = {
444                 "ebuild":"porttree",
445                 "binary":"bintree",
446                 "installed":"vartree"}
447
448         if pkgtype not in type_map:
449                 writemsg("Unrecognized package type: '%s'\n" % pkgtype,
450                         noiselevel=-1)
451                 return 2
452
453         eroot = argv[0]
454         db = portage.db[eroot][type_map[pkgtype]].dbapi
455
456         try:
457                 atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
458         except portage.exception.InvalidAtom:
459                 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
460                         noiselevel=-1)
461                 return 2
462
463         root_config = RootConfig(portage.settings,
464                 portage.db[eroot], None)
465
466         if hasattr(db, "xmatch"):
467                 cpv_list = db.xmatch("match-all-cpv-only", atom)
468         else:
469                 cpv_list = db.match(atom)
470
471         if cpv_list:
472                 # reversed, for descending order
473                 cpv_list.reverse()
474                 # verify match, since the atom may match the package
475                 # for a given cpv from one repo but not another, and
476                 # we can use match-all-cpv-only to avoid redundant
477                 # metadata access.
478                 atom_set = InternalPackageSet(initial_atoms=(atom,))
479
480                 if atom.repo is None and hasattr(db, "getRepositories"):
481                         repo_list = db.getRepositories()
482                 else:
483                         repo_list = [atom.repo]
484
485                 for cpv in cpv_list:
486                         for repo in repo_list:
487                                 try:
488                                         metadata = dict(zip(Package.metadata_keys,
489                                                 db.aux_get(cpv, Package.metadata_keys, myrepo=repo)))
490                                 except KeyError:
491                                         continue
492                                 pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
493                                         installed=(pkgtype=="installed"), metadata=metadata,
494                                         root_config=root_config, type_name=pkgtype)
495                                 if not atom_set.findAtomForPackage(pkg):
496                                         continue
497
498                                 if pkg.visible:
499                                         writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
500                                         return os.EX_OK
501
502         # No package found, write out an empty line.
503         writemsg_stdout("\n", noiselevel=-1)
504
505         return 1
506 best_visible.uses_eroot = True
507
508
509 def mass_best_visible(argv):
510         """<eroot> [<type>] [<category/package>]+
511         Returns category/package-version (without .ebuild).
512         The pkgtype argument defaults to "ebuild" if unspecified,
513         otherwise it must be one of ebuild, binary, or installed.
514         """
515         type_map = {
516                 "ebuild":"porttree",
517                 "binary":"bintree",
518                 "installed":"vartree"}
519
520         if (len(argv) < 2):
521                 print("ERROR: insufficient parameters!")
522                 return 2
523         try:
524                 root = argv.pop(0)
525                 pkgtype = "ebuild"
526                 if argv[0] in type_map:
527                         pkgtype = argv.pop(0)
528                 for pack in argv:
529                         writemsg_stdout("%s:" % pack, noiselevel=-1)
530                         best_visible([root, pkgtype, pack])
531         except KeyError:
532                 return 1
533 mass_best_visible.uses_eroot = True
534
535
536 def all_best_visible(argv):
537         """<eroot>
538         Returns all best_visible packages (without .ebuild).
539         """
540         if len(argv) < 1:
541                 sys.stderr.write("ERROR: insufficient parameters!\n")
542                 sys.stderr.flush()
543                 return 2
544
545         #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
546         for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
547                 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
548                 if mybest:
549                         print(mybest)
550 all_best_visible.uses_eroot = True
551
552
553 def match(argv):
554         """<eroot> <atom>
555         Returns a \\n separated list of category/package-version.
556         When given an empty string, all installed packages will
557         be listed.
558         """
559         if len(argv) != 2:
560                 print("ERROR: expected 2 parameters, got %d!" % len(argv))
561                 return 2
562         root, atom = argv
563         if not atom:
564                 atom = "*/*"
565
566         vardb = portage.db[root]["vartree"].dbapi
567         try:
568                 atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
569         except portage.exception.InvalidAtom:
570                 # maybe it's valid but missing category
571                 atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
572
573         if atom.extended_syntax:
574                 if atom == "*/*":
575                         results = vardb.cpv_all()
576                 else:
577                         results = []
578                         require_metadata = atom.slot or atom.repo
579                         for cpv in vardb.cpv_all():
580
581                                 if not portage.match_from_list(atom, [cpv]):
582                                         continue
583
584                                 if require_metadata:
585                                         try:
586                                                 cpv = vardb._pkg_str(cpv, atom.repo)
587                                         except (KeyError, portage.exception.InvalidData):
588                                                 continue
589                                         if not portage.match_from_list(atom, [cpv]):
590                                                 continue
591
592                                 results.append(cpv)
593
594                 results.sort()
595         else:
596                 results = vardb.match(atom)
597         for cpv in results:
598                 print(cpv)
599 match.uses_eroot = True
600
601 def expand_virtual(argv):
602         """<eroot> <atom>
603         Returns a \\n separated list of atoms expanded from a
604         given virtual atom (GLEP 37 virtuals only),
605         excluding blocker atoms. Satisfied
606         virtual atoms are not included in the output, since
607         they are expanded to real atoms which are displayed.
608         Unsatisfied virtual atoms are displayed without
609         any expansion. The "match" command can be used to
610         resolve the returned atoms to specific installed
611         packages.
612         """
613         if len(argv) != 2:
614                 writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
615                         noiselevel=-1)
616                 return 2
617
618         root, atom = argv
619
620         try:
621                 results = list(expand_new_virt(
622                         portage.db[root]["vartree"].dbapi, atom))
623         except portage.exception.InvalidAtom:
624                 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
625                         noiselevel=-1)
626                 return 2
627
628         results.sort()
629         for x in results:
630                 if not x.blocker:
631                         writemsg_stdout("%s\n" % (x,))
632
633         return os.EX_OK
634
635 expand_virtual.uses_eroot = True
636
637 def vdb_path(argv):
638         """
639         Returns the path used for the var(installed) package database for the
640         set environment/configuration options.
641         """
642         out = sys.stdout
643         out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
644         out.flush()
645         return os.EX_OK
646
647 def gentoo_mirrors(argv):
648         """
649         Returns the mirrors set to use in the portage configuration.
650         """
651         print(portage.settings["GENTOO_MIRRORS"])
652
653
654 def portdir(argv):
655         """
656         Returns the PORTDIR path.
657         """
658         print(portage.settings["PORTDIR"])
659
660
661 def config_protect(argv):
662         """
663         Returns the CONFIG_PROTECT paths.
664         """
665         print(portage.settings["CONFIG_PROTECT"])
666
667
668 def config_protect_mask(argv):
669         """
670         Returns the CONFIG_PROTECT_MASK paths.
671         """
672         print(portage.settings["CONFIG_PROTECT_MASK"])
673
674
675 def portdir_overlay(argv):
676         """
677         Returns the PORTDIR_OVERLAY path.
678         """
679         print(portage.settings["PORTDIR_OVERLAY"])
680
681
682 def pkgdir(argv):
683         """
684         Returns the PKGDIR path.
685         """
686         print(portage.settings["PKGDIR"])
687
688
689 def distdir(argv):
690         """
691         Returns the DISTDIR path.
692         """
693         print(portage.settings["DISTDIR"])
694
695
696 def colormap(argv):
697         """
698         Display the color.map as environment variables.
699         """
700         print(portage.output.colormap())
701
702
703 def envvar(argv):
704         """<variable>+
705         Returns a specific environment variable as exists prior to ebuild.sh.
706         Similar to: emerge --verbose --info | egrep '^<variable>='
707         """
708         verbose = "-v" in argv
709         if verbose:
710                 argv.pop(argv.index("-v"))
711
712         if len(argv) == 0:
713                 print("ERROR: insufficient parameters!")
714                 return 2
715
716         for arg in argv:
717                 if verbose:
718                         print(arg +"='"+ portage.settings[arg] +"'")
719                 else:
720                         print(portage.settings[arg])
721
722 def get_repos(argv):
723         """<eroot>
724         Returns all repos with names (repo_name file) argv[0] = $EROOT
725         """
726         if len(argv) < 1:
727                 print("ERROR: insufficient parameters!")
728                 return 2
729         print(" ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories()))
730
731 get_repos.uses_eroot = True
732
733 def get_repo_path(argv):
734         """<eroot> <repo_id>+
735         Returns the path to the repo named argv[1], argv[0] = $EROOT
736         """
737         if len(argv) < 2:
738                 print("ERROR: insufficient parameters!")
739                 return 2
740         for arg in argv[1:]:
741                 path = portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg)
742                 if path is None:
743                         path = ""
744                 print(path)
745
746 get_repo_path.uses_eroot = True
747
748 def list_preserved_libs(argv):
749         """<eroot>
750         Print a list of libraries preserved during a package update in the form
751         package: path. Returns 1 if no preserved libraries could be found,
752         0 otherwise.
753         """
754
755         if len(argv) != 1:
756                 print("ERROR: wrong number of arguments")
757                 return 2
758         mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
759         rValue = 1
760         msg = []
761         for cpv in sorted(mylibs):
762                 msg.append(cpv)
763                 for path in mylibs[cpv]:
764                         msg.append(' ' + path)
765                         rValue = 0
766                 msg.append('\n')
767         writemsg_stdout(''.join(msg), noiselevel=-1)
768         return rValue
769 list_preserved_libs.uses_eroot = True
770
771 #-----------------------------------------------------------------------------
772 #
773 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
774 #
775
776 non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'main', 'usage'])
777 commands = sorted(k for k, v in globals().items() \
778         if k not in non_commands and isinstance(v, types.FunctionType) and v.__module__ == "__main__")
779
780 def usage(argv):
781         print(">>> Portage information query tool")
782         print(">>> %s" % portage.VERSION)
783         print(">>> Usage: portageq <command> [<option> ...]")
784         print("")
785         print("Available commands:")
786
787         #
788         # Show our commands -- we do this by scanning the functions in this
789         # file, and formatting each functions documentation.
790         #
791         help_mode = '--help' in sys.argv
792         for name in commands:
793                 # Drop non-functions
794                 obj = globals()[name]
795
796                 doc = obj.__doc__
797                 if (doc == None):
798                         print("   " + name)
799                         print("      MISSING DOCUMENTATION!")
800                         print("")
801                         continue
802
803                 lines = doc.lstrip("\n").split("\n")
804                 print("   " + name + " " + lines[0].strip())
805                 if (len(sys.argv) > 1):
806                         if (not help_mode):
807                                 lines = lines[:-1]
808                         for line in lines[1:]:
809                                 print("      " + line.strip())
810         if (len(sys.argv) == 1):
811                 print("\nRun portageq with --help for info")
812
813 atom_validate_strict = "EBUILD_PHASE" in os.environ
814 eapi = None
815 if atom_validate_strict:
816         eapi = os.environ.get('EAPI')
817
818         def elog(elog_funcname, lines):
819                 cmd = "source '%s/isolated-functions.sh' ; " % \
820                         os.environ["PORTAGE_BIN_PATH"]
821                 for line in lines:
822                         cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
823                 subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
824
825 else:
826         def elog(elog_funcname, lines):
827                 pass
828
829 def main():
830
831         nocolor = os.environ.get('NOCOLOR')
832         if nocolor in ('yes', 'true'):
833                 portage.output.nocolor()
834
835         if len(sys.argv) < 2:
836                 usage(sys.argv)
837                 sys.exit(os.EX_USAGE)
838
839         for x in sys.argv:
840                 if x in ("-h", "--help"):
841                         usage(sys.argv)
842                         sys.exit(os.EX_OK)
843                 elif x == "--version":
844                         print("Portage", portage.VERSION)
845                         sys.exit(os.EX_OK)
846
847         cmd = sys.argv[1]
848         function = globals().get(cmd)
849         if function is None or cmd not in commands:
850                 usage(sys.argv)
851                 sys.exit(os.EX_USAGE)
852         function = globals()[cmd]
853         uses_eroot = getattr(function, "uses_eroot", False) and len(sys.argv) > 2
854         if uses_eroot:
855                 if not os.path.isdir(sys.argv[2]):
856                         sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
857                         sys.stderr.write("Run portageq with --help for info\n")
858                         sys.stderr.flush()
859                         sys.exit(os.EX_USAGE)
860                 eprefix = portage.const.EPREFIX
861                 eroot = portage.util.normalize_path(sys.argv[2])
862
863                 if eprefix:
864                         if not eroot.endswith(eprefix):
865                                 sys.stderr.write("ERROR: This version of portageq"
866                                                  " only supports <eroot>s ending in"
867                                                  " '%s'. The provided <eroot>, '%s',"
868                                                  " doesn't.\n" % (eprefix, eroot));
869                                 sys.stderr.flush()
870                                 sys.exit(os.EX_USAGE)
871                         root = eroot[:1-len(eprefix)]
872                 else:
873                         root = eroot
874
875                 os.environ["ROOT"] = root
876
877         args = sys.argv[2:]
878         if args and isinstance(args[0], bytes):
879                 for i in range(len(args)):
880                         args[i] = portage._unicode_decode(args[i])
881
882         try:
883                 if uses_eroot:
884                         args[0] = portage.settings['EROOT']
885                 retval = function(args)
886                 if retval:
887                         sys.exit(retval)
888         except portage.exception.PermissionDenied as e:
889                 sys.stderr.write("Permission denied: '%s'\n" % str(e))
890                 sys.exit(e.errno)
891         except portage.exception.ParseError as e:
892                 sys.stderr.write("%s\n" % str(e))
893                 sys.exit(1)
894         except portage.exception.AmbiguousPackageName as e:
895                 # Multiple matches thrown from cpv_expand
896                 pkgs = e.args[0]
897                 # An error has occurred so we writemsg to stderr and exit nonzero.
898                 portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
899                 for pkg in pkgs:
900                         portage.writemsg("* %s\n" % pkg, noiselevel=-1)
901                 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
902                 sys.exit(1)
903
904 main()
905
906 #-----------------------------------------------------------------------------