Fix spelling typos in error messages.
[portage.git] / bin / portageq
1 #!/usr/bin/python -O
2 # Copyright 1999-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Id$
5
6 import sys
7 # This block ensures that ^C interrupts are handled quietly.
8 try:
9         import signal
10
11         def exithandler(signum, frame):
12                 signal.signal(signal.SIGINT, signal.SIG_IGN)
13                 signal.signal(signal.SIGTERM, signal.SIG_IGN)
14                 sys.exit(1)
15
16         signal.signal(signal.SIGINT, exithandler)
17         signal.signal(signal.SIGTERM, exithandler)
18
19 except KeyboardInterrupt:
20         sys.exit(1)
21
22 import os
23
24 import types
25
26 #-----------------------------------------------------------------------------
27 #
28 # To add functionality to this tool, add a function below.
29 #
30 # The format for functions is:
31 #
32 #   def function(argv):
33 #       """<list of options for this function>
34 #       <description of the function>
35 #       """
36 #       <code>
37 #
38 # "argv" is an array of the command line parameters provided after the command.
39 #
40 # Make sure you document the function in the right format.  The documentation
41 # is used to display help on the function.
42 #
43 # You do not need to add the function to any lists, this tool is introspective,
44 # and will automaticly add a command by the same name as the function!
45 #
46
47 def has_version(argv):
48         """<root> <category/package>
49         Return code 0 if it's available, 1 otherwise.
50         """
51         if (len(argv) < 2):
52                 print "ERROR: insufficient parameters!"
53                 sys.exit(2)
54         if atom_validate_strict and not portage.isvalidatom(argv[1]):
55                 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
56                         noiselevel=-1)
57                 return 2
58         try:
59                 mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1])
60                 if mylist:
61                         sys.exit(0)
62                 else:
63                         sys.exit(1)
64         except KeyError:
65                 sys.exit(1)
66 has_version.uses_root = True
67
68
69 def best_version(argv):
70         """<root> <category/package>
71         Returns category/package-version (without .ebuild).
72         """
73         if (len(argv) < 2):
74                 print "ERROR: insufficient parameters!"
75                 sys.exit(2)
76         if atom_validate_strict and not portage.isvalidatom(argv[1]):
77                 portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
78                         noiselevel=-1)
79                 return 2
80         try:
81                 mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1])
82                 print portage.best(mylist)
83         except KeyError:
84                 sys.exit(1)
85 best_version.uses_root = True
86
87
88 def mass_best_version(argv):
89         """<root> [<category/package>]+
90         Returns category/package-version (without .ebuild).
91         """
92         if (len(argv) < 2):
93                 print "ERROR: insufficient parameters!"
94                 sys.exit(2)
95         try:
96                 for pack in argv[1:]:
97                         mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
98                         print pack+":"+portage.best(mylist)
99         except KeyError:
100                 sys.exit(1)
101 mass_best_version.uses_root = True
102
103 def metadata(argv):
104         """<root> <pkgtype> <category/package> [<key>]+
105         Returns metadata values for the specified package.
106         """
107         if (len(argv) < 4):
108                 print >> sys.stderr, "ERROR: insufficient parameters!"
109                 sys.exit(2)
110
111         root, pkgtype, pkgspec = argv[0:3]
112         metakeys = argv[3:]
113         type_map = {
114                 "ebuild":"porttree",
115                 "binary":"bintree",
116                 "installed":"vartree"}
117         if pkgtype not in type_map:
118                 print >> sys.stderr, "Unrecognized package type: '%s'" % pkgtype
119                 sys.exit(1)
120         trees = portage.db
121         if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
122                 root = portage.settings["ROOT"] # contains the normalized $ROOT
123         try:
124                         values = trees[root][type_map[pkgtype]].dbapi.aux_get(
125                                 pkgspec, metakeys)
126                         for value in values:
127                                 print value
128         except KeyError:
129                 print >> sys.stderr, "Package not found: '%s'" % pkgspec
130                 sys.exit(1)
131
132 metadata.uses_root = True
133
134 def contents(argv):
135         """<root> <category/package>
136         List the files that are installed for a given package, with
137         one file listed on each line. All file names will begin with
138         <root>.
139         """
140         if len(argv) != 2:
141                 print "ERROR: expected 2 parameters, got %d!" % len(argv)
142                 return 2
143
144         root, cpv = argv
145         vartree = portage.db[root]["vartree"]
146         if not vartree.dbapi.cpv_exists(cpv):
147                 sys.stderr.write("Package not found: '%s'\n" % cpv)
148                 return 1
149         cat, pkg = portage.catsplit(cpv)
150         db = portage.dblink(cat, pkg, root, vartree.settings,
151                 treetype="vartree", vartree=vartree)
152         file_list = db.getcontents().keys()
153         file_list.sort()
154         for f in file_list:
155                 sys.stdout.write("%s\n" % f)
156         sys.stdout.flush()
157 contents.uses_root = True
158
159 def owners(argv):
160         """<root> [<filename>]+
161         Given a list of files, print the packages that own the files and which
162         files belong to each package. Files owned by a package are listed on
163         the lines below it, indented by a single tab character (\\t). All file
164         paths must start with <root>. Returns 1 if no owners could be found,
165         and 0 otherwise.
166         """
167         if len(argv) < 2:
168                 sys.stderr.write("ERROR: insufficient parameters!\n")
169                 sys.stderr.flush()
170                 return 2
171
172         from portage import catsplit, dblink
173         settings = portage.settings
174         root = settings["ROOT"]
175         vardb = portage.db[root]["vartree"].dbapi
176
177         cwd = None
178         try:
179                 cwd = os.getcwd()
180         except OSError:
181                 pass
182
183         files = []
184         for f in argv[1:]:
185                 f = portage.normalize_path(f)
186                 if not f.startswith(os.path.sep):
187                         if cwd is None:
188                                 sys.stderr.write("ERROR: cwd does not exist!\n")
189                                 sys.stderr.flush()
190                                 return 2
191                         f = os.path.join(cwd, f)
192                         f = portage.normalize_path(f)
193                 if not f.startswith(root):
194                         sys.stderr.write("ERROR: file paths must begin with <root>!\n")
195                         sys.stderr.flush()
196                         return 2
197                 files.append(f[len(root):])
198
199         owners = vardb._owners.get_owners(files)
200
201         for pkg, owned_files in owners.iteritems():
202                 cpv = pkg.mycpv
203                 sys.stdout.write("%s\n" % cpv)
204                 for f in sorted(owned_files):
205                         sys.stdout.write("\t%s\n" % \
206                                 os.path.join(root, f.lstrip(os.path.sep)))
207         if owners:
208                 sys.stdout.flush()
209                 return 0
210
211         sys.stderr.write("None of the installed packages claim the file(s).\n")
212         sys.stderr.flush()
213         return 1
214
215 owners.uses_root = True
216
217 def is_protected(argv):
218         """<root> <filename>
219         Given a single filename, return code 0 if it's protected, 1 otherwise.
220         The filename must begin with <root>.
221         """
222         if len(argv) != 2:
223                 sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
224                 sys.stderr.flush()
225                 return 2
226
227         root, filename = argv
228
229         err = sys.stderr
230         cwd = None
231         try:
232                 cwd = os.getcwd()
233         except OSError:
234                 pass
235
236         f = portage.normalize_path(filename)
237         if not f.startswith(os.path.sep):
238                 if cwd is None:
239                         err.write("ERROR: cwd does not exist!\n")
240                         err.flush()
241                         return 2
242                 f = os.path.join(cwd, f)
243                 f = portage.normalize_path(f)
244
245         if not f.startswith(root):
246                 err.write("ERROR: file paths must begin with <root>!\n")
247                 err.flush()
248                 return 2
249
250         import shlex
251         from portage.util import ConfigProtect
252
253         settings = portage.settings
254         protect = shlex.split(settings.get("CONFIG_PROTECT", ""))
255         protect_mask = shlex.split(settings.get("CONFIG_PROTECT_MASK", ""))
256         protect_obj = ConfigProtect(root, protect, protect_mask)
257
258         if protect_obj.isprotected(f):
259                 return 0
260         return 1
261
262 is_protected.uses_root = True
263
264 def filter_protected(argv):
265         """<root>
266         Read filenames from stdin and write them to stdout if they are protected.
267         All filenames are delimited by \\n and must begin with <root>.
268         """
269         if len(argv) != 1:
270                 sys.stderr.write("ERROR: expected 1 parameters, got %d!\n" % len(argv))
271                 sys.stderr.flush()
272                 return 2
273
274         root, = argv
275         out = sys.stdout
276         err = sys.stderr
277         cwd = None
278         try:
279                 cwd = os.getcwd()
280         except OSError:
281                 pass
282
283         import shlex
284         from portage.util import ConfigProtect
285
286         settings = portage.settings
287         protect = shlex.split(settings.get("CONFIG_PROTECT", ""))
288         protect_mask = shlex.split(settings.get("CONFIG_PROTECT_MASK", ""))
289         protect_obj = ConfigProtect(root, protect, protect_mask)
290
291         protected = 0
292         errors = 0
293
294         for line in sys.stdin:
295                 filename = line.rstrip("\n")
296                 f = portage.normalize_path(filename)
297                 if not f.startswith(os.path.sep):
298                         if cwd is None:
299                                 err.write("ERROR: cwd does not exist!\n")
300                                 err.flush()
301                                 errors += 1
302                                 continue
303                         f = os.path.join(cwd, f)
304                         f = portage.normalize_path(f)
305
306                 if not f.startswith(root):
307                         err.write("ERROR: file paths must begin with <root>!\n")
308                         err.flush()
309                         errors += 1
310                         continue
311
312                 if protect_obj.isprotected(f):
313                         protected += 1
314                         out.write("%s\n" % filename)
315         out.flush()
316
317         if errors:
318                 return 2
319
320         return 0
321
322 filter_protected.uses_root = True
323
324 def best_visible(argv):
325         """<root> [<category/package>]+
326         Returns category/package-version (without .ebuild).
327         """
328         if (len(argv) < 2):
329                 print "ERROR: insufficient parameters!"
330                 sys.exit(2)
331         try:
332                 mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1])
333                 visible=portage.best(mylist)
334                 if visible:
335                         print visible
336                         sys.exit(0)
337                 else:
338                         sys.exit(1)
339         except KeyError:
340                 sys.exit(1)
341 best_visible.uses_root = True
342
343
344 def mass_best_visible(argv):
345         """<root> [<category/package>]+
346         Returns category/package-version (without .ebuild).
347         """
348         if (len(argv) < 2):
349                 print "ERROR: insufficient parameters!"
350                 sys.exit(2)
351         try:
352                 for pack in argv[1:]:
353                         mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
354                         print pack+":"+portage.best(mylist)
355         except KeyError:
356                 sys.exit(1)
357 mass_best_visible.uses_root = True
358
359
360 def all_best_visible(argv):
361         """<root>
362         Returns all best_visible packages (without .ebuild).
363         """
364         if (len(argv) < 1):
365                 print "ERROR: insufficient parameters!"
366         
367         #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
368         for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
369                 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
370                 if mybest:
371                         print mybest
372 all_best_visible.uses_root = True
373
374
375 def match(argv):
376         """<root> <atom>
377         Returns a \\n separated list of category/package-version.
378         When given an empty string, all installed packages will
379         be listed.
380         """
381         if len(argv) != 2:
382                 print "ERROR: expected 2 parameters, got %d!" % len(argv)
383                 sys.exit(2)
384         root, atom = argv
385         if atom:
386                 if atom_validate_strict and not portage.isvalidatom(atom):
387                         portage.writemsg("ERROR: Invalid atom: '%s'\n" % atom,
388                                 noiselevel=-1)
389                         return 2
390                 results = portage.db[root]["vartree"].dbapi.match(atom)
391         else:
392                 results = portage.db[root]["vartree"].dbapi.cpv_all()
393                 results.sort()
394         for cpv in results:
395                 print cpv
396 match.uses_root = True
397
398
399 def vdb_path(argv):
400         """
401         Returns the path used for the var(installed) package database for the
402         set environment/configuration options.
403         """
404         out = sys.stdout
405         out.write(os.path.join(portage.settings["ROOT"], portage.VDB_PATH) + "\n")
406         out.flush()
407         return os.EX_OK
408
409 def gentoo_mirrors(argv):
410         """
411         Returns the mirrors set to use in the portage configuration.
412         """
413         print portage.settings["GENTOO_MIRRORS"]
414
415
416 def portdir(argv):
417         """
418         Returns the PORTDIR path.
419         """
420         print portage.settings["PORTDIR"]
421
422
423 def config_protect(argv):
424         """
425         Returns the CONFIG_PROTECT paths.
426         """
427         print portage.settings["CONFIG_PROTECT"]
428
429
430 def config_protect_mask(argv):
431         """
432         Returns the CONFIG_PROTECT_MASK paths.
433         """
434         print portage.settings["CONFIG_PROTECT_MASK"]
435
436
437 def portdir_overlay(argv):
438         """
439         Returns the PORTDIR_OVERLAY path.
440         """
441         print portage.settings["PORTDIR_OVERLAY"]
442
443
444 def pkgdir(argv):
445         """
446         Returns the PKGDIR path.
447         """
448         print portage.settings["PKGDIR"]
449
450
451 def distdir(argv):
452         """
453         Returns the DISTDIR path.
454         """
455         print portage.settings["DISTDIR"]
456
457
458 def envvar(argv):
459         """<variable>+
460         Returns a specific environment variable as exists prior to ebuild.sh.
461         Similar to: emerge --verbose --info | egrep '^<variable>='
462         """
463         verbose = "-v" in argv
464         if verbose:
465                 argv.pop(argv.index("-v"))
466
467         if len(argv) == 0:
468                 print "ERROR: insufficient parameters!"
469                 sys.exit(2)
470
471         for arg in argv:
472                 if verbose:
473                         print arg +"='"+ portage.settings[arg] +"'"
474                 else:
475                         print portage.settings[arg]
476
477 def get_repos(argv):
478         """<root>
479         Returns all repos with names (repo_name file) argv[0] = $ROOT
480         """
481         if len(argv) < 1:
482                 print "ERROR: insufficient parameters!"
483                 sys.exit(2)
484         print " ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories())
485
486 def get_repo_path(argv):
487         """<root> <repo_id>+
488         Returns the path to the repo named argv[1], argv[0] = $ROOT
489         """
490         if len(argv) < 2:
491                 print "ERROR: insufficient parameters!"
492                 sys.exit(2)
493         for arg in argv[1:]:
494                 print portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg)
495
496 def list_preserved_libs(argv):
497         """<root>
498         Print a list of libraries preserved during a package update in the form
499         package: path. Returns 0 if no preserved libraries could be found, 
500         1 otherwise.
501         """
502
503         if len(argv) != 1:
504                 print "ERROR: wrong number of arguments"
505                 sys.exit(2)
506         mylibs = portage.db[argv[0]]["vartree"].dbapi.plib_registry.getPreservedLibs()
507         rValue = 0
508         for cpv in mylibs:
509                 print cpv,
510                 for path in mylibs[cpv]:
511                         print path,
512                         rValue = 1
513                 print
514         return rValue
515 list_preserved_libs.uses_root = True
516
517 #-----------------------------------------------------------------------------
518 #
519 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
520 #
521
522 def usage(argv):
523         print ">>> Portage information query tool"
524         print ">>> $Id$"
525         print ">>> Usage: portageq <command> [<option> ...]"
526         print ""
527         print "Available commands:"
528
529         #
530         # Show our commands -- we do this by scanning the functions in this
531         # file, and formatting each functions documentation.
532         #
533         commands = [x for x in globals() if x not in \
534                                 ("usage", "__doc__", "__name__", "main", "os", "portage", \
535                                 "sys", "__builtins__", "types", "string","exithandler")]
536         commands.sort()
537
538         for name in commands:
539                 # Drop non-functions
540                 obj = globals()[name]
541                 if  (type(obj) != types.FunctionType):
542                         continue
543
544                 doc = obj.__doc__
545                 if (doc == None):
546                         print "   "+name
547                         print "      MISSING DOCUMENTATION!"
548                         print ""
549                         continue
550
551                 lines = doc.split("\n")
552                 print "   "+name+" "+lines[0].strip()
553                 if (len(sys.argv) > 1):
554                         if ("--help" not in sys.argv):
555                                 lines = lines[:-1]
556                         for line in lines[1:]:
557                                 print "      "+line.strip()
558         if (len(sys.argv) == 1):
559                 print "\nRun portageq with --help for info"
560
561 atom_validate_strict = "EBUILD_PHASE" in os.environ
562
563 def main():
564         if "-h" in sys.argv or "--help" in sys.argv:
565                 usage(sys.argv)
566                 sys.exit(os.EX_OK)
567         elif len(sys.argv) < 2:
568                 usage(sys.argv)
569                 sys.exit(os.EX_USAGE)
570
571         cmd = sys.argv[1]
572         function = globals().get(cmd)
573         if function is None:
574                 usage(sys.argv)
575                 sys.exit(os.EX_USAGE)
576         function = globals()[cmd]
577         uses_root = getattr(function, "uses_root", False) and len(sys.argv) > 2
578         if uses_root:
579                 if not os.path.isdir(sys.argv[2]):
580                         sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
581                         sys.stderr.write("Run portageq with --help for info\n")
582                         sys.stderr.flush()
583                         sys.exit(os.EX_USAGE)
584                 os.environ["ROOT"] = sys.argv[2]
585
586         # Avoid sandbox violations after python upgrade.
587         from os import path as osp
588         pym_path = osp.join(osp.dirname(
589                 osp.dirname(osp.realpath(__file__))), "pym")
590         if os.environ.get("SANDBOX_ON") == "1":
591                 sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
592                 if pym_path not in sandbox_write:
593                         sandbox_write.append(pym_path)
594                         os.environ["SANDBOX_WRITE"] = \
595                                 ":".join(filter(None, sandbox_write))
596
597         global portage
598         try:
599                 import portage
600         except ImportError:
601                 sys.path.insert(0, pym_path)
602                 import portage
603
604         try:
605                 if uses_root:
606                         sys.argv[2] = portage.settings["ROOT"]
607                 retval = function(sys.argv[2:])
608                 if retval:
609                         sys.exit(retval)
610         except portage.exception.PermissionDenied, e:
611                 sys.stderr.write("Permission denied: '%s'\n" % str(e))
612                 sys.exit(e.errno)
613         except portage.exception.ParseError, e:
614                 sys.stderr.write("%s\n" % str(e))
615                 sys.exit(1)
616         except ValueError, e:
617                 if not e.args or \
618                         not hasattr(e.args[0], "__len__") or \
619                         len(e.args[0]) < 2:
620                         raise
621                 # Multiple matches thrown from cpv_expand
622                 pkgs = e.args[0]
623                 # An error has occurred so we writemsg to stderr and exit nonzero.
624                 portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
625                 for pkg in pkgs:
626                         portage.writemsg("* %s\n" % pkg, noiselevel=-1)
627                 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
628                 sys.exit(1)
629
630 main()
631
632 #-----------------------------------------------------------------------------