blob: 93220e36178e27f70c6b4b4938faa113977aff13 [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002
3# OpenEmbedded pkgdata utility
4#
5# Written by: Paul Eggleton <paul.eggleton@linux.intel.com>
6#
7# Copyright 2012-2015 Intel Corporation
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
11
12import sys
13import os
14import os.path
15import fnmatch
16import re
17import argparse
18import logging
19from collections import defaultdict, OrderedDict
20
21scripts_path = os.path.dirname(os.path.realpath(__file__))
22lib_path = scripts_path + '/lib'
23sys.path = sys.path + [lib_path]
24import scriptutils
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050025import argparse_oe
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026logger = scriptutils.logger_create('pkgdatautil')
27
28def tinfoil_init():
29 import bb.tinfoil
30 import logging
31 tinfoil = bb.tinfoil.Tinfoil()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032 tinfoil.logger.setLevel(logging.WARNING)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050033 tinfoil.prepare(True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 return tinfoil
35
36
37def glob(args):
38 # Handle both multiple arguments and multiple values within an arg (old syntax)
39 globs = []
40 for globitem in args.glob:
41 globs.extend(globitem.split())
42
43 if not os.path.exists(args.pkglistfile):
44 logger.error('Unable to find package list file %s' % args.pkglistfile)
45 sys.exit(1)
46
47 skipval = "-locale-|^locale-base-|-dev$|-doc$|-dbg$|-staticdev$|^kernel-module-"
48 if args.exclude:
49 skipval += "|" + args.exclude
50 skipregex = re.compile(skipval)
51
Patrick Williamsf1e5d692016-03-30 15:21:19 -050052 skippedpkgs = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050053 mappedpkgs = set()
54 with open(args.pkglistfile, 'r') as f:
55 for line in f:
56 fields = line.rstrip().split()
57 if not fields:
58 continue
59 pkg = fields[0]
60 # We don't care about other args (used to need the package architecture but the
61 # new pkgdata structure avoids the need for that)
62
63 # Skip packages for which there is no point applying globs
64 if skipregex.search(pkg):
65 logger.debug("%s -> !!" % pkg)
Patrick Williamsf1e5d692016-03-30 15:21:19 -050066 skippedpkgs.add(pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067 continue
68
69 # Skip packages that already match the globs, so if e.g. a dev package
70 # is already installed and thus in the list, we don't process it any further
71 # Most of these will be caught by skipregex already, but just in case...
72 already = False
73 for g in globs:
74 if fnmatch.fnmatchcase(pkg, g):
75 already = True
76 break
77 if already:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050078 skippedpkgs.add(pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050079 logger.debug("%s -> !" % pkg)
80 continue
81
82 # Define some functions
83 def revpkgdata(pkgn):
84 return os.path.join(args.pkgdata_dir, "runtime-reverse", pkgn)
85 def fwdpkgdata(pkgn):
86 return os.path.join(args.pkgdata_dir, "runtime", pkgn)
87 def readpn(pkgdata_file):
88 pn = ""
89 with open(pkgdata_file, 'r') as f:
90 for line in f:
91 if line.startswith("PN:"):
92 pn = line.split(': ')[1].rstrip()
93 return pn
94 def readrenamed(pkgdata_file):
95 renamed = ""
96 pn = os.path.basename(pkgdata_file)
97 with open(pkgdata_file, 'r') as f:
98 for line in f:
99 if line.startswith("PKG_%s:" % pn):
100 renamed = line.split(': ')[1].rstrip()
101 return renamed
102
103 # Main processing loop
104 for g in globs:
105 mappedpkg = ""
106 # First just try substitution (i.e. packagename -> packagename-dev)
107 newpkg = g.replace("*", pkg)
108 revlink = revpkgdata(newpkg)
109 if os.path.exists(revlink):
110 mappedpkg = os.path.basename(os.readlink(revlink))
111 fwdfile = fwdpkgdata(mappedpkg)
112 if os.path.exists(fwdfile):
113 mappedpkg = readrenamed(fwdfile)
114 if not os.path.exists(fwdfile + ".packaged"):
115 mappedpkg = ""
116 else:
117 revlink = revpkgdata(pkg)
118 if os.path.exists(revlink):
119 # Check if we can map after undoing the package renaming (by resolving the symlink)
120 origpkg = os.path.basename(os.readlink(revlink))
121 newpkg = g.replace("*", origpkg)
122 fwdfile = fwdpkgdata(newpkg)
123 if os.path.exists(fwdfile):
124 mappedpkg = readrenamed(fwdfile)
125 else:
126 # That didn't work, so now get the PN, substitute that, then map in the other direction
127 pn = readpn(revlink)
128 newpkg = g.replace("*", pn)
129 fwdfile = fwdpkgdata(newpkg)
130 if os.path.exists(fwdfile):
131 mappedpkg = readrenamed(fwdfile)
132 if not os.path.exists(fwdfile + ".packaged"):
133 mappedpkg = ""
134 else:
135 # Package doesn't even exist...
136 logger.debug("%s is not a valid package!" % (pkg))
137 break
138
139 if mappedpkg:
140 logger.debug("%s (%s) -> %s" % (pkg, g, mappedpkg))
141 mappedpkgs.add(mappedpkg)
142 else:
143 logger.debug("%s (%s) -> ?" % (pkg, g))
144
145 logger.debug("------")
146
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500147 print("\n".join(mappedpkgs - skippedpkgs))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149def read_value(args):
150 # Handle both multiple arguments and multiple values within an arg (old syntax)
151 packages = []
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 if args.file:
153 with open(args.file, 'r') as f:
154 for line in f:
155 splitline = line.split()
156 if splitline:
157 packages.append(splitline[0])
158 else:
159 for pkgitem in args.pkg:
160 packages.extend(pkgitem.split())
161 if not packages:
162 logger.error("No packages specified")
163 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500165 def readvar(pkgdata_file, valuename, mappedpkg):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500166 val = ""
167 with open(pkgdata_file, 'r') as f:
168 for line in f:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500169 if (line.startswith(valuename + ":") or
170 line.startswith(valuename + "_" + mappedpkg + ":")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500171 val = line.split(': ', 1)[1].rstrip()
172 return val
173
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500174 logger.debug("read-value('%s', '%s' '%s')" % (args.pkgdata_dir, args.valuename, packages))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500175 for package in packages:
176 pkg_split = package.split('_')
177 pkg_name = pkg_split[0]
178 logger.debug("package: '%s'" % pkg_name)
179 revlink = os.path.join(args.pkgdata_dir, "runtime-reverse", pkg_name)
180 logger.debug(revlink)
181 if os.path.exists(revlink):
182 mappedpkg = os.path.basename(os.readlink(revlink))
183 qvar = args.valuename
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500184 value = readvar(revlink, qvar, mappedpkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185 if qvar == "PKGSIZE":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500186 # PKGSIZE is now in bytes, but we we want it in KB
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500187 pkgsize = (int(value) + 1024 // 2) // 1024
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500188 value = "%d" % pkgsize
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500189 if args.unescape:
190 import codecs
191 # escape_decode() unescapes backslash encodings in byte streams
192 value = codecs.escape_decode(bytes(value, "utf-8"))[0].decode("utf-8")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500193 if args.prefix_name:
194 print('%s %s' % (pkg_name, value))
195 else:
196 print(value)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500197 else:
198 logger.debug("revlink %s does not exist", revlink)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500199
200def lookup_pkglist(pkgs, pkgdata_dir, reverse):
201 if reverse:
202 mappings = OrderedDict()
203 for pkg in pkgs:
204 revlink = os.path.join(pkgdata_dir, "runtime-reverse", pkg)
205 logger.debug(revlink)
206 if os.path.exists(revlink):
207 mappings[pkg] = os.path.basename(os.readlink(revlink))
208 else:
209 mappings = defaultdict(list)
210 for pkg in pkgs:
211 pkgfile = os.path.join(pkgdata_dir, 'runtime', pkg)
212 if os.path.exists(pkgfile):
213 with open(pkgfile, 'r') as f:
214 for line in f:
215 fields = line.rstrip().split(': ')
216 if fields[0] == 'PKG_%s' % pkg:
217 mappings[pkg].append(fields[1])
218 break
219 return mappings
220
221def lookup_pkg(args):
222 # Handle both multiple arguments and multiple values within an arg (old syntax)
223 pkgs = []
224 for pkgitem in args.pkg:
225 pkgs.extend(pkgitem.split())
226
227 mappings = lookup_pkglist(pkgs, args.pkgdata_dir, args.reverse)
228
229 if len(mappings) < len(pkgs):
230 missing = list(set(pkgs) - set(mappings.keys()))
231 logger.error("The following packages could not be found: %s" % ', '.join(missing))
232 sys.exit(1)
233
234 if args.reverse:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600235 items = list(mappings.values())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500236 else:
237 items = []
238 for pkg in pkgs:
239 items.extend(mappings.get(pkg, []))
240
241 print('\n'.join(items))
242
243def lookup_recipe(args):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400244 def parse_pkgdatafile(pkgdatafile):
245 with open(pkgdatafile, 'r') as f:
246 found = False
247 for line in f:
248 if line.startswith('PN:'):
249 print("%s" % line.split(':', 1)[1].strip())
250 found = True
251 break
252 if not found:
253 logger.error("Unable to find PN entry in %s" % pkgdatafile)
254 sys.exit(1)
255
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256 # Handle both multiple arguments and multiple values within an arg (old syntax)
257 pkgs = []
258 for pkgitem in args.pkg:
259 pkgs.extend(pkgitem.split())
260
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261 for pkg in pkgs:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400262 providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg)
263 if os.path.exists(providepkgpath):
264 for f in os.listdir(providepkgpath):
265 if f != pkg:
266 print("%s is in the RPROVIDES of %s:" % (pkg, f))
267 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f)
268 parse_pkgdatafile(pkgdatafile)
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700269 continue
Brad Bishop316dfdd2018-06-25 12:45:53 -0400270 pkgdatafile = os.path.join(args.pkgdata_dir, 'runtime-reverse', pkg)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800271 if os.path.exists(pkgdatafile):
272 parse_pkgdatafile(pkgdatafile)
273 else:
274 if args.carryon:
275 print("The following packages could not be found: %s" % pkg)
276 else:
277 logger.error("The following packages could not be found: %s" % pkg)
278 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500279
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600280def package_info(args):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400281 def parse_pkgdatafile(pkgdatafile):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700282 vars = ['PKGV', 'PKGE', 'PKGR', 'PN', 'PV', 'PE', 'PR', 'PKGSIZE']
283 if args.extra:
284 vars += args.extra
Brad Bishop316dfdd2018-06-25 12:45:53 -0400285 with open(pkgdatafile, 'r') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700286 vals = dict()
287 extra = ''
Brad Bishop316dfdd2018-06-25 12:45:53 -0400288 for line in f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700289 for var in vars:
290 m = re.match(var + '(?:_\S+)?:\s*(.+?)\s*$', line)
291 if m:
292 vals[var] = m.group(1)
293 pkg_version = vals['PKGV'] or ''
294 recipe = vals['PN'] or ''
295 recipe_version = vals['PV'] or ''
296 pkg_size = vals['PKGSIZE'] or ''
297 if 'PKGE' in vals:
298 pkg_version = vals['PKGE'] + ":" + pkg_version
299 if 'PKGR' in vals:
300 pkg_version = pkg_version + "-" + vals['PKGR']
301 if 'PE' in vals:
302 recipe_version = vals['PE'] + ":" + recipe_version
303 if 'PR' in vals:
304 recipe_version = recipe_version + "-" + vals['PR']
305 if args.extra:
306 for var in args.extra:
307 if var in vals:
308 val = re.sub(r'\s+', ' ', vals[var])
309 extra += ' "%s"' % val
310 print("%s %s %s %s %s%s" % (pkg, pkg_version, recipe, recipe_version, pkg_size, extra))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400311
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600312 # Handle both multiple arguments and multiple values within an arg (old syntax)
313 packages = []
314 if args.file:
315 with open(args.file, 'r') as f:
316 for line in f:
317 splitline = line.split()
318 if splitline:
319 packages.append(splitline[0])
320 else:
321 for pkgitem in args.pkg:
322 packages.extend(pkgitem.split())
323 if not packages:
324 logger.error("No packages specified")
325 sys.exit(1)
326
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600327 for pkg in packages:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400328 providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg)
329 if os.path.exists(providepkgpath):
330 for f in os.listdir(providepkgpath):
331 if f != pkg:
332 print("%s is in the RPROVIDES of %s:" % (pkg, f))
333 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f)
334 parse_pkgdatafile(pkgdatafile)
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700335 continue
Brad Bishop316dfdd2018-06-25 12:45:53 -0400336 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime-reverse", pkg)
337 if not os.path.exists(pkgdatafile):
338 logger.error("Unable to find any built runtime package named %s" % pkg)
339 sys.exit(1)
340 parse_pkgdatafile(pkgdatafile)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600341
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342def get_recipe_pkgs(pkgdata_dir, recipe, unpackaged):
343 recipedatafile = os.path.join(pkgdata_dir, recipe)
344 if not os.path.exists(recipedatafile):
345 logger.error("Unable to find packaged recipe with name %s" % recipe)
346 sys.exit(1)
347 packages = []
348 with open(recipedatafile, 'r') as f:
349 for line in f:
350 fields = line.rstrip().split(': ')
351 if fields[0] == 'PACKAGES':
352 packages = fields[1].split()
353 break
354
355 if not unpackaged:
356 pkglist = []
357 for pkg in packages:
358 if os.path.exists(os.path.join(pkgdata_dir, 'runtime', '%s.packaged' % pkg)):
359 pkglist.append(pkg)
360 return pkglist
361 else:
362 return packages
363
364def list_pkgs(args):
365 found = False
366
367 def matchpkg(pkg):
368 if args.pkgspec:
369 matched = False
370 for pkgspec in args.pkgspec:
371 if fnmatch.fnmatchcase(pkg, pkgspec):
372 matched = True
373 break
374 if not matched:
375 return False
376 if not args.unpackaged:
377 if args.runtime:
378 revlink = os.path.join(args.pkgdata_dir, "runtime-reverse", pkg)
379 if os.path.exists(revlink):
380 # We're unlikely to get here if the package was not packaged, but just in case
381 # we add the symlinks for unpackaged files in the future
382 mappedpkg = os.path.basename(os.readlink(revlink))
383 if not os.path.exists(os.path.join(args.pkgdata_dir, 'runtime', '%s.packaged' % mappedpkg)):
384 return False
385 else:
386 return False
387 else:
388 if not os.path.exists(os.path.join(args.pkgdata_dir, 'runtime', '%s.packaged' % pkg)):
389 return False
390 return True
391
Brad Bishop64c979e2019-11-04 13:55:29 -0500392 pkglist = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500393 if args.recipe:
394 packages = get_recipe_pkgs(args.pkgdata_dir, args.recipe, args.unpackaged)
395
396 if args.runtime:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500397 runtime_pkgs = lookup_pkglist(packages, args.pkgdata_dir, False)
398 for rtpkgs in runtime_pkgs.values():
399 pkglist.extend(rtpkgs)
400 else:
401 pkglist = packages
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500402 else:
403 if args.runtime:
404 searchdir = 'runtime-reverse'
405 else:
406 searchdir = 'runtime'
407
408 for root, dirs, files in os.walk(os.path.join(args.pkgdata_dir, searchdir)):
409 for fn in files:
410 if fn.endswith('.packaged'):
411 continue
Brad Bishop64c979e2019-11-04 13:55:29 -0500412 pkglist.append(fn)
413
414 for pkg in sorted(pkglist):
415 if matchpkg(pkg):
416 found = True
417 print("%s" % pkg)
418
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500419 if not found:
420 if args.pkgspec:
421 logger.error("Unable to find any package matching %s" % args.pkgspec)
422 else:
423 logger.error("No packages found")
424 sys.exit(1)
425
426def list_pkg_files(args):
427 import json
Brad Bishop316dfdd2018-06-25 12:45:53 -0400428 def parse_pkgdatafile(pkgdatafile, long=False):
429 with open(pkgdatafile, 'r') as f:
430 found = False
431 for line in f:
432 if line.startswith('FILES_INFO:'):
433 found = True
434 val = line.split(':', 1)[1].strip()
435 dictval = json.loads(val)
436 if long:
437 width = max(map(len, dictval), default=0)
438 for fullpth in sorted(dictval):
439 print("\t{:{width}}\t{}".format(fullpth, dictval[fullpth], width=width))
440 else:
441 for fullpth in sorted(dictval):
442 print("\t%s" % fullpth)
443 break
444 if not found:
445 logger.error("Unable to find FILES_INFO entry in %s" % pkgdatafile)
446 sys.exit(1)
447
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500448
449 if args.recipe:
450 if args.pkg:
451 logger.error("list-pkg-files: If -p/--recipe is specified then a package name cannot be specified")
452 sys.exit(1)
453 recipepkglist = get_recipe_pkgs(args.pkgdata_dir, args.recipe, args.unpackaged)
454 if args.runtime:
455 pkglist = []
456 runtime_pkgs = lookup_pkglist(recipepkglist, args.pkgdata_dir, False)
457 for rtpkgs in runtime_pkgs.values():
458 pkglist.extend(rtpkgs)
459 else:
460 pkglist = recipepkglist
461 else:
462 if not args.pkg:
463 logger.error("list-pkg-files: If -p/--recipe is not specified then at least one package name must be specified")
464 sys.exit(1)
465 pkglist = args.pkg
466
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500467 for pkg in sorted(pkglist):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468 print("%s:" % pkg)
469 if args.runtime:
470 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime-reverse", pkg)
471 if not os.path.exists(pkgdatafile):
472 if args.recipe:
473 # This package was empty and thus never packaged, ignore
474 continue
475 logger.error("Unable to find any built runtime package named %s" % pkg)
476 sys.exit(1)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400477 parse_pkgdatafile(pkgdatafile, args.long)
478
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500479 else:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400480 providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg)
481 if os.path.exists(providepkgpath):
482 for f in os.listdir(providepkgpath):
483 if f != pkg:
484 print("%s is in the RPROVIDES of %s:" % (pkg, f))
485 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f)
486 parse_pkgdatafile(pkgdatafile, args.long)
487 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500488 pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", pkg)
489 if not os.path.exists(pkgdatafile):
490 logger.error("Unable to find any built recipe-space package named %s" % pkg)
491 sys.exit(1)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400492 parse_pkgdatafile(pkgdatafile, args.long)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500493
494def find_path(args):
495 import json
496
497 found = False
498 for root, dirs, files in os.walk(os.path.join(args.pkgdata_dir, 'runtime')):
499 for fn in files:
500 with open(os.path.join(root,fn)) as f:
501 for line in f:
502 if line.startswith('FILES_INFO:'):
503 val = line.split(':', 1)[1].strip()
504 dictval = json.loads(val)
505 for fullpth in dictval.keys():
506 if fnmatch.fnmatchcase(fullpth, args.targetpath):
507 found = True
508 print("%s: %s" % (fn, fullpth))
509 break
510 if not found:
511 logger.error("Unable to find any package producing path %s" % args.targetpath)
512 sys.exit(1)
513
514
515def main():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500516 parser = argparse_oe.ArgumentParser(description="OpenEmbedded pkgdata tool - queries the pkgdata files written out during do_package",
517 epilog="Use %(prog)s <subcommand> --help to get help on a specific command")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500518 parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true')
519 parser.add_argument('-p', '--pkgdata-dir', help='Path to pkgdata directory (determined automatically if not specified)')
520 subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600521 subparsers.required = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500522
523 parser_lookup_pkg = subparsers.add_parser('lookup-pkg',
524 help='Translate between recipe-space package names and runtime package names',
525 description='Looks up the specified recipe-space package name(s) to see what the final runtime package name is (e.g. glibc becomes libc6), or with -r/--reverse looks up the other way.')
526 parser_lookup_pkg.add_argument('pkg', nargs='+', help='Package name to look up')
527 parser_lookup_pkg.add_argument('-r', '--reverse', help='Switch to looking up recipe-space package names from runtime package names', action='store_true')
528 parser_lookup_pkg.set_defaults(func=lookup_pkg)
529
530 parser_list_pkgs = subparsers.add_parser('list-pkgs',
531 help='List packages',
532 description='Lists packages that have been built')
533 parser_list_pkgs.add_argument('pkgspec', nargs='*', help='Package name to search for (wildcards * ? allowed, use quotes to avoid shell expansion)')
534 parser_list_pkgs.add_argument('-r', '--runtime', help='Show runtime package names instead of recipe-space package names', action='store_true')
535 parser_list_pkgs.add_argument('-p', '--recipe', help='Limit to packages produced by the specified recipe')
536 parser_list_pkgs.add_argument('-u', '--unpackaged', help='Include unpackaged (i.e. empty) packages', action='store_true')
537 parser_list_pkgs.set_defaults(func=list_pkgs)
538
539 parser_list_pkg_files = subparsers.add_parser('list-pkg-files',
540 help='List files within a package',
541 description='Lists files included in one or more packages')
542 parser_list_pkg_files.add_argument('pkg', nargs='*', help='Package name to report on (if -p/--recipe is not specified)')
543 parser_list_pkg_files.add_argument('-r', '--runtime', help='Specified package(s) are runtime package names instead of recipe-space package names', action='store_true')
544 parser_list_pkg_files.add_argument('-p', '--recipe', help='Report on all packages produced by the specified recipe')
545 parser_list_pkg_files.add_argument('-u', '--unpackaged', help='Include unpackaged (i.e. empty) packages (only useful with -p/--recipe)', action='store_true')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400546 parser_list_pkg_files.add_argument('-l', '--long', help='Show more information per file', action='store_true')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500547 parser_list_pkg_files.set_defaults(func=list_pkg_files)
548
549 parser_lookup_recipe = subparsers.add_parser('lookup-recipe',
550 help='Find recipe producing one or more packages',
551 description='Looks up the specified runtime package(s) to see which recipe they were produced by')
552 parser_lookup_recipe.add_argument('pkg', nargs='+', help='Runtime package name to look up')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800553 parser_lookup_recipe.add_argument('-c', '--continue', dest="carryon", help='Continue looking up recipes even if we can not find one', action='store_true')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554 parser_lookup_recipe.set_defaults(func=lookup_recipe)
555
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600556 parser_package_info = subparsers.add_parser('package-info',
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500557 help='Show version, recipe and size information for one or more packages',
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600558 description='Looks up the specified runtime package(s) and display information')
559 parser_package_info.add_argument('pkg', nargs='*', help='Runtime package name to look up')
560 parser_package_info.add_argument('-f', '--file', help='Read package names from the specified file (one per line, first field only)')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500561 parser_package_info.add_argument('-e', '--extra', help='Extra variables to display, e.g., LICENSE (can be specified multiple times)', action='append')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600562 parser_package_info.set_defaults(func=package_info)
563
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564 parser_find_path = subparsers.add_parser('find-path',
565 help='Find package providing a target path',
566 description='Finds the recipe-space package providing the specified target path')
567 parser_find_path.add_argument('targetpath', help='Path to find (wildcards * ? allowed, use quotes to avoid shell expansion)')
568 parser_find_path.set_defaults(func=find_path)
569
570 parser_read_value = subparsers.add_parser('read-value',
571 help='Read any pkgdata value for one or more packages',
572 description='Reads the named value from the pkgdata files for the specified packages')
573 parser_read_value.add_argument('valuename', help='Name of the value to look up')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500574 parser_read_value.add_argument('pkg', nargs='*', help='Runtime package name to look up')
575 parser_read_value.add_argument('-f', '--file', help='Read package names from the specified file (one per line, first field only)')
576 parser_read_value.add_argument('-n', '--prefix-name', help='Prefix output with package name', action='store_true')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500577 parser_read_value.add_argument('-u', '--unescape', help='Expand escapes such as \\n', action='store_true')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500578 parser_read_value.set_defaults(func=read_value)
579
580 parser_glob = subparsers.add_parser('glob',
581 help='Expand package name glob expression',
582 description='Expands one or more glob expressions over the packages listed in pkglistfile')
583 parser_glob.add_argument('pkglistfile', help='File listing packages (one package name per line)')
584 parser_glob.add_argument('glob', nargs="+", help='Glob expression for package names, e.g. *-dev')
585 parser_glob.add_argument('-x', '--exclude', help='Exclude packages matching specified regex from the glob operation')
586 parser_glob.set_defaults(func=glob)
587
588
589 args = parser.parse_args()
590
591 if args.debug:
592 logger.setLevel(logging.DEBUG)
593
594 if not args.pkgdata_dir:
595 import scriptpath
596 bitbakepath = scriptpath.add_bitbake_lib_path()
597 if not bitbakepath:
598 logger.error("Unable to find bitbake by searching parent directory of this script or PATH")
599 sys.exit(1)
600 logger.debug('Found bitbake path: %s' % bitbakepath)
601 tinfoil = tinfoil_init()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600602 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500603 args.pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600604 finally:
605 tinfoil.shutdown()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500606 logger.debug('Value of PKGDATA_DIR is "%s"' % args.pkgdata_dir)
607 if not args.pkgdata_dir:
608 logger.error('Unable to determine pkgdata directory from PKGDATA_DIR')
609 sys.exit(1)
610
611 if not os.path.exists(args.pkgdata_dir):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500612 logger.error('Unable to find pkgdata directory %s' % args.pkgdata_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500613 sys.exit(1)
614
615 ret = args.func(args)
616
617 return ret
618
619
620if __name__ == "__main__":
621 main()