Bug #196043 - Implement a `portageq owners <root> [<filename>]+`
[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 owners(argv):
127         """<root> [<filename>]+
128         Given a list of files, print the packages that own the files and which
129         files belong to each package. Files owned by a package are listed on
130         the lines below it, indented by a single tab character (\\t). All file
131         paths must start with <root>. Returns 1 if no owners could be found,
132         and 0 otherwise.
133         """
134         if len(argv) < 2:
135                 sys.stderr.write("ERROR: insufficient parameters!\n")
136                 sys.stderr.flush()
137                 return 2
138
139         from portage import catsplit, dblink
140         settings = portage.settings
141         root = settings["ROOT"]
142         vardb = portage.db[root]["vartree"].dbapi
143
144         cwd = None
145         try:
146                 cwd = os.getcwd()
147         except OSError:
148                 pass
149
150         files = []
151         for f in argv[1:]:
152                 f = portage.normalize_path(f)
153                 if not f.startswith(os.path.sep):
154                         if cwd is None:
155                                 sys.stderr.write("ERROR: cwd does not exist!\n")
156                                 sys.stderr.flush()
157                                 return 2
158                         f = os.path.join(cwd, f)
159                         f = portage.normalize_path(f)
160                 if not f.startswith(root):
161                         sys.stderr.write("ERROR: file paths must begin with <root>!\n")
162                         sys.stderr.flush()
163                         return 2
164                 files.append(f[len(root):])
165
166         found_owner = False
167         for cpv in vardb.cpv_all():
168                 cat, pkg = catsplit(cpv)
169                 mylink = dblink(cat, pkg, root, settings, vartree=vardb.vartree)
170                 myfiles = []
171                 for f in files:
172                         if mylink.isowner(f, root):
173                                 myfiles.append(f)
174                 if myfiles:
175                         found_owner = True
176                         sys.stdout.write("%s\n" % cpv)
177                         for f in myfiles:
178                                 sys.stdout.write("\t%s\n" % \
179                                         os.path.join(root, f.lstrip(os.path.sep)))
180                         sys.stdout.flush()
181         if not found_owner:
182                 sys.stderr.write("None of the installed packages claim the file(s).\n")
183                 sys.stderr.flush()
184                 return 1
185         return 0
186
187 owners.uses_root = True
188
189 def best_visible(argv):
190         """<root> [<category/package>]+
191         Returns category/package-version (without .ebuild).
192         """
193         if (len(argv) < 2):
194                 print "ERROR: insufficient parameters!"
195                 sys.exit(2)
196         try:
197                 mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1])
198                 visible=portage.best(mylist)
199                 if visible:
200                         print visible
201                         sys.exit(0)
202                 else:
203                         sys.exit(1)
204         except KeyError:
205                 sys.exit(1)
206 best_visible.uses_root = True
207
208
209 def mass_best_visible(argv):
210         """<root> [<category/package>]+
211         Returns category/package-version (without .ebuild).
212         """
213         if (len(argv) < 2):
214                 print "ERROR: insufficient parameters!"
215                 sys.exit(2)
216         try:
217                 for pack in argv[1:]:
218                         mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
219                         print pack+":"+portage.best(mylist)
220         except KeyError:
221                 sys.exit(1)
222 mass_best_visible.uses_root = True
223
224
225 def all_best_visible(argv):
226         """<root>
227         Returns all best_visible packages (without .ebuild).
228         """
229         if (len(argv) < 1):
230                 print "ERROR: insufficient parameters!"
231         
232         #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
233         for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
234                 mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
235                 if mybest:
236                         print mybest
237 all_best_visible.uses_root = True
238
239
240 def match(argv):
241         """<root> <category/package>
242         Returns \n seperated list of category/package-version
243         """
244         if (len(argv) < 2):
245                 print "ERROR: insufficient parameters!"
246                 sys.exit(2)
247         try:
248                 print "\n".join(portage.db[argv[0]]["vartree"].dbapi.match(argv[1]))
249         except KeyError, e:
250                 portage.writemsg("%s\n" % str(e), noiselevel=-1)
251                 sys.exit(1)
252 match.uses_root = True
253
254
255 def vdb_path(argv):
256         """
257         Returns the path used for the var(installed) package database for the
258         set environment/configuration options.
259         """
260         print portage.root+portage.VDB_PATH
261
262
263 def gentoo_mirrors(argv):
264         """
265         Returns the mirrors set to use in the portage configuration.
266         """
267         print portage.settings["GENTOO_MIRRORS"]
268
269
270 def portdir(argv):
271         """
272         Returns the PORTDIR path.
273         """
274         print portage.settings["PORTDIR"]
275
276
277 def config_protect(argv):
278         """
279         Returns the CONFIG_PROTECT paths.
280         """
281         print portage.settings["CONFIG_PROTECT"]
282
283
284 def config_protect_mask(argv):
285         """
286         Returns the CONFIG_PROTECT_MASK paths.
287         """
288         print portage.settings["CONFIG_PROTECT_MASK"]
289
290
291 def portdir_overlay(argv):
292         """
293         Returns the PORTDIR_OVERLAY path.
294         """
295         print portage.settings["PORTDIR_OVERLAY"]
296
297
298 def pkgdir(argv):
299         """
300         Returns the PKGDIR path.
301         """
302         print portage.settings["PKGDIR"]
303
304
305 def distdir(argv):
306         """
307         Returns the DISTDIR path.
308         """
309         print portage.settings["DISTDIR"]
310
311
312 def envvar(argv):
313         """<variable>+
314         Returns a specific environment variable as exists prior to ebuild.sh.
315         Similar to: emerge --verbose --info | egrep '^<variable>='
316         """
317         verbose = "-v" in argv
318         if verbose:
319                 argv.pop(argv.index("-v"))
320
321         if len(argv) == 0:
322                 print "ERROR: insufficient parameters!"
323                 sys.exit(2)
324
325         for arg in argv:
326                 if verbose:
327                         print arg +"='"+ portage.settings[arg] +"'"
328                 else:
329                         print portage.settings[arg]
330
331 def get_repos(argv):
332         """<root>
333         Returns all repos with names (repo_name file) argv[0] = $ROOT
334         """
335         if len(argv) < 1:
336                 print "ERROR: insufficient parameters!"
337                 sys.exit(2)
338         print " ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories())
339
340 def get_repo_path(argv):
341         """<root> <repo_id>+
342         Returns the path to the repo named argv[1], argv[0] = $ROOT
343         """
344         if len(argv) < 2:
345                 print "ERROR: insufficient parameters!"
346                 sys.exit(2)
347         for arg in arvg[1:]:
348                 print portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(argv[1])
349
350 def list_preserved_libs(argv):
351         """<root>
352         Print a list of libraries preserved during a package update in the form
353         package: path. Returns 0 if no preserved libraries could be found, 
354         1 otherwise.
355         """
356
357         if len(argv) != 1:
358                 print "ERROR: wrong number of arguments"
359                 sys.exit(2)
360         mylibs = portage.db[argv[0]]["vartree"].dbapi.plib_registry.getPreservedLibs()
361         rValue = 0
362         for cpv in mylibs:
363                 print cpv,
364                 for path in mylibs[cpv]:
365                         print path,
366                         rValue = 1
367                 print
368         return rValue
369 list_preserved_libs.uses_root = True
370
371 #-----------------------------------------------------------------------------
372 #
373 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
374 #
375
376 def usage(argv):
377         rev="$Revision: 1.13.2.1 $"
378         ver= rev.split(' ')[1]
379         print ">>> Portage information query tool -- version "+ver
380         print ">>> Usage: portageq <command> [<option> ...]"
381         print ""
382         print "Available commands:"
383
384         #
385         # Show our commands -- we do this by scanning the functions in this
386         # file, and formatting each functions documentation.
387         #
388         commands = [x for x in globals() if x not in \
389                                 ("usage", "__doc__", "__name__", "main", "os", "portage", \
390                                 "sys", "__builtins__", "types", "string","exithandler")]
391         commands.sort()
392
393         for name in commands:
394                 # Drop non-functions
395                 obj = globals()[name]
396                 if  (type(obj) != types.FunctionType):
397                         continue
398
399                 doc = obj.__doc__
400                 if (doc == None):
401                         print "   "+name
402                         print "      MISSING DOCUMENTATION!"
403                         print ""
404                         continue
405
406                 lines = doc.split("\n")
407                 print "   "+name+" "+lines[0].strip()
408                 if (len(sys.argv) > 1):
409                         if ("--help" not in sys.argv):
410                                 lines = lines[:-1]
411                         for line in lines[1:]:
412                                 print "      "+line.strip()
413         if (len(sys.argv) == 1):
414                 print "\nRun portageq with --help for info"
415
416 def main():
417         if "-h" in sys.argv or "--help" in sys.argv:
418                 usage(sys.argv)
419                 sys.exit(os.EX_OK)
420         elif len(sys.argv) < 2:
421                 usage(sys.argv)
422                 sys.exit(os.EX_USAGE)
423
424         cmd = sys.argv[1]
425         try:
426                 function = globals()[cmd]
427                 uses_root = (getattr(function, "uses_root", False) and len(sys.argv) > 2)
428                 if uses_root:
429                         os.environ["ROOT"] = sys.argv[2]
430                 global portage
431                 try:
432                         import portage
433                 except ImportError:
434                         from os import path as osp
435                         sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
436                         import portage
437                 if uses_root:
438                         sys.argv[2] = portage.root
439                 retval = function(sys.argv[2:])
440                 if retval:
441                         sys.exit(retval)
442         except KeyError:
443                 usage(sys.argv)
444                 sys.exit(os.EX_USAGE)
445         except portage.exception.PermissionDenied, e:
446                 sys.stderr.write("Permission denied: '%s'\n" % str(e))
447                 sys.exit(e.errno)
448         except ValueError, e:
449                 if not e.args or \
450                         not hasattr(e.args[0], "__len__") or \
451                         len(e.args[0]) < 2:
452                         raise
453                 # Multiple matches thrown from cpv_expand
454                 pkgs = e.args[0]
455                 # An error has occurred so we writemsg to stderr and exit nonzero.
456                 portage.writemsg("The following packages available:\n", noiselevel=-1)
457                 for pkg in pkgs:
458                         portage.writemsg("* %s\n" % pkg, noiselevel=-1)
459                 portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
460                 sys.exit(1)
461
462 main()
463
464 #-----------------------------------------------------------------------------