diff options
Diffstat (limited to 'scripts/oe-pkgdata-util')
-rwxr-xr-x | scripts/oe-pkgdata-util | 269 |
1 files changed, 157 insertions, 112 deletions
diff --git a/scripts/oe-pkgdata-util b/scripts/oe-pkgdata-util index e4d262d7b7..7412cc1f47 100755 --- a/scripts/oe-pkgdata-util +++ b/scripts/oe-pkgdata-util @@ -6,18 +6,7 @@ # # Copyright 2012-2015 Intel Corporation # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# SPDX-License-Identifier: GPL-2.0-only # import sys @@ -40,9 +29,8 @@ def tinfoil_init(): import bb.tinfoil import logging tinfoil = bb.tinfoil.Tinfoil() - tinfoil.prepare(True) - tinfoil.logger.setLevel(logging.WARNING) + tinfoil.prepare(True) return tinfoil @@ -108,7 +96,7 @@ def glob(args): pn = os.path.basename(pkgdata_file) with open(pkgdata_file, 'r') as f: for line in f: - if line.startswith("PKG_%s:" % pn): + if line.startswith("PKG:%s:" % pn): renamed = line.split(': ')[1].rstrip() return renamed @@ -174,15 +162,16 @@ def read_value(args): logger.error("No packages specified") sys.exit(1) - def readvar(pkgdata_file, valuename): + def readvar(pkgdata_file, valuename, mappedpkg): val = "" with open(pkgdata_file, 'r') as f: for line in f: - if line.startswith(valuename + ":"): + if (line.startswith(valuename + ":") or + line.startswith(valuename + "_" + mappedpkg + ":")): val = line.split(': ', 1)[1].rstrip() return val - logger.debug("read-value('%s', '%s' '%s'" % (args.pkgdata_dir, args.valuename, packages)) + logger.debug("read-value('%s', '%s' '%s')" % (args.pkgdata_dir, args.valuenames, packages)) for package in packages: pkg_split = package.split('_') pkg_name = pkg_split[0] @@ -191,19 +180,31 @@ def read_value(args): logger.debug(revlink) if os.path.exists(revlink): mappedpkg = os.path.basename(os.readlink(revlink)) - qvar = args.valuename - if qvar == "PKGSIZE": - # append packagename - qvar = "%s_%s" % (args.valuename, mappedpkg) - # PKGSIZE is now in bytes, but we we want it in KB - pkgsize = (int(readvar(revlink, qvar)) + 1024 // 2) // 1024 - value = "%d" % pkgsize - else: - value = readvar(revlink, qvar) + qvars = args.valuenames + val_names = qvars.split(',') + values = [] + for qvar in val_names: + if qvar == "PACKAGE": + value = mappedpkg + else: + value = readvar(revlink, qvar, mappedpkg) + if qvar == "PKGSIZE": + # PKGSIZE is now in bytes, but we we want it in KB + pkgsize = (int(value) + 1024 // 2) // 1024 + value = "%d" % pkgsize + if args.unescape: + import codecs + # escape_decode() unescapes backslash encodings in byte streams + value = codecs.escape_decode(bytes(value, "utf-8"))[0].decode("utf-8") + values.append(value) + + values_str = ' '.join(values) if args.prefix_name: - print('%s %s' % (pkg_name, value)) + print('%s %s' % (pkg_name, values_str)) else: - print(value) + print(values_str) + else: + logger.debug("revlink %s does not exist", revlink) def lookup_pkglist(pkgs, pkgdata_dir, reverse): if reverse: @@ -221,7 +222,7 @@ def lookup_pkglist(pkgs, pkgdata_dir, reverse): with open(pkgfile, 'r') as f: for line in f: fields = line.rstrip().split(': ') - if fields[0] == 'PKG_%s' % pkg: + if fields[0] == 'PKG:%s' % pkg: mappings[pkg].append(fields[1]) break return mappings @@ -249,32 +250,74 @@ def lookup_pkg(args): print('\n'.join(items)) def lookup_recipe(args): + def parse_pkgdatafile(pkgdatafile): + with open(pkgdatafile, 'r') as f: + found = False + for line in f: + if line.startswith('PN:'): + print("%s" % line.split(':', 1)[1].strip()) + found = True + break + if not found: + logger.error("Unable to find PN entry in %s" % pkgdatafile) + sys.exit(1) + # Handle both multiple arguments and multiple values within an arg (old syntax) pkgs = [] for pkgitem in args.pkg: pkgs.extend(pkgitem.split()) - mappings = defaultdict(list) for pkg in pkgs: - pkgfile = os.path.join(args.pkgdata_dir, 'runtime-reverse', pkg) - if os.path.exists(pkgfile): - with open(pkgfile, 'r') as f: - for line in f: - fields = line.rstrip().split(': ') - if fields[0] == 'PN': - mappings[pkg].append(fields[1]) - break - if len(mappings) < len(pkgs): - missing = list(set(pkgs) - set(mappings.keys())) - logger.error("The following packages could not be found: %s" % ', '.join(missing)) - sys.exit(1) - - items = [] - for pkg in pkgs: - items.extend(mappings.get(pkg, [])) - print('\n'.join(items)) + providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg) + if os.path.exists(providepkgpath): + for f in os.listdir(providepkgpath): + if f != pkg: + print("%s is in the RPROVIDES of %s:" % (pkg, f)) + pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f) + parse_pkgdatafile(pkgdatafile) + continue + pkgdatafile = os.path.join(args.pkgdata_dir, 'runtime-reverse', pkg) + if os.path.exists(pkgdatafile): + parse_pkgdatafile(pkgdatafile) + else: + if args.carryon: + print("The following packages could not be found: %s" % pkg) + else: + logger.error("The following packages could not be found: %s" % pkg) + sys.exit(1) def package_info(args): + def parse_pkgdatafile(pkgdatafile): + vars = ['PKGV', 'PKGE', 'PKGR', 'PN', 'PV', 'PE', 'PR', 'PKGSIZE'] + if args.extra: + vars += args.extra + with open(pkgdatafile, 'r') as f: + vals = dict() + extra = '' + for line in f: + for var in vars: + m = re.match(var + '(?::\S+)?:\s*(.+?)\s*$', line) + if m: + vals[var] = m.group(1) + pkg_version = vals['PKGV'] or '' + recipe = vals['PN'] or '' + recipe_version = vals['PV'] or '' + pkg_size = vals['PKGSIZE'] or '' + if 'PKGE' in vals: + pkg_version = vals['PKGE'] + ":" + pkg_version + if 'PKGR' in vals: + pkg_version = pkg_version + "-" + vals['PKGR'] + if 'PE' in vals: + recipe_version = vals['PE'] + ":" + recipe_version + if 'PR' in vals: + recipe_version = recipe_version + "-" + vals['PR'] + if args.extra: + for var in args.extra: + if var in vals: + val = re.sub(r'\s+', ' ', vals[var]) + extra += ' "%s"' % val + print("%s %s %s %s %s%s" % (pkg, pkg_version, recipe, recipe_version, pkg_size, extra)) + # Handle both multiple arguments and multiple values within an arg (old syntax) packages = [] if args.file: @@ -290,44 +333,20 @@ def package_info(args): logger.error("No packages specified") sys.exit(1) - mappings = defaultdict(lambda: defaultdict(str)) - for pkg in packages: - pkgfile = os.path.join(args.pkgdata_dir, 'runtime-reverse', pkg) - if os.path.exists(pkgfile): - with open(pkgfile, 'r') as f: - for line in f: - fields = line.rstrip().split(': ') - if fields[0].endswith("_" + pkg): - k = fields[0][:len(fields[0]) - len(pkg) - 1] - else: - k = fields[0] - v = fields[1] if len(fields) == 2 else "" - mappings[pkg][k] = v - - if len(mappings) < len(packages): - missing = list(set(packages) - set(mappings.keys())) - logger.error("The following packages could not be found: %s" % - ', '.join(missing)) - sys.exit(1) - - items = [] for pkg in packages: - pkg_version = mappings[pkg]['PKGV'] - if mappings[pkg]['PKGE']: - pkg_version = mappings[pkg]['PKGE'] + ":" + pkg_version - if mappings[pkg]['PKGR']: - pkg_version = pkg_version + "-" + mappings[pkg]['PKGR'] - recipe = mappings[pkg]['PN'] - recipe_version = mappings[pkg]['PV'] - if mappings[pkg]['PE']: - recipe_version = mappings[pkg]['PE'] + ":" + recipe_version - if mappings[pkg]['PR']: - recipe_version = recipe_version + "-" + mappings[pkg]['PR'] - pkg_size = mappings[pkg]['PKGSIZE'] - - items.append("%s %s %s %s %s" % - (pkg, pkg_version, recipe, recipe_version, pkg_size)) - print('\n'.join(items)) + providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg) + if os.path.exists(providepkgpath): + for f in os.listdir(providepkgpath): + if f != pkg: + print("%s is in the RPROVIDES of %s:" % (pkg, f)) + pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f) + parse_pkgdatafile(pkgdatafile) + continue + pkgdatafile = os.path.join(args.pkgdata_dir, "runtime-reverse", pkg) + if not os.path.exists(pkgdatafile): + logger.error("Unable to find any built runtime package named %s" % pkg) + sys.exit(1) + parse_pkgdatafile(pkgdatafile) def get_recipe_pkgs(pkgdata_dir, recipe, unpackaged): recipedatafile = os.path.join(pkgdata_dir, recipe) @@ -379,21 +398,16 @@ def list_pkgs(args): return False return True + pkglist = [] if args.recipe: packages = get_recipe_pkgs(args.pkgdata_dir, args.recipe, args.unpackaged) if args.runtime: - pkglist = [] runtime_pkgs = lookup_pkglist(packages, args.pkgdata_dir, False) for rtpkgs in runtime_pkgs.values(): pkglist.extend(rtpkgs) else: pkglist = packages - - for pkg in pkglist: - if matchpkg(pkg): - found = True - print("%s" % pkg) else: if args.runtime: searchdir = 'runtime-reverse' @@ -404,9 +418,13 @@ def list_pkgs(args): for fn in files: if fn.endswith('.packaged'): continue - if matchpkg(fn): - found = True - print("%s" % fn) + pkglist.append(fn) + + for pkg in sorted(pkglist): + if matchpkg(pkg): + found = True + print("%s" % pkg) + if not found: if args.pkgspec: logger.error("Unable to find any package matching %s" % args.pkgspec) @@ -416,6 +434,26 @@ def list_pkgs(args): def list_pkg_files(args): import json + def parse_pkgdatafile(pkgdatafile, long=False): + with open(pkgdatafile, 'r') as f: + found = False + for line in f: + if line.startswith('FILES_INFO:'): + found = True + val = line.split(': ', 1)[1].strip() + dictval = json.loads(val) + if long: + width = max(map(len, dictval), default=0) + for fullpth in sorted(dictval): + print("\t{:{width}}\t{}".format(fullpth, dictval[fullpth], width=width)) + else: + for fullpth in sorted(dictval): + print("\t%s" % fullpth) + break + if not found: + logger.error("Unable to find FILES_INFO entry in %s" % pkgdatafile) + sys.exit(1) + if args.recipe: if args.pkg: @@ -445,25 +483,22 @@ def list_pkg_files(args): continue logger.error("Unable to find any built runtime package named %s" % pkg) sys.exit(1) + parse_pkgdatafile(pkgdatafile, args.long) + else: + providepkgpath = os.path.join(args.pkgdata_dir, "runtime-rprovides", pkg) + if os.path.exists(providepkgpath): + for f in os.listdir(providepkgpath): + if f != pkg: + print("%s is in the RPROVIDES of %s:" % (pkg, f)) + pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", f) + parse_pkgdatafile(pkgdatafile, args.long) + continue pkgdatafile = os.path.join(args.pkgdata_dir, "runtime", pkg) if not os.path.exists(pkgdatafile): logger.error("Unable to find any built recipe-space package named %s" % pkg) sys.exit(1) - - with open(pkgdatafile, 'r') as f: - found = False - for line in f: - if line.startswith('FILES_INFO:'): - found = True - val = line.split(':', 1)[1].strip() - dictval = json.loads(val) - for fullpth in sorted(dictval): - print("\t%s" % fullpth) - break - if not found: - logger.error("Unable to find FILES_INFO entry in %s" % pkgdatafile) - sys.exit(1) + parse_pkgdatafile(pkgdatafile, args.long) def find_path(args): import json @@ -474,7 +509,7 @@ def find_path(args): with open(os.path.join(root,fn)) as f: for line in f: if line.startswith('FILES_INFO:'): - val = line.split(':', 1)[1].strip() + val = line.split(': ', 1)[1].strip() dictval = json.loads(val) for fullpth in dictval.keys(): if fnmatch.fnmatchcase(fullpth, args.targetpath): @@ -517,19 +552,22 @@ def main(): 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') parser_list_pkg_files.add_argument('-p', '--recipe', help='Report on all packages produced by the specified recipe') parser_list_pkg_files.add_argument('-u', '--unpackaged', help='Include unpackaged (i.e. empty) packages (only useful with -p/--recipe)', action='store_true') + parser_list_pkg_files.add_argument('-l', '--long', help='Show more information per file', action='store_true') parser_list_pkg_files.set_defaults(func=list_pkg_files) parser_lookup_recipe = subparsers.add_parser('lookup-recipe', help='Find recipe producing one or more packages', description='Looks up the specified runtime package(s) to see which recipe they were produced by') parser_lookup_recipe.add_argument('pkg', nargs='+', help='Runtime package name to look up') + parser_lookup_recipe.add_argument('-c', '--continue', dest="carryon", help='Continue looking up recipes even if we can not find one', action='store_true') parser_lookup_recipe.set_defaults(func=lookup_recipe) parser_package_info = subparsers.add_parser('package-info', - help='Shows version, recipe and size information for one or more packages', + help='Show version, recipe and size information for one or more packages', description='Looks up the specified runtime package(s) and display information') parser_package_info.add_argument('pkg', nargs='*', help='Runtime package name to look up') parser_package_info.add_argument('-f', '--file', help='Read package names from the specified file (one per line, first field only)') + parser_package_info.add_argument('-e', '--extra', help='Extra variables to display, e.g., LICENSE (can be specified multiple times)', action='append') parser_package_info.set_defaults(func=package_info) parser_find_path = subparsers.add_parser('find-path', @@ -541,10 +579,11 @@ def main(): parser_read_value = subparsers.add_parser('read-value', help='Read any pkgdata value for one or more packages', description='Reads the named value from the pkgdata files for the specified packages') - parser_read_value.add_argument('valuename', help='Name of the value to look up') + parser_read_value.add_argument('valuenames', help='Name of the value/s to look up (separated by commas, no spaces)') parser_read_value.add_argument('pkg', nargs='*', help='Runtime package name to look up') parser_read_value.add_argument('-f', '--file', help='Read package names from the specified file (one per line, first field only)') parser_read_value.add_argument('-n', '--prefix-name', help='Prefix output with package name', action='store_true') + parser_read_value.add_argument('-u', '--unescape', help='Expand escapes such as \\n', action='store_true') parser_read_value.set_defaults(func=read_value) parser_glob = subparsers.add_parser('glob', @@ -568,8 +607,14 @@ def main(): logger.error("Unable to find bitbake by searching parent directory of this script or PATH") sys.exit(1) logger.debug('Found bitbake path: %s' % bitbakepath) + if not os.environ.get('BUILDDIR', ''): + logger.error("This script can only be run after initialising the build environment (e.g. by using oe-init-build-env)") + sys.exit(1) tinfoil = tinfoil_init() - args.pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR', True) + try: + args.pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR') + finally: + tinfoil.shutdown() logger.debug('Value of PKGDATA_DIR is "%s"' % args.pkgdata_dir) if not args.pkgdata_dir: logger.error('Unable to determine pkgdata directory from PKGDATA_DIR') |