mirror of
https://git.yoctoproject.org/poky-contrib
synced 2025-05-08 23:52:25 +08:00

bblock script allows to lock/unlock recipes to latest task signatures. The idea is to prevent some recipes to be rebuilt during development. For example when working on rust recipe, one may not want rust-native to be rebuilt. This tool can be used, with proper environment set up, using the following command: bblock <recipe_name> See help for more details if a <recipe_name>'s task signature change, this task will not be built again and sstate cache will be used. [YOCTO #13425] (From OE-Core rev: 2d9ab0cfd7f3cacc347954676f1323342a6b286f) Signed-off-by: Julien Stephan <jstephan@baylibre.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
185 lines
5.5 KiB
Python
Executable File
185 lines
5.5 KiB
Python
Executable File
#!/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)
|