@@ -24,7 +24,24 @@ class RecipeParseError(Exception):
-def init_parser(settings, branch, bitbakepath, enable_tracking=False, nocheckout=False, classic=False, logger=None):
+def layer_addpylibs(layerdir):
+ """
+ Return the addpylib statements in a layer's conf/layer.conf, with LAYERDIR
+ expanded. The BitBake server only processes addpylib while parsing its base
+ configuration, so these need to go in bblayers.conf for its recipe parsing
+ to be able to use the libraries.
+ """
+ lines = []
+ try:
+ with open(os.path.join(layerdir, 'conf', 'layer.conf')) as f:
+ for line in f:
+ if re.match(r'\s*addpylib\s', line):
+ lines.append(line.strip().replace('${LAYERDIR}', layerdir))
+ except FileNotFoundError:
+ pass
+ return lines
+
+def init_parser(settings, branch, bitbakepath, enable_tracking=False, nocheckout=False, classic=False, logger=None, pylib_layerdirs=None):
if not (nocheckout or classic):
# Check out the branch of BitBake appropriate for this branch and clean out any stale files (e.g. *.pyc)
if re.match('[0-9a-f]{40}', branch.bitbake_branch):
@@ -86,6 +103,10 @@ def init_parser(settings, branch, bitbakepath, enable_tracking=False, nocheckout
# We need this to avoid problems with AVAILABLE_LICENSES
f.write('COREBASE = "%s"\n' % core_repodir)
f.write('BBLAYERS = "%s"\n' % core_layerdir)
+ # Python libraries of the layer being parsed and its dependencies
+ for layerdir in pylib_layerdirs or []:
+ for line in layer_addpylibs(layerdir):
+ f.write(line + '\n')
pass
if logger:
@@ -428,8 +428,15 @@ def main():
logger.warn("Unable to checkout dependent layer %s - %s" % (layerdependency.dependency, str(e)))
logger.info("Collecting data for layer %s on branch %s" % (layer.name, branchdesc))
+ # Layers whose addpylib libraries recipes may use (the core
+ # layer's are loaded through BBLAYERS)
+ pylib_layerdirs = [layerdir]
+ for dep in layerbranch.dependencies_set.all():
+ deplayerbranch = dep.dependency.get_layerbranch(branch.name)
+ if deplayerbranch and dep.dependency.name != settings.CORE_LAYER_NAME:
+ pylib_layerdirs.append(os.path.join(fetchdir, dep.dependency.get_fetch_dir(), deplayerbranch.vcs_subdir))
try:
- (tinfoil, tempdir) = recipeparse.init_parser(settings, branch, bitbakepath, nocheckout=options.nocheckout, logger=logger)
+ (tinfoil, tempdir) = recipeparse.init_parser(settings, branch, bitbakepath, nocheckout=options.nocheckout, logger=logger, pylib_layerdirs=pylib_layerdirs)
except recipeparse.RecipeParseError as e:
logger.error(str(e))
sys.exit(1)
@@ -144,6 +144,26 @@ def test_upgrade_recipe(import_layer, repo, db_access_without_rollback_and_trunc
assert recipe.filename == 'upgrademe_0.2.bb'
assert recipe.filepath == 'recipes-example/upgrademe'
+def test_addpylib_used_in_recipe(import_layer, repo, db_access_without_rollback_and_truncate):
+ # [YOCTO #16192] a recipe can use a Python library the layer adds with
+ # addpylib in conf/layer.conf, as it can in a build
+ from layerindex.models import LayerBranch, Recipe
+ layerdir = os.path.join(repo, 'meta-layerindex-test')
+ os.makedirs(os.path.join(layerdir, 'lib', 'layerindextestlib'))
+ with open(os.path.join(layerdir, 'lib', 'layerindextestlib', '__init__.py'), 'w') as f:
+ f.write('def summary():\n return "Summary from addpylib"\n')
+ with open(os.path.join(layerdir, 'conf', 'layer.conf'), 'a') as f:
+ f.write('\naddpylib ${LAYERDIR}/lib layerindextestlib\n')
+ os.makedirs(os.path.join(layerdir, 'recipes-example', 'pylib'))
+ with open(os.path.join(layerdir, 'recipes-example', 'pylib', 'pylib_1.0.bb'), 'w') as f:
+ f.write('SUMMARY = "${@layerindextestlib.summary()}"\nLICENSE = "MIT"\n')
+ run_cmd('git add -A && git commit -m "Add a recipe that uses addpylib"', cwd=repo)
+ run_cmd("layerindex/update.py -d -l meta-layerindex-test --nofetch --nocheckout")
+ layerbranch = LayerBranch.objects.get(layer__name='meta-layerindex-test')
+ recipe = Recipe.objects.filter(layerbranch=layerbranch, pn='pylib').first()
+ assert recipe, 'pylib recipe not found'
+ assert recipe.summary == 'Summary from addpylib'
+
def test_add_recipe(import_layer, repo, db_access_without_rollback_and_truncate):
from layerindex.models import LayerBranch, Recipe
layerbranch = LayerBranch.objects.get(layer__name='meta-layerindex-test')
A recipe that uses a Python library added with addpylib in its layer's conf/layer.conf failed to parse, e.g. meta-luneos with "NameError: name 'oebackport' is not defined". update_layer.py parses layer.conf itself, but the recipes are parsed by the BitBake server, which only processes addpylib in its base configuration, so the library was never imported there. Add the addpylib statements of the layer and its dependencies to the bblayers.conf the server reads. [YOCTO #16192] AI-Generated: Claude Opus 5.5 Signed-off-by: Tim Orling <tim.orling@konsulko.com> --- layerindex/recipeparse.py | 23 ++++++++++++++++++++++- layerindex/update_layer.py | 9 ++++++++- tests/test_update.py | 20 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-)