Bug #211949 - As suggested by vapier, tighten the variable filter to also
[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         try:
55                 mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1])
56                 if mylist:
57                         sys.exit(0)
58                 else:
59                         sys.exit(1)
60         except KeyError:
61                 sys.exit(1)
62 has_version.uses_root = True
63
64
65 def best_version(argv):
66         """<root> <category/package>
67         Returns category/package-version (without .ebuild).
68         """
69         if (len(argv) < 2):
70                 print "ERROR: insufficient parameters!"
71                 sys.exit(2)
72         try:
73                 mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1])
74                 print portage.best(mylist)
75         except KeyError:
76                 sys.exit(1)
77 best_version.uses_root = True
78
79
80 def mass_best_version(argv):
81         """<root> [<category/package>]+
82         Returns category/package-version (without .ebuild).
83         """
84         if (len(argv) < 2):
85                 print "ERROR: insufficient parameters!"
86                 sys.exit(2)
87         try:
88                 for pack in argv[1:]:
89                         mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
90                         print pack+":"+portage.best(mylist)
91         except KeyError:
92                 sys.exit(1)
93 mass_best_version.uses_root = True
94
95 def metadata(argv):
96         """<root> <pkgtype> <category/package> [<key>]+
97         Returns metadata values for the specified package.
98         """
99         if (len(argv) < 4):
100                 print >> sys.stderr, "ERROR: insufficient parameters!"
101                 sys.exit(2)
102
103         root, pkgtype, pkgspec = argv[0:3]
104         metakeys = argv[3:]
105         type_map = {
106                 "ebuild":"porttree",
107                 "binary":"bintree",
108                 "installed":"vartree"}
109         if pkgtype not in type_map:
110                 print >> sys.stderr, "Unrecognized package type: '%s'" % pkgtype
111                 sys.exit(1)
112         trees = portage.db
113         if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
114                 root = portage.settings["ROOT"] # contains the normalized $ROOT
115         try:
116                         values = trees[root][type_map[pkgtype]].dbapi.aux_get(
117                                 pkgspec, metakeys)
118                         for value in values:
119                                 print value
120         except KeyError:
121                 print >> sys.stderr, "Package not found: '%s'" % pkgspec
122                 sys.exit(1)
123
124 metadata.uses_root = True
125
126 def contents(argv):
127         """<root> <category/package>
128         List the files that are installed for a given package, with
129         one file listed on each line. All file names will begin with
130         <root>.
131         """
132         if len(argv) != 2:
133                 print "ERROR: expected 2 parameters, got %d!" % len(argv)
134                 return 2
135
136         root, cpv = argv
137         vartree = portage.db[root]["vartree"]
138         if not vartree.dbapi.cpv_exists(cpv):
139                 sys.stderr.write("Package not found: '%s'\n" % cpv)
140                 return 1
141         cat, pkg = portage.catsplit(cpv)
142         db = portage.dblink(cat, pkg, root, vartree.settings,
143                 treetype="vartree", vartree=vartree)
144         file_list = db.getcontents().keys()
145         file_list.sort()
146         for f in file_list:
147                 sys.stdout.write("%s\n" % f)
148         sys.stdout.flush()
149 contents.uses_root = True
150
151 def owners(argv):
152         """<root> [<filename>]+
153         Given a list of files, print the packages that own the files and which
154         files belong to each package. Files owned by a package are listed on
155         the lines below it, indented by a single tab character (\\t). All file
156         paths must start with <root>. Returns 1 if no owners could be found,
157         and 0 otherwise.
158         """
159         if len(argv) < 2:
160                 sys.stderr.write("ERROR: insufficient parameters!\n")
161                 sys.stderr.flush()
162                 return 2
163
164         from portage import catsplit, dblink
165         settings = portage.settings
166         root = settings["ROOT"]
167         vardb = portage.db[root]["vartree"].dbapi
168
169         cwd = None
170         try:
171                 cwd = os.getcwd()
172         except OSError:
173                 pass
174
175         files = []
176         for f in argv[1:]:
177                 f = portage.normalize_path(f)
178                 if not f.startswith(os.path.sep):
179                         if cwd is None:
180                                 sys.stderr.write("ERROR: cwd does not exist!\n")
181                                 sys.stderr.flush()
182                                 return 2
183                         f = os.path.join(cwd, f)
184                         f = portage.normalize_path(f)
185                 if not f.startswith(root):
186                         sys.stderr.write("ERROR: file paths must begin with <root>!\n")
187                         sys.stderr.flush()
188                         return 2
189                 files.append(f[len(root):])
190
191         found_owner = False
192         for cpv in vardb.cpv_all():
193                 cat, pkg = catsplit(cpv)
194                 mylink = dblink(cat, pkg, root, settings, vartree=vardb.vartree)
195                 myfiles = []
196                 for f in files:
197                         if mylink.isowner(f, root):
198                                 myfiles.append(f)
199                 if myfiles:
200                         found_owner = True
201                         sys.stdout.write("%s\n" % cpv)
202                         for f in myfiles:
203                                 sys.stdout.write("\t%s\n" % \
204                                         os.path.join(root, f.lstrip(os.path.sep)))
205                         sys.stdout.flush()
206         if not found_owner:
207                 sys.stderr.write("None of the installed packages claim the file(s).\n")
208                 sys.stderr.flush()
209                 return 1
210         return 0
211
212 owners.uses_root = True
213
214 def best_visible(argv):
215         """<root> [<category/package>]+
216         Returns category/package-version (without .ebuild).
217         """
218         if (len(argv) < 2):
219                 print "ERROR: insufficient parameters!"
220                 sys.exit(2)
221         try:
222                 mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1])
223                 visible=portage.best(mylist)
224                 if visible:
225                         print visible
226                         sys.exit(0)
227                 else:
228                         sys.exit(1)
229         except KeyError:
230                 sys.exit(1)
231 best_visible.uses_root = True
232
233
234 def mass_best_visible(argv):
235         """<root> [<category/package>]+
236         Returns category/package-version (without .ebuild).
237         """
238         if (len(argv) < 2):
239                 print "ERROR: insufficient parameters!"
240                 sys.exit(2)
241         try:
242                 for pack in argv[1:]:
243                         mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
244                         print pack+":"+portage.best(mylist)
245         except KeyError:
246                 sys.exit(1)
247 mass_best_visible.uses_root = True
248
249
250 def all_best_visible(argv):
251         """<root>
252         Returns all best_visible packages (without .ebuild).
253         """
254         if (len(argv) < 1):
255                 print "ERROR: insufficient parameters!"
256         
257         #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
258         for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
259                 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
260                 if mybest:
261                         print mybest
262 all_best_visible.uses_root = True
263
264
265 def match(argv):
266         """<root> <atom>
267         Returns a \\n separated list of category/package-version.
268         When given an empty string, all installed packages will
269         be listed.
270         """
271         if len(argv) != 2:
272                 print "ERROR: expected 2 parameters, got %d!" % len(argv)
273                 sys.exit(2)
274         root, atom = argv
275         if atom:
276                 results = portage.db[root]["vartree"].dbapi.match(atom)
277         else:
278                 results = portage.db[root]["vartree"].dbapi.cpv_all()
279                 results.sort()
280         for cpv in results:
281                 print cpv
282 match.uses_root = True
283
284
285 def vdb_path(argv):
286         """
287         Returns the path used for the var(installed) package database for the
288         set environment/configuration options.
289         """
290         print portage.root+portage.VDB_PATH
291
292
293 def gentoo_mirrors(argv):
294         """
295         Returns the mirrors set to use in the portage configuration.
296         """
297         print portage.settings["GENTOO_MIRRORS"]
298
299
300 def portdir(argv):
301         """
302         Returns the PORTDIR path.
303         """
304         print portage.settings["PORTDIR"]
305
306
307 def config_protect(argv):
308         """
309         Returns the CONFIG_PROTECT paths.
310         """
311         print portage.settings["CONFIG_PROTECT"]
312
313
314 def config_protect_mask(argv):
315         """
316         Returns the CONFIG_PROTECT_MASK paths.
317         """
318         print portage.settings["CONFIG_PROTECT_MASK"]
319
320
321 def portdir_overlay(argv):
322         """
323         Returns the PORTDIR_OVERLAY path.
324         """
325         print portage.settings["PORTDIR_OVERLAY"]
326
327
328 def pkgdir(argv):
329         """
330         Returns the PKGDIR path.
331         """
332         print portage.settings["PKGDIR"]
333
334
335 def distdir(argv):
336         """
337         Returns the DISTDIR path.
338         """
339         print portage.settings["DISTDIR"]
340
341
342 def envvar(argv):
343         """<variable>+
344         Returns a specific environment variable as exists prior to ebuild.sh.
345         Similar to: emerge --verbose --info | egrep '^<variable>='
346         """
347         verbose = "-v" in argv
348         if verbose:
349                 argv.pop(argv.index("-v"))
350
351         if len(argv) == 0:
352                 print "ERROR: insufficient parameters!"
353                 sys.exit(2)
354
355         for arg in argv:
356                 if verbose:
357                         print arg +"='"+ portage.settings[arg] +"'"
358                 else:
359                         print portage.settings[arg]
360
361 def get_repos(argv):
362         """<root>
363         Returns all repos with names (repo_name file) argv[0] = $ROOT
364         """
365         if len(argv) < 1:
366                 print "ERROR: insufficient parameters!"
367                 sys.exit(2)
368         print " ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories())
369
370 def get_repo_path(argv):
371         """<root> <repo_id>+
372         Returns the path to the repo named argv[1], argv[0] = $ROOT
373         """
374         if len(argv) < 2:
375                 print "ERROR: insufficient parameters!"
376                 sys.exit(2)
377         for arg in arvg[1:]:
378                 print portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(argv[1])
379
380 def list_preserved_libs(argv):
381         """<root>
382         Print a list of libraries preserved during a package update in the form
383         package: path. Returns 0 if no preserved libraries could be found, 
384         1 otherwise.
385         """
386
387         if len(argv) != 1:
388                 print "ERROR: wrong number of arguments"
389                 sys.exit(2)
390         mylibs = portage.db[argv[0]]["vartree"].dbapi.plib_registry.getPreservedLibs()
391         rValue = 0
392         for cpv in mylibs:
393                 print cpv,
394                 for path in mylibs[cpv]:
395                         print path,
396                         rValue = 1
397                 print
398         return rValue
399 list_preserved_libs.uses_root = True
400
401 #-----------------------------------------------------------------------------
402 #
403 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
404 #
405
406 def usage(argv):
407         print ">>> Portage information query tool"
408         print ">>> $Id$"
409         print ">>> Usage: portageq <command> [<option> ...]"
410         print ""
411         print "Available commands:"
412
413         #
414         # Show our commands -- we do this by scanning the functions in this
415         # file, and formatting each functions documentation.
416         #
417         commands = [x for x in globals() if x not in \
418                                 ("usage", "__doc__", "__name__", "main", "os", "portage", \
419                                 "sys", "__builtins__", "types", "string","exithandler")]
420         commands.sort()
421
422         for name in commands:
423                 # Drop non-functions
424                 obj = globals()[name]
425                 if  (type(obj) != types.FunctionType):
426                         continue
427
428                 doc = obj.__doc__
429                 if (doc == None):
430                         print "   "+name
431                         print "      MISSING DOCUMENTATION!"
432                         print ""
433                         continue
434
435                 lines = doc.split("\n")
436                 print "   "+name+" "+lines[0].strip()
437                 if (len(sys.argv) > 1):
438                         if ("--help" not in sys.argv):
439                                 lines = lines[:-1]
440                         for line in lines[1:]:
441                                 print "      "+line.strip()
442         if (len(sys.argv) == 1):
443                 print "\nRun portageq with --help for info"
444
445 def main():
446         if "-h" in sys.argv or "--help" in sys.argv:
447                 usage(sys.argv)
448                 sys.exit(os.EX_OK)
449         elif len(sys.argv) < 2:
450                 usage(sys.argv)
451                 sys.exit(os.EX_USAGE)
452
453         cmd = sys.argv[1]
454         function = globals().get(cmd)
455         if function is None:
456                 usage(sys.argv)
457                 sys.exit(os.EX_USAGE)
458         function = globals()[cmd]
459         uses_root = getattr(function, "uses_root", False) and len(sys.argv) > 2
460         if uses_root:
461                 if not os.path.isdir(sys.argv[2]):
462                         sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
463                         sys.stderr.write("Run portageq with --help for info\n")
464                         sys.stderr.flush()
465                         sys.exit(os.EX_USAGE)
466                 os.environ["ROOT"] = sys.argv[2]
467
468         global portage
469
470         # First import the main portage module without legacy globals since it
471         # is almost certain to succeed in that case. This provides access to
472         # the portage.exception namespace which is needed for later exception
473         # handling, like if portage.exception.PermissionDenied is raised when
474         # constructing the legacy global config instance.
475         os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
476         import portage
477         del os.environ["PORTAGE_LEGACY_GLOBALS"]
478         try:
479                 try:
480                         reload(portage)
481                 except ImportError:
482                         from os import path as osp
483                         sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
484                         import portage
485                 if uses_root:
486                         sys.argv[2] = portage.root
487                 retval = function(sys.argv[2:])
488                 if retval:
489                         sys.exit(retval)
490         except portage.exception.PermissionDenied, e:
491                 sys.stderr.write("Permission denied: '%s'\n" % str(e))
492                 sys.exit(e.errno)
493         except portage.exception.ParseError, e:
494                 sys.stderr.write("%s\n" % str(e))
495                 sys.exit(1)
496         except ValueError, e:
497                 if not e.args or \
498                         not hasattr(e.args[0], "__len__") or \
499                         len(e.args[0]) < 2:
500                         raise
501                 # Multiple matches thrown from cpv_expand
502                 pkgs = e.args[0]
503                 # An error has occurred so we writemsg to stderr and exit nonzero.
504                 portage.writemsg("The following packages available:\n", noiselevel=-1)
505                 for pkg in pkgs:
506                         portage.writemsg("* %s\n" % pkg, noiselevel=-1)
507                 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
508                 sys.exit(1)
509
510 main()
511
512 #-----------------------------------------------------------------------------