|
@@ -0,0 +1,184 @@
|
|
|
+#!/usr/bin/env python3
|
|
|
+# bblock
|
|
|
+# lock/unlock task to latest signature
|
|
|
+#
|
|
|
+# Copyright (c) 2023 BayLibre, SAS
|
|
|
+# Author: Julien Stepahn <jstephan@baylibre.com>
|
|
|
+#
|
|
|
+# SPDX-License-Identifier: GPL-2.0-only
|
|
|
+#
|
|
|
+
|
|
|
+import os
|
|
|
+import sys
|
|
|
+import logging
|
|
|
+
|
|
|
+scripts_path = os.path.dirname(os.path.realpath(__file__))
|
|
|
+lib_path = scripts_path + "/lib"
|
|
|
+sys.path = sys.path + [lib_path]
|
|
|
+
|
|
|
+import scriptpath
|
|
|
+
|
|
|
+scriptpath.add_bitbake_lib_path()
|
|
|
+
|
|
|
+import bb.tinfoil
|
|
|
+import bb.msg
|
|
|
+
|
|
|
+import argparse_oe
|
|
|
+
|
|
|
+myname = os.path.basename(sys.argv[0])
|
|
|
+logger = bb.msg.logger_create(myname)
|
|
|
+
|
|
|
+
|
|
|
+def getTaskSignatures(tinfoil, pn, tasks):
|
|
|
+ tinfoil.set_event_mask(
|
|
|
+ [
|
|
|
+ "bb.event.GetTaskSignatureResult",
|
|
|
+ "logging.LogRecord",
|
|
|
+ "bb.command.CommandCompleted",
|
|
|
+ "bb.command.CommandFailed",
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ ret = tinfoil.run_command("getTaskSignatures", pn, tasks)
|
|
|
+ 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.GetTaskSignatureResult):
|
|
|
+ sig = event.sig
|
|
|
+ elif isinstance(event, logging.LogRecord):
|
|
|
+ logger.handle(event)
|
|
|
+ else:
|
|
|
+ logger.error("No result returned from getTaskSignatures command")
|
|
|
+ sys.exit(2)
|
|
|
+ return sig
|
|
|
+
|
|
|
+
|
|
|
+def parseRecipe(tinfoil, recipe):
|
|
|
+ try:
|
|
|
+ tinfoil.parse_recipes()
|
|
|
+ d = tinfoil.parse_recipe(recipe)
|
|
|
+ except Exception:
|
|
|
+ logger.error("Failed to get recipe info for: %s" % recipe)
|
|
|
+ sys.exit(1)
|
|
|
+ return d
|
|
|
+
|
|
|
+
|
|
|
+def bblockDump(lockfile):
|
|
|
+ try:
|
|
|
+ with open(lockfile, "r") as lockfile:
|
|
|
+ for line in lockfile:
|
|
|
+ print(line.strip())
|
|
|
+ except IOError:
|
|
|
+ return 1
|
|
|
+ return 0
|
|
|
+
|
|
|
+
|
|
|
+def bblockReset(lockfile, pns, package_archs, tasks):
|
|
|
+ if not pns:
|
|
|
+ logger.info("Unlocking all recipes")
|
|
|
+ try:
|
|
|
+ os.remove(lockfile)
|
|
|
+ except FileNotFoundError:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ logger.info("Unlocking {pns}".format(pns=pns))
|
|
|
+ tmp_lockfile = lockfile + ".tmp"
|
|
|
+ with open(lockfile, "r") as infile, open(tmp_lockfile, "w") as outfile:
|
|
|
+ for line in infile:
|
|
|
+ if not (
|
|
|
+ any(element in line for element in pns)
|
|
|
+ and any(element in line for element in package_archs.split())
|
|
|
+ ):
|
|
|
+ outfile.write(line)
|
|
|
+ else:
|
|
|
+ if tasks and not any(element in line for element in tasks):
|
|
|
+ outfile.write(line)
|
|
|
+ os.remove(lockfile)
|
|
|
+ os.rename(tmp_lockfile, lockfile)
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ parser = argparse_oe.ArgumentParser(description="Lock and unlock a recipe")
|
|
|
+ parser.add_argument("pn", nargs="*", help="Space separated list of recipe to lock")
|
|
|
+ parser.add_argument(
|
|
|
+ "-t",
|
|
|
+ "--tasks",
|
|
|
+ help="Comma separated list of tasks",
|
|
|
+ type=lambda s: [
|
|
|
+ task if task.startswith("do_") else "do_" + task for task in s.split(",")
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ parser.add_argument(
|
|
|
+ "-r",
|
|
|
+ "--reset",
|
|
|
+ action="store_true",
|
|
|
+ help="Unlock pn recipes, or all recipes if pn is empty",
|
|
|
+ )
|
|
|
+ parser.add_argument(
|
|
|
+ "-d",
|
|
|
+ "--dump",
|
|
|
+ action="store_true",
|
|
|
+ help="Dump generated bblock.conf file",
|
|
|
+ )
|
|
|
+
|
|
|
+ global_args, unparsed_args = parser.parse_known_args()
|
|
|
+
|
|
|
+ with bb.tinfoil.Tinfoil() as tinfoil:
|
|
|
+ tinfoil.prepare(config_only=True)
|
|
|
+
|
|
|
+ package_archs = tinfoil.config_data.getVar("PACKAGE_ARCHS")
|
|
|
+ builddir = tinfoil.config_data.getVar("TOPDIR")
|
|
|
+ lockfile = "{builddir}/conf/bblock.conf".format(builddir=builddir)
|
|
|
+
|
|
|
+ if global_args.dump:
|
|
|
+ bblockDump(lockfile)
|
|
|
+ return 0
|
|
|
+
|
|
|
+ if global_args.reset:
|
|
|
+ bblockReset(lockfile, global_args.pn, package_archs, global_args.tasks)
|
|
|
+ return 0
|
|
|
+
|
|
|
+ with open(lockfile, "a") as lockfile:
|
|
|
+ s = ""
|
|
|
+ if lockfile.tell() == 0:
|
|
|
+ s = "# Generated by bblock\n"
|
|
|
+ s += 'SIGGEN_LOCKEDSIGS_TASKSIG_CHECK = "info"\n'
|
|
|
+ s += 'SIGGEN_LOCKEDSIGS_TYPES += "${PACKAGE_ARCHS}"\n'
|
|
|
+ s += "\n"
|
|
|
+
|
|
|
+ for pn in global_args.pn:
|
|
|
+ d = parseRecipe(tinfoil, pn)
|
|
|
+ package_arch = d.getVar("PACKAGE_ARCH")
|
|
|
+ siggen_locked_sigs_package_arch = d.getVar(
|
|
|
+ "SIGGEN_LOCKEDSIGS_{package_arch}".format(package_arch=package_arch)
|
|
|
+ )
|
|
|
+ sigs = getTaskSignatures(tinfoil, [pn], global_args.tasks)
|
|
|
+ for sig in sigs:
|
|
|
+ new_entry = "{pn}:{taskname}:{sig}".format(
|
|
|
+ pn=sig[0], taskname=sig[1], sig=sig[2]
|
|
|
+ )
|
|
|
+ if (
|
|
|
+ siggen_locked_sigs_package_arch
|
|
|
+ and not new_entry in siggen_locked_sigs_package_arch
|
|
|
+ ) or not siggen_locked_sigs_package_arch:
|
|
|
+ s += 'SIGGEN_LOCKEDSIGS_{package_arch} += "{new_entry}"\n'.format(
|
|
|
+ package_arch=package_arch, new_entry=new_entry
|
|
|
+ )
|
|
|
+ lockfile.write(s)
|
|
|
+ return 0
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ try:
|
|
|
+ ret = main()
|
|
|
+ except Exception:
|
|
|
+ ret = 1
|
|
|
+ import traceback
|
|
|
+
|
|
|
+ traceback.print_exc()
|
|
|
+ sys.exit(ret)
|