poky/bitbake/bin/bitbake-diffsigs
Enrico Jörns 287e2ede38 bitbake: bitbake-diffsigs: fix handling when finding only a single sigfile
This fixes the following error when calling 'bitbake-dumpsig' or
'bitbake-diffsigs' when having only a single sigfile available:

| Traceback (most recent call last):
|   File "[..]/poky/bitbake/bin/bitbake-dumpsig", line 171, in <module>
|     files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
|             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "[..]/poky/bitbake/bin/bitbake-dumpsig", line 83, in find_siginfo_task
|     sig2 = latestsigs[1]
|            ~~~~~~~~~~^^^
| IndexError: list index out of range

Handle this by adding (and returning) the path for the second sigfile
only if one is found. This way it will work for both diffsigs and
dumpsig use case.

The calling argparse code already deals with find_siginfo_task()
returning only a single file.
For 'bitbake-dumpsig' it will just dump the single sigfile, for
'bitbake-diffsigs' it will emit a proper error message again:

| ERROR: Only one matching sigdata file found for the specified task (systemd configure)

(Bitbake rev: 25057d33e9131f3214a06bbb316c916c744f8f03)

Signed-off-by: Enrico Jörns <ejo@pengutronix.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2024-07-02 22:29:27 +01:00

8.0 KiB
Executable File

#!/usr/bin/env python3

bitbake-diffsigs / bitbake-dumpsig

BitBake task signature data dump and comparison utility

Copyright (C) 2012-2013, 2017 Intel Corporation

SPDX-License-Identifier: GPL-2.0-only

import os import sys import warnings

warnings.simplefilter("default") import argparse import logging import pickle

sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))

import bb.tinfoil import bb.siggen import bb.msg

myname = os.path.basename(sys.argv[0]) logger = bb.msg.logger_create(myname)

is_dump = myname == 'bitbake-dumpsig'

def find_siginfo(tinfoil, pn, taskname, sigs=None): result = None tinfoil.set_event_mask(['bb.event.FindSigInfoResult', 'logging.LogRecord', 'bb.command.CommandCompleted', 'bb.command.CommandFailed']) ret = tinfoil.run_command('findSigInfo', pn, taskname, sigs) if ret: while True: event = tinfoil.wait_event(1) if event: if isinstance(event, bb.command.CommandCompleted): break elif isinstance(event, bb.command.CommandFailed): logger.error(str(event)) sys.exit(2) elif isinstance(event, bb.event.FindSigInfoResult): result = event.result elif isinstance(event, logging.LogRecord): logger.handle(event) else: logger.error('No result returned from findSigInfo command') sys.exit(2) return result

def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None): """ Find the most recent signature files for the specified PN/task """

if not taskname.startswith('do_'):
    taskname = 'do_%s' % taskname

if sig1 and sig2:
    sigfiles = find_siginfo(bbhandler, pn, taskname, [sig1, sig2])
    if not sigfiles:
        logger.error('No sigdata files found matching %s %s matching either %s or %s' % (pn, taskname, sig1, sig2))
        sys.exit(1)
    elif sig1 not in sigfiles:
        logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig1))
        sys.exit(1)
    elif sig2 not in sigfiles:
        logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig2))
        sys.exit(1)

    latestfiles = [sigfiles[sig1]['path'], sigfiles[sig2]['path']]
else:
    sigfiles = find_siginfo(bbhandler, pn, taskname)
    latestsigs = sorted(sigfiles.keys(), key=lambda h: sigfiles[h]['time'])[-2:]
    if not latestsigs:
        logger.error('No sigdata files found matching %s %s' % (pn, taskname))
        sys.exit(1)
    latestfiles = [sigfiles[latestsigs[0]]['path']]
    if len(latestsigs) > 1:
        latestfiles.append(sigfiles[latestsigs[1]]['path'])

return latestfiles

Define recursion callback

def recursecb(key, hash1, hash2): hashes = [hash1, hash2] hashfiles = find_siginfo(tinfoil, key, None, hashes)

recout = []
if not hashfiles:
    recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
elif hash1 not in hashfiles:
    recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
elif hash2 not in hashfiles:
    recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
else:
    out2 = bb.siggen.compare_sigfiles(hashfiles[hash1]['path'], hashfiles[hash2]['path'], recursecb, color=color)
    for change in out2:
        for line in change.splitlines():
            recout.append('    ' + line)

return recout

parser = argparse.ArgumentParser( description=("Dumps" if is_dump else "Compares") + " siginfo/sigdata files written out by BitBake")

parser.add_argument('-D', '--debug', help='Enable debug output', action='store_true')

if is_dump: parser.add_argument("-t", "--task", help="find the signature data file for the last run of the specified task", action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))

parser.add_argument("sigdatafile1",
                    help="Signature file to dump. Not used when using -t/--task.",
                    action="store", nargs='?', metavar="sigdatafile")

else: parser.add_argument('-c', '--color', help='Colorize the output (where %(metavar)s is %(choices)s)', choices=['auto', 'always', 'never'], default='auto', metavar='color')

parser.add_argument('-d', '--dump',
                    help='Dump the last signature data instead of comparing (equivalent to using bitbake-dumpsig)',
                    action='store_true')

parser.add_argument("-t", "--task",
                    help="find the signature data files for the last two runs of the specified task and compare them",
                    action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))

parser.add_argument("-s", "--signature",
                    help="With -t/--task, specify the signatures to look for instead of taking the last two",
                    action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))

parser.add_argument("sigdatafile1",
                    help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
                    action="store", nargs='?')

parser.add_argument("sigdatafile2",
                    help="Second signature file to compare",
                    action="store", nargs='?')

options = parser.parse_args() if is_dump: options.color = 'never' options.dump = True options.sigdatafile2 = None options.sigargs = None

if options.debug: logger.setLevel(logging.DEBUG)

color = (options.color == 'always' or (options.color == 'auto' and sys.stdout.isatty()))

if options.taskargs: with bb.tinfoil.Tinfoil() as tinfoil: tinfoil.prepare(config_only=True) if not options.dump and options.sigargs: files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1]) else: files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])

    if options.dump:
        logger.debug("Signature file: %s" % files[-1])
        output = bb.siggen.dump_sigfile(files[-1])
    else:
        if len(files) < 2:
            logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (
                options.taskargs[0], options.taskargs[1]))
            sys.exit(1)

        # Recurse into signature comparison
        logger.debug("Signature file (previous): %s" % files[-2])
        logger.debug("Signature file (latest): %s" % files[-1])
        output = bb.siggen.compare_sigfiles(files[-2], files[-1], recursecb, color=color)

else: if options.sigargs: logger.error('-s/--signature can only be used together with -t/--task') sys.exit(1) try: if not options.dump and options.sigdatafile1 and options.sigdatafile2: with bb.tinfoil.Tinfoil() as tinfoil: tinfoil.prepare(config_only=True) output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2, recursecb, color=color) elif options.sigdatafile1: output = bb.siggen.dump_sigfile(options.sigdatafile1) else: logger.error('Must specify signature file(s) or -t/--task') parser.print_help() sys.exit(1) except IOError as e: logger.error(str(e)) sys.exit(1) except (pickle.UnpicklingError, EOFError): logger.error('Invalid signature data - ensure you are specifying sigdata/siginfo files') sys.exit(1)

if output: print('\n'.join(output))