portageq: Delete incorrect usage of uses_eroot decorator for pquery.
[portage.git] / bin / portageq
1 #!/usr/bin/python -O
2 # Copyright 1999-2013 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 from __future__ import print_function, unicode_literals
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 optparse
24 import os
25 import types
26
27 # Avoid sandbox violations after python upgrade.
28 pym_path = os.path.join(os.path.dirname(
29         os.path.dirname(os.path.realpath(__file__))), "pym")
30 if os.environ.get("SANDBOX_ON") == "1":
31         sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
32         if pym_path not in sandbox_write:
33                 sandbox_write.append(pym_path)
34                 os.environ["SANDBOX_WRITE"] = \
35                         ":".join(filter(None, sandbox_write))
36         del sandbox_write
37
38 sys.path.insert(0, pym_path)
39 import portage
40 portage._internal_caller = True
41 from portage import os
42 from portage.eapi import eapi_has_repo_deps
43 from portage.util import writemsg, writemsg_stdout
44 portage.proxy.lazyimport.lazyimport(globals(),
45         're',
46         'subprocess',
47         '_emerge.Package:Package',
48         '_emerge.RootConfig:RootConfig',
49         '_emerge.is_valid_package_atom:insert_category_into_atom',
50         'portage.dbapi._expand_new_virt:expand_new_virt',
51         'portage._sets.base:InternalPackageSet',
52         'portage.xml.metadata:MetaDataXML'
53 )
54
55 def eval_atom_use(atom):
56         if 'USE' in os.environ:
57                 use = frozenset(os.environ['USE'].split())
58                 atom = atom.evaluate_conditionals(use)
59         return atom
60
61 def uses_eroot(function):
62         function.uses_eroot = True
63         return function
64
65 #-----------------------------------------------------------------------------
66 #
67 # To add functionality to this tool, add a function below.
68 #
69 # The format for functions is:
70 #
71 #   def function(argv):
72 #       """<list of options for this function>
73 #       <description of the function>
74 #       """
75 #       <code>
76 #
77 # "argv" is an array of the command line parameters provided after the command.
78 #
79 # Make sure you document the function in the right format.  The documentation
80 # is used to display help on the function.
81 #
82 # You do not need to add the function to any lists, this tool is introspective,
83 # and will automaticly add a command by the same name as the function!
84 #
85
86 @uses_eroot
87 def has_version(argv):
88         """<eroot> <category/package>
89         Return code 0 if it's available, 1 otherwise.
90         """
91         if (len(argv) < 2):
92                 print("ERROR: insufficient parameters!")
93                 return 3
94
95         warnings = []
96
97         allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
98         try:
99                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
100         except portage.exception.InvalidAtom:
101                 if atom_validate_strict:
102                         portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
103                                 noiselevel=-1)
104                         return 2
105                 else:
106                         atom = argv[1]
107         else:
108                 if atom_validate_strict:
109                         try:
110                                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
111                         except portage.exception.InvalidAtom as e:
112                                 warnings.append("QA Notice: %s: %s" % ('has_version', e))
113                 atom = eval_atom_use(atom)
114
115         if warnings:
116                 elog('eqawarn', warnings)
117
118         try:
119                 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
120                 if mylist:
121                         return 0
122                 else:
123                         return 1
124         except KeyError:
125                 return 1
126         except portage.exception.InvalidAtom:
127                 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
128                         noiselevel=-1)
129                 return 2
130
131
132 @uses_eroot
133 def best_version(argv):
134         """<eroot> <category/package>
135         Returns category/package-version (without .ebuild).
136         """
137         if (len(argv) < 2):
138                 print("ERROR: insufficient parameters!")
139                 return 3
140
141         warnings = []
142
143         allow_repo = atom_validate_strict is False or eapi_has_repo_deps(eapi)
144         try:
145                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo)
146         except portage.exception.InvalidAtom:
147                 if atom_validate_strict:
148                         portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
149                                 noiselevel=-1)
150                         return 2
151                 else:
152                         atom = argv[1]
153         else:
154                 if atom_validate_strict:
155                         try:
156                                 atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi)
157                         except portage.exception.InvalidAtom as e:
158                                 warnings.append("QA Notice: %s: %s" % ('best_version', e))
159                 atom = eval_atom_use(atom)
160
161         if warnings:
162                 elog('eqawarn', warnings)
163
164         try:
165                 mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
166                 print(portage.best(mylist))
167         except KeyError:
168                 return 1
169
170
171 @uses_eroot
172 def mass_best_version(argv):
173         """<eroot> [<category/package>]+
174         Returns category/package-version (without .ebuild).
175         """
176         if (len(argv) < 2):
177                 print("ERROR: insufficient parameters!")
178                 return 2
179         try:
180                 for pack in argv[1:]:
181                         mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
182                         print(pack+":"+portage.best(mylist))
183         except KeyError:
184                 return 1
185
186
187 @uses_eroot
188 def metadata(argv):
189         if (len(argv) < 4):
190                 print("ERROR: insufficient parameters!", file=sys.stderr)
191                 return 2
192
193         eroot, pkgtype, pkgspec = argv[0:3]
194         metakeys = argv[3:]
195         type_map = {
196                 "ebuild":"porttree",
197                 "binary":"bintree",
198                 "installed":"vartree"}
199         if pkgtype not in type_map:
200                 print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
201                 return 1
202         trees = portage.db
203         repo = portage.dep.dep_getrepo(pkgspec)
204         pkgspec = portage.dep.remove_slot(pkgspec)
205         try:
206                         values = trees[eroot][type_map[pkgtype]].dbapi.aux_get(
207                                 pkgspec, metakeys, myrepo=repo)
208                         writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
209         except KeyError:
210                 print("Package not found: '%s'" % pkgspec, file=sys.stderr)
211                 return 1
212
213 metadata.__doc__ = """
214 <eroot> <pkgtype> <category/package> [<key>]+
215 Returns metadata values for the specified package.
216 Available keys: %s
217 """  % ','.join(sorted(x for x in portage.auxdbkeys \
218 if not x.startswith('UNUSED_')))
219
220
221 @uses_eroot
222 def contents(argv):
223         """<eroot> <category/package>
224         List the files that are installed for a given package, with
225         one file listed on each line. All file names will begin with
226         <eroot>.
227         """
228         if len(argv) != 2:
229                 print("ERROR: expected 2 parameters, got %d!" % len(argv))
230                 return 2
231
232         root, cpv = argv
233         vartree = portage.db[root]["vartree"]
234         if not vartree.dbapi.cpv_exists(cpv):
235                 sys.stderr.write("Package not found: '%s'\n" % cpv)
236                 return 1
237         cat, pkg = portage.catsplit(cpv)
238         db = portage.dblink(cat, pkg, root, vartree.settings,
239                 treetype="vartree", vartree=vartree)
240         writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
241                 noiselevel=-1)
242
243
244 @uses_eroot
245 def owners(argv):
246         """<eroot> [<filename>]+
247         Given a list of files, print the packages that own the files and which
248         files belong to each package. Files owned by a package are listed on
249         the lines below it, indented by a single tab character (\\t). All file
250         paths must either start with <eroot> or be a basename alone.
251         Returns 1 if no owners could be found, and 0 otherwise.
252         """
253         if len(argv) < 2:
254                 sys.stderr.write("ERROR: insufficient parameters!\n")
255                 sys.stderr.flush()
256                 return 2
257
258         eroot = argv[0]
259         vardb = portage.db[eroot]["vartree"].dbapi
260         root = portage.settings['ROOT']
261
262         cwd = None
263         try:
264                 cwd = os.getcwd()
265         except OSError:
266                 pass
267
268         files = []
269         orphan_abs_paths = set()
270         orphan_basenames = set()
271         for f in argv[1:]:
272                 f = portage.normalize_path(f)
273                 is_basename = os.sep not in f
274                 if not is_basename and f[:1] != os.sep:
275                         if cwd is None:
276                                 sys.stderr.write("ERROR: cwd does not exist!\n")
277                                 sys.stderr.flush()
278                                 return 2
279                         f = os.path.join(cwd, f)
280                         f = portage.normalize_path(f)
281                 if not is_basename and not f.startswith(eroot):
282                         sys.stderr.write("ERROR: file paths must begin with <eroot>!\n")
283                         sys.stderr.flush()
284                         return 2
285                 if is_basename:
286                         files.append(f)
287                         orphan_basenames.add(f)
288                 else:
289                         files.append(f[len(root)-1:])
290                         orphan_abs_paths.add(f)
291
292         owners = vardb._owners.get_owners(files)
293
294         msg = []
295         for pkg, owned_files in owners.items():
296                 cpv = pkg.mycpv
297                 msg.append("%s\n" % cpv)
298                 for f in sorted(owned_files):
299                         f_abs = os.path.join(root, f.lstrip(os.path.sep))
300                         msg.append("\t%s\n" % (f_abs,))
301                         orphan_abs_paths.discard(f_abs)
302                         if orphan_basenames:
303                                 orphan_basenames.discard(os.path.basename(f_abs))
304
305         writemsg_stdout(''.join(msg), noiselevel=-1)
306
307         if orphan_abs_paths or orphan_basenames:
308                 orphans = []
309                 orphans.extend(orphan_abs_paths)
310                 orphans.extend(orphan_basenames)
311                 orphans.sort()
312                 msg = []
313                 msg.append("None of the installed packages claim these files:\n")
314                 for f in orphans:
315                         msg.append("\t%s\n" % (f,))
316                 sys.stderr.write("".join(msg))
317                 sys.stderr.flush()
318
319         if owners:
320                 return 0
321         return 1
322
323
324 @uses_eroot
325 def is_protected(argv):
326         """<eroot> <filename>
327         Given a single filename, return code 0 if it's protected, 1 otherwise.
328         The filename must begin with <eroot>.
329         """
330         if len(argv) != 2:
331                 sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
332                 sys.stderr.flush()
333                 return 2
334
335         root, filename = argv
336
337         err = sys.stderr
338         cwd = None
339         try:
340                 cwd = os.getcwd()
341         except OSError:
342                 pass
343
344         f = portage.normalize_path(filename)
345         if not f.startswith(os.path.sep):
346                 if cwd is None:
347                         err.write("ERROR: cwd does not exist!\n")
348                         err.flush()
349                         return 2
350                 f = os.path.join(cwd, f)
351                 f = portage.normalize_path(f)
352
353         if not f.startswith(root):
354                 err.write("ERROR: file paths must begin with <eroot>!\n")
355                 err.flush()
356                 return 2
357
358         from portage.util import ConfigProtect
359
360         settings = portage.settings
361         protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
362         protect_mask = portage.util.shlex_split(
363                 settings.get("CONFIG_PROTECT_MASK", ""))
364         protect_obj = ConfigProtect(root, protect, protect_mask)
365
366         if protect_obj.isprotected(f):
367                 return 0
368         return 1
369
370
371 @uses_eroot
372 def filter_protected(argv):
373         """<eroot>
374         Read filenames from stdin and write them to stdout if they are protected.
375         All filenames are delimited by \\n and must begin with <eroot>.
376         """
377         if len(argv) != 1:
378                 sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
379                 sys.stderr.flush()
380                 return 2
381
382         root, = argv
383         out = sys.stdout
384         err = sys.stderr
385         cwd = None
386         try:
387                 cwd = os.getcwd()
388         except OSError:
389                 pass
390
391         from portage.util import ConfigProtect
392
393         settings = portage.settings
394         protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
395         protect_mask = portage.util.shlex_split(
396                 settings.get("CONFIG_PROTECT_MASK", ""))
397         protect_obj = ConfigProtect(root, protect, protect_mask)
398
399         protected = 0
400         errors = 0
401
402         for line in sys.stdin:
403                 filename = line.rstrip("\n")
404                 f = portage.normalize_path(filename)
405                 if not f.startswith(os.path.sep):
406                         if cwd is None:
407                                 err.write("ERROR: cwd does not exist!\n")
408                                 err.flush()
409                                 errors += 1
410                                 continue
411                         f = os.path.join(cwd, f)
412                         f = portage.normalize_path(f)
413
414                 if not f.startswith(root):
415                         err.write("ERROR: file paths must begin with <eroot>!\n")
416                         err.flush()
417                         errors += 1
418                         continue
419
420                 if protect_obj.isprotected(f):
421                         protected += 1
422                         out.write("%s\n" % filename)
423         out.flush()
424
425         if errors:
426                 return 2
427
428         return 0
429
430
431 @uses_eroot
432 def best_visible(argv):
433         """<eroot> [pkgtype] <atom>
434         Returns category/package-version (without .ebuild).
435         The pkgtype argument defaults to "ebuild" if unspecified,
436         otherwise it must be one of ebuild, binary, or installed.
437         """
438         if (len(argv) < 2):
439                 writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
440                 return 2
441
442         pkgtype = "ebuild"
443         if len(argv) > 2:
444                 pkgtype = argv[1]
445                 atom = argv[2]
446         else:
447                 atom = argv[1]
448
449         type_map = {
450                 "ebuild":"porttree",
451                 "binary":"bintree",
452                 "installed":"vartree"}
453
454         if pkgtype not in type_map:
455                 writemsg("Unrecognized package type: '%s'\n" % pkgtype,
456                         noiselevel=-1)
457                 return 2
458
459         eroot = argv[0]
460         db = portage.db[eroot][type_map[pkgtype]].dbapi
461
462         try:
463                 atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
464         except portage.exception.InvalidAtom:
465                 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
466                         noiselevel=-1)
467                 return 2
468
469         root_config = RootConfig(portage.settings,
470                 portage.db[eroot], None)
471
472         if hasattr(db, "xmatch"):
473                 cpv_list = db.xmatch("match-all-cpv-only", atom)
474         else:
475                 cpv_list = db.match(atom)
476
477         if cpv_list:
478                 # reversed, for descending order
479                 cpv_list.reverse()
480                 # verify match, since the atom may match the package
481                 # for a given cpv from one repo but not another, and
482                 # we can use match-all-cpv-only to avoid redundant
483                 # metadata access.
484                 atom_set = InternalPackageSet(initial_atoms=(atom,))
485
486                 if atom.repo is None and hasattr(db, "getRepositories"):
487                         repo_list = db.getRepositories()
488                 else:
489                         repo_list = [atom.repo]
490
491                 for cpv in cpv_list:
492                         for repo in repo_list:
493                                 try:
494                                         metadata = dict(zip(Package.metadata_keys,
495                                                 db.aux_get(cpv, Package.metadata_keys, myrepo=repo)))
496                                 except KeyError:
497                                         continue
498                                 pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
499                                         installed=(pkgtype=="installed"), metadata=metadata,
500                                         root_config=root_config, type_name=pkgtype)
501                                 if not atom_set.findAtomForPackage(pkg):
502                                         continue
503
504                                 if pkg.visible:
505                                         writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
506                                         return os.EX_OK
507
508         # No package found, write out an empty line.
509         writemsg_stdout("\n", noiselevel=-1)
510
511         return 1
512
513
514 @uses_eroot
515 def mass_best_visible(argv):
516         """<eroot> [<type>] [<category/package>]+
517         Returns category/package-version (without .ebuild).
518         The pkgtype argument defaults to "ebuild" if unspecified,
519         otherwise it must be one of ebuild, binary, or installed.
520         """
521         type_map = {
522                 "ebuild":"porttree",
523                 "binary":"bintree",
524                 "installed":"vartree"}
525
526         if (len(argv) < 2):
527                 print("ERROR: insufficient parameters!")
528                 return 2
529         try:
530                 root = argv.pop(0)
531                 pkgtype = "ebuild"
532                 if argv[0] in type_map:
533                         pkgtype = argv.pop(0)
534                 for pack in argv:
535                         writemsg_stdout("%s:" % pack, noiselevel=-1)
536                         best_visible([root, pkgtype, pack])
537         except KeyError:
538                 return 1
539
540
541 @uses_eroot
542 def all_best_visible(argv):
543         """<eroot>
544         Returns all best_visible packages (without .ebuild).
545         """
546         if len(argv) < 1:
547                 sys.stderr.write("ERROR: insufficient parameters!\n")
548                 sys.stderr.flush()
549                 return 2
550
551         #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
552         for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
553                 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
554                 if mybest:
555                         print(mybest)
556
557
558 @uses_eroot
559 def match(argv):
560         """<eroot> <atom>
561         Returns a \\n separated list of category/package-version.
562         When given an empty string, all installed packages will
563         be listed.
564         """
565         if len(argv) != 2:
566                 print("ERROR: expected 2 parameters, got %d!" % len(argv))
567                 return 2
568         root, atom = argv
569         if not atom:
570                 atom = "*/*"
571
572         vardb = portage.db[root]["vartree"].dbapi
573         try:
574                 atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
575         except portage.exception.InvalidAtom:
576                 # maybe it's valid but missing category
577                 atom = portage.dep_expand(atom, mydb=vardb, settings=vardb.settings)
578
579         if atom.extended_syntax:
580                 if atom == "*/*":
581                         results = vardb.cpv_all()
582                 else:
583                         results = []
584                         require_metadata = atom.slot or atom.repo
585                         for cpv in vardb.cpv_all():
586
587                                 if not portage.match_from_list(atom, [cpv]):
588                                         continue
589
590                                 if require_metadata:
591                                         try:
592                                                 cpv = vardb._pkg_str(cpv, atom.repo)
593                                         except (KeyError, portage.exception.InvalidData):
594                                                 continue
595                                         if not portage.match_from_list(atom, [cpv]):
596                                                 continue
597
598                                 results.append(cpv)
599
600                 results.sort()
601         else:
602                 results = vardb.match(atom)
603         for cpv in results:
604                 print(cpv)
605
606
607 @uses_eroot
608 def expand_virtual(argv):
609         """<eroot> <atom>
610         Returns a \\n separated list of atoms expanded from a
611         given virtual atom (GLEP 37 virtuals only),
612         excluding blocker atoms. Satisfied
613         virtual atoms are not included in the output, since
614         they are expanded to real atoms which are displayed.
615         Unsatisfied virtual atoms are displayed without
616         any expansion. The "match" command can be used to
617         resolve the returned atoms to specific installed
618         packages.
619         """
620         if len(argv) != 2:
621                 writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
622                         noiselevel=-1)
623                 return 2
624
625         root, atom = argv
626
627         try:
628                 results = list(expand_new_virt(
629                         portage.db[root]["vartree"].dbapi, atom))
630         except portage.exception.InvalidAtom:
631                 writemsg("ERROR: Invalid atom: '%s'\n" % atom,
632                         noiselevel=-1)
633                 return 2
634
635         results.sort()
636         for x in results:
637                 if not x.blocker:
638                         writemsg_stdout("%s\n" % (x,))
639
640         return os.EX_OK
641
642
643 def vdb_path(argv):
644         """
645         Returns the path used for the var(installed) package database for the
646         set environment/configuration options.
647         """
648         out = sys.stdout
649         out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
650         out.flush()
651         return os.EX_OK
652
653 def gentoo_mirrors(argv):
654         """
655         Returns the mirrors set to use in the portage configuration.
656         """
657         print(portage.settings["GENTOO_MIRRORS"])
658
659
660 @uses_eroot
661 def repositories_configuration(argv):
662         """<eroot>
663         Returns the configuration of repositories.
664         """
665         if len(argv) < 1:
666                 print("ERROR: insufficient parameters!", file=sys.stderr)
667                 return 3
668         sys.stdout.write(portage.db[argv[0]]["vartree"].settings.repositories.config_string())
669         sys.stdout.flush()
670
671
672 def portdir(argv):
673         """
674         Returns the PORTDIR path.
675         """
676         print(portage.settings["PORTDIR"])
677
678
679 def config_protect(argv):
680         """
681         Returns the CONFIG_PROTECT paths.
682         """
683         print(portage.settings["CONFIG_PROTECT"])
684
685
686 def config_protect_mask(argv):
687         """
688         Returns the CONFIG_PROTECT_MASK paths.
689         """
690         print(portage.settings["CONFIG_PROTECT_MASK"])
691
692
693 def portdir_overlay(argv):
694         """
695         Returns the PORTDIR_OVERLAY path.
696         """
697         print(portage.settings["PORTDIR_OVERLAY"])
698
699
700 def pkgdir(argv):
701         """
702         Returns the PKGDIR path.
703         """
704         print(portage.settings["PKGDIR"])
705
706
707 def distdir(argv):
708         """
709         Returns the DISTDIR path.
710         """
711         print(portage.settings["DISTDIR"])
712
713
714 def colormap(argv):
715         """
716         Display the color.map as environment variables.
717         """
718         print(portage.output.colormap())
719
720
721 def envvar(argv):
722         """<variable>+
723         Returns a specific environment variable as exists prior to ebuild.sh.
724         Similar to: emerge --verbose --info | egrep '^<variable>='
725         """
726         verbose = "-v" in argv
727         if verbose:
728                 argv.pop(argv.index("-v"))
729
730         if len(argv) == 0:
731                 print("ERROR: insufficient parameters!")
732                 return 2
733
734         for arg in argv:
735                 if verbose:
736                         print(arg +"='"+ portage.settings[arg] +"'")
737                 else:
738                         print(portage.settings[arg])
739
740
741 @uses_eroot
742 def get_repos(argv):
743         """<eroot>
744         Returns all repos with names (repo_name file) argv[0] = $EROOT
745         """
746         if len(argv) < 1:
747                 print("ERROR: insufficient parameters!")
748                 return 2
749         print(" ".join(reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order)))
750
751
752 @uses_eroot
753 def master_repositories(argv):
754         """<eroot> <repo_id>+
755         Returns space-separated list of master repositories for specified repository.
756         """
757         if len(argv) < 2:
758                 print("ERROR: insufficient parameters!", file=sys.stderr)
759                 return 3
760         for arg in argv[1:]:
761                 if portage.dep._repo_name_re.match(arg) is None:
762                         print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
763                         return 2
764                 try:
765                         repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
766                 except KeyError:
767                         print("")
768                         return 1
769                 else:
770                         print(" ".join(x.name for x in repo.masters))
771
772
773 @uses_eroot
774 def get_repo_path(argv):
775         """<eroot> <repo_id>+
776         Returns the path to the repo named argv[1], argv[0] = $EROOT
777         """
778         if len(argv) < 2:
779                 print("ERROR: insufficient parameters!", file=sys.stderr)
780                 return 3
781         for arg in argv[1:]:
782                 if portage.dep._repo_name_re.match(arg) is None:
783                         print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
784                         return 2
785                 path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg)
786                 if path is None:
787                         print("")
788                         return 1
789                 print(path)
790
791
792 @uses_eroot
793 def available_eclasses(argv):
794         """<eroot> <repo_id>+
795         Returns space-separated list of available eclasses for specified repository.
796         """
797         if len(argv) < 2:
798                 print("ERROR: insufficient parameters!", file=sys.stderr)
799                 return 3
800         for arg in argv[1:]:
801                 if portage.dep._repo_name_re.match(arg) is None:
802                         print("ERROR: invalid repository: %s" % arg, file=sys.stderr)
803                         return 2
804                 try:
805                         repo = portage.db[argv[0]]["vartree"].settings.repositories[arg]
806                 except KeyError:
807                         print("")
808                         return 1
809                 else:
810                         print(" ".join(sorted(repo.eclass_db.eclasses)))
811
812
813 @uses_eroot
814 def eclass_path(argv):
815         """<eroot> <repo_id> <eclass>+
816         Returns the path to specified eclass for specified repository.
817         """
818         if len(argv) < 3:
819                 print("ERROR: insufficient parameters!", file=sys.stderr)
820                 return 3
821         if portage.dep._repo_name_re.match(argv[1]) is None:
822                 print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
823                 return 2
824         try:
825                 repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
826         except KeyError:
827                 print("")
828                 return 1
829         else:
830                 retval = 0
831                 for arg in argv[2:]:
832                         try:
833                                 eclass = repo.eclass_db.eclasses[arg]
834                         except KeyError:
835                                 print("")
836                                 retval = 1
837                         else:
838                                 print(eclass.location)
839                 return retval
840
841
842 @uses_eroot
843 def license_path(argv):
844         """<eroot> <repo_id> <license>+
845         Returns the path to specified license for specified repository.
846         """
847         if len(argv) < 3:
848                 print("ERROR: insufficient parameters!", file=sys.stderr)
849                 return 3
850         if portage.dep._repo_name_re.match(argv[1]) is None:
851                 print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr)
852                 return 2
853         try:
854                 repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]]
855         except KeyError:
856                 print("")
857                 return 1
858         else:
859                 retval = 0
860                 for arg in argv[2:]:
861                         eclass_path = ""
862                         paths = reversed([os.path.join(x.location, 'licenses', arg) for x in list(repo.masters) + [repo]])
863                         for path in paths:
864                                 if os.path.exists(path):
865                                         eclass_path = path
866                                         break
867                         if eclass_path == "":
868                                 retval = 1
869                         print(eclass_path)
870                 return retval
871
872
873 @uses_eroot
874 def list_preserved_libs(argv):
875         """<eroot>
876         Print a list of libraries preserved during a package update in the form
877         package: path. Returns 1 if no preserved libraries could be found,
878         0 otherwise.
879         """
880
881         if len(argv) != 1:
882                 print("ERROR: wrong number of arguments")
883                 return 2
884         mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
885         rValue = 1
886         msg = []
887         for cpv in sorted(mylibs):
888                 msg.append(cpv)
889                 for path in mylibs[cpv]:
890                         msg.append(' ' + path)
891                         rValue = 0
892                 msg.append('\n')
893         writemsg_stdout(''.join(msg), noiselevel=-1)
894         return rValue
895
896
897 class MaintainerEmailMatcher(object):
898         def __init__(self, maintainer_emails):
899                 self._re = re.compile("^(%s)$" % "|".join(maintainer_emails))
900
901         def __call__(self, metadata_xml):
902                 match = False
903                 matcher = self._re.match
904                 for x in metadata_xml.maintainers():
905                         if x.email is not None and matcher(x.email) is not None:
906                                 match = True
907                                 break
908                 return match
909
910 class HerdMatcher(object):
911         def __init__(self, herds):
912                 self._herds = frozenset(herds)
913
914         def __call__(self, metadata_xml):
915                 herds = self._herds
916                 return any(x in herds for x in metadata_xml.herds())
917
918
919 def pquery(parser, pquery_option_groups, opts, args):
920         """[options] [atom]+
921         Emulates a subset of Pkgcore's pquery tool.
922         """
923
924         portdb = portage.db[portage.root]['porttree'].dbapi
925         root_config = RootConfig(portdb.settings,
926                 portage.db[portage.root], None)
927
928         def _pkg(cpv, repo_name):
929                 try:
930                         metadata = dict(zip(
931                                 Package.metadata_keys,
932                                 portdb.aux_get(cpv,
933                                 Package.metadata_keys,
934                                 myrepo=repo_name)))
935                 except KeyError:
936                         raise portage.exception.PackageNotFound(cpv)
937                 return Package(built=False, cpv=cpv,
938                         installed=False, metadata=metadata,
939                         root_config=root_config,
940                         type_name="ebuild")
941
942         need_metadata = False
943         atoms = []
944         for arg in args:
945                 if "/" not in arg.split(":")[0]:
946                         atom = insert_category_into_atom(arg, '*')
947                         if atom is None:
948                                 writemsg("ERROR: Invalid atom: '%s'\n" % arg,
949                                         noiselevel=-1)
950                                 return 2
951                 else:
952                         atom = arg
953
954                 try:
955                         atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True)
956                 except portage.exception.InvalidAtom:
957                         writemsg("ERROR: Invalid atom: '%s'\n" % arg,
958                                 noiselevel=-1)
959                         return 2
960
961                 if atom.slot is not None:
962                         need_metadata = True
963
964                 atoms.append(atom)
965
966         if "*/*" in atoms:
967                 del atoms[:]
968                 need_metadata = False
969
970         if not opts.no_filters:
971                 need_metadata = True
972
973         xml_matchers = []
974         if opts.maintainer_email:
975                 maintainer_emails = []
976                 for x in opts.maintainer_email:
977                         maintainer_emails.extend(x.split(","))
978                 xml_matchers.append(MaintainerEmailMatcher(maintainer_emails))
979         if opts.herd is not None:
980                 herds  = []
981                 for x in opts.herd:
982                         herds.extend(x.split(","))
983                 xml_matchers.append(HerdMatcher(herds))
984
985         repos = []
986         if opts.all_repos:
987                 repos.extend(portdb.repositories.get_repo_for_location(location)
988                         for location in portdb.porttrees)
989         elif opts.repo is not None:
990                 repos.append(portdb.repositories[opts.repo])
991         else:
992                 repos.append(portdb.repositories.mainRepo())
993
994         if not atoms:
995                 names = None
996                 categories = list(portdb.categories)
997         else:
998                 category_wildcard = False
999                 name_wildcard = False
1000                 categories = []
1001                 names = []
1002                 for atom in atoms:
1003                         category, name = portage.catsplit(atom.cp)
1004                         categories.append(category)
1005                         names.append(name)
1006                         if "*" in category:
1007                                 category_wildcard = True
1008                         if "*" in name:
1009                                 name_wildcard = True
1010
1011                 if category_wildcard:
1012                         categories = list(portdb.categories)
1013                 else:
1014                         categories = list(set(categories))
1015
1016                 if name_wildcard:
1017                         names = None
1018                 else:
1019                         names = sorted(set(names))
1020
1021         no_version = opts.no_version
1022         categories.sort()
1023
1024         for category in categories:
1025                 if names is None:
1026                         cp_list = portdb.cp_all(categories=(category,))
1027                 else:
1028                         cp_list = [category + "/" + name for name in names]
1029                 for cp in cp_list:
1030                         matches = []
1031                         for repo in repos:
1032                                 match = True
1033                                 if xml_matchers:
1034                                         metadata_xml_path = os.path.join(
1035                                                 repo.location, cp, 'metadata.xml')
1036                                         try:
1037                                                 metadata_xml = MetaDataXML(metadata_xml_path, None)
1038                                         except (EnvironmentError, SyntaxError):
1039                                                 match = False
1040                                         else:
1041                                                 for matcher in xml_matchers:
1042                                                         if not matcher(metadata_xml):
1043                                                                 match = False
1044                                                                 break
1045                                 if not match:
1046                                         continue
1047                                 cpv_list = portdb.cp_list(cp, mytree=[repo.location])
1048                                 if atoms:
1049                                         for cpv in cpv_list:
1050                                                 pkg = None
1051                                                 for atom in atoms:
1052                                                         if atom.repo is not None and \
1053                                                                 atom.repo != repo.name:
1054                                                                 continue
1055                                                         if not portage.match_from_list(atom, [cpv]):
1056                                                                 continue
1057                                                         if need_metadata:
1058                                                                 if pkg is None:
1059                                                                         try:
1060                                                                                 pkg = _pkg(cpv, repo.name)
1061                                                                         except portage.exception.PackageNotFound:
1062                                                                                 continue
1063
1064                                                                 if not (opts.no_filters or pkg.visible):
1065                                                                         continue
1066                                                                 if not portage.match_from_list(atom, [pkg]):
1067                                                                         continue
1068                                                         matches.append(cpv)
1069                                                         break
1070                                                 if no_version and matches:
1071                                                         break
1072                                 elif opts.no_filters:
1073                                         matches.extend(cpv_list)
1074                                 else:
1075                                         for cpv in cpv_list:
1076                                                 try:
1077                                                         pkg = _pkg(cpv, repo.name)
1078                                                 except portage.exception.PackageNotFound:
1079                                                         continue
1080                                                 else:
1081                                                         if pkg.visible:
1082                                                                 matches.append(cpv)
1083                                                                 if no_version:
1084                                                                         break
1085
1086                                 if no_version and matches:
1087                                         break
1088
1089                         if not matches:
1090                                 continue
1091
1092                         if no_version:
1093                                 writemsg_stdout("%s\n" % (cp,), noiselevel=-1)
1094                         else:
1095                                 matches = list(set(matches))
1096                                 portdb._cpv_sort_ascending(matches)
1097                                 for cpv in matches:
1098                                         writemsg_stdout("%s\n" % (cpv,), noiselevel=-1)
1099
1100         return os.EX_OK
1101
1102
1103 #-----------------------------------------------------------------------------
1104 #
1105 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
1106 #
1107
1108 non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'main', 'usage', 'uses_eroot'])
1109 commands = sorted(k for k, v in globals().items() \
1110         if k not in non_commands and isinstance(v, types.FunctionType) and v.__module__ == "__main__")
1111
1112 def usage(argv, parser=None, pquery_option_groups=None):
1113         print(">>> Portage information query tool")
1114         print(">>> %s" % portage.VERSION)
1115         print(">>> Usage: portageq <command> [<option> ...]")
1116         print("")
1117         print("Available commands:")
1118
1119         #
1120         # Show our commands -- we do this by scanning the functions in this
1121         # file, and formatting each functions documentation.
1122         #
1123         help_mode = '--help' in argv
1124         for name in commands:
1125                 # Drop non-functions
1126                 obj = globals()[name]
1127
1128                 doc = obj.__doc__
1129                 if (doc == None):
1130                         print("   " + name)
1131                         print("      MISSING DOCUMENTATION!")
1132                         print("")
1133                         continue
1134
1135                 lines = doc.lstrip("\n").split("\n")
1136                 print("   " + name + " " + lines[0].strip())
1137                 if len(argv) > 1:
1138                         if (not help_mode):
1139                                 lines = lines[:-1]
1140                         for line in lines[1:]:
1141                                 print("      " + line.strip())
1142
1143         if pquery_option_groups is not None:
1144                 parser.formatter.store_option_strings(parser)
1145                 print()
1146                 print('Pkgcore pquery compatible options:')
1147                 print()
1148                 for optgroup in pquery_option_groups:
1149                         print(optgroup.format_help(parser.formatter))
1150
1151         if len(argv) == 1:
1152                 print("\nRun portageq with --help for info")
1153
1154 atom_validate_strict = "EBUILD_PHASE" in os.environ
1155 eapi = None
1156 if atom_validate_strict:
1157         eapi = os.environ.get('EAPI')
1158
1159         def elog(elog_funcname, lines):
1160                 cmd = "source '%s/isolated-functions.sh' ; " % \
1161                         os.environ["PORTAGE_BIN_PATH"]
1162                 for line in lines:
1163                         cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
1164                 subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
1165
1166 else:
1167         def elog(elog_funcname, lines):
1168                 pass
1169
1170 def main(argv):
1171
1172         argv = portage._decode_argv(argv)
1173
1174         nocolor = os.environ.get('NOCOLOR')
1175         if nocolor in ('yes', 'true'):
1176                 portage.output.nocolor()
1177
1178         parser = optparse.OptionParser(add_help_option=False)
1179
1180         # used by envvar
1181         parser.add_option("-v", dest="verbose", action="store_true")
1182
1183         actions = optparse.OptionGroup(parser, 'Actions')
1184         actions.add_option("-h", "--help", action="store_true")
1185         actions.add_option("--version", action="store_true")
1186         parser.add_option_group(actions)
1187
1188         pquery_option_groups = []
1189
1190         repo_optgroup = optparse.OptionGroup(parser,
1191                 'Repository matching options')
1192         repo_optgroup.add_option("--no-filters", action="store_true",
1193                 help="no visibility filters (ACCEPT_KEYWORDS, package masking, etc)")
1194         repo_optgroup.add_option("--repo", action="store",
1195                 help="repo to use (default is PORTDIR if omitted)")
1196         repo_optgroup.add_option("--all-repos", action="store_true",
1197                 help="search all repos")
1198         parser.add_option_group(repo_optgroup)
1199         pquery_option_groups.append(repo_optgroup)
1200
1201         matching_optgroup = optparse.OptionGroup(parser,
1202                 'Package matching options')
1203         matching_optgroup.add_option("--herd", action="append",
1204                 help="exact match on a herd")
1205         matching_optgroup.add_option("--maintainer-email", action="append",
1206                 help="comma-separated list of maintainer email regexes to search for")
1207         parser.add_option_group(matching_optgroup)
1208         pquery_option_groups.append(matching_optgroup)
1209
1210         formatting_optgroup = optparse.OptionGroup(parser,
1211                 'Output formatting')
1212         formatting_optgroup.add_option("-n", "--no-version", action="store_true",
1213                 help="collapse multiple matching versions together")
1214         parser.add_option_group(formatting_optgroup)
1215         pquery_option_groups.append(formatting_optgroup)
1216
1217         opts, args = parser.parse_args(argv[1:])
1218
1219         if opts.help:
1220                 usage(argv, parser=parser, pquery_option_groups=pquery_option_groups)
1221                 return os.EX_OK
1222         elif opts.version:
1223                 print("Portage", portage.VERSION)
1224                 return os.EX_OK
1225
1226         cmd = None
1227         if args and args[0] in commands:
1228                 cmd = args[0]
1229
1230         if cmd == 'pquery':
1231                 cmd = None
1232                 args = args[1:]
1233
1234         if cmd is None:
1235                 return pquery(parser, pquery_option_groups, opts, args)
1236
1237         if opts.verbose:
1238                 # used by envvar
1239                 args.append("-v")
1240
1241         argv = argv[:1] + args
1242
1243         if len(argv) < 2:
1244                 usage(argv)
1245                 sys.exit(os.EX_USAGE)
1246
1247         function = globals()[cmd]
1248         uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2
1249         if uses_eroot:
1250                 if not os.path.isdir(argv[2]):
1251                         sys.stderr.write("Not a directory: '%s'\n" % argv[2])
1252                         sys.stderr.write("Run portageq with --help for info\n")
1253                         sys.stderr.flush()
1254                         sys.exit(os.EX_USAGE)
1255                 eprefix = portage.settings["EPREFIX"]
1256                 eroot = portage.util.normalize_path(argv[2])
1257
1258                 if eprefix:
1259                         if not eroot.endswith(eprefix):
1260                                 sys.stderr.write("ERROR: This version of portageq"
1261                                                  " only supports <eroot>s ending in"
1262                                                  " '%s'. The provided <eroot>, '%s',"
1263                                                  " doesn't.\n" % (eprefix, eroot));
1264                                 sys.stderr.flush()
1265                                 sys.exit(os.EX_USAGE)
1266                         root = eroot[:1-len(eprefix)]
1267                 else:
1268                         root = eroot
1269
1270                 os.environ["ROOT"] = root
1271
1272         args = argv[2:]
1273
1274         try:
1275                 if uses_eroot:
1276                         args[0] = portage.settings['EROOT']
1277                 retval = function(args)
1278                 if retval:
1279                         sys.exit(retval)
1280         except portage.exception.PermissionDenied as e:
1281                 sys.stderr.write("Permission denied: '%s'\n" % str(e))
1282                 sys.exit(e.errno)
1283         except portage.exception.ParseError as e:
1284                 sys.stderr.write("%s\n" % str(e))
1285                 sys.exit(1)
1286         except portage.exception.AmbiguousPackageName as e:
1287                 # Multiple matches thrown from cpv_expand
1288                 pkgs = e.args[0]
1289                 # An error has occurred so we writemsg to stderr and exit nonzero.
1290                 portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
1291                 for pkg in pkgs:
1292                         portage.writemsg("* %s\n" % pkg, noiselevel=-1)
1293                 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
1294                 sys.exit(1)
1295
1296 if __name__ == '__main__':
1297         sys.exit(main(sys.argv))
1298
1299 #-----------------------------------------------------------------------------