Skip to contentSkip to conversation

bitbake-layers: flatten improvements

PATCH Applied Paul Eggleton 2 participants 5 messages Jan 8, 2012 – Jan 10, 2012

lore
Share & tools
lore
#0 lore raw

cover bitbake-layers: flatten improvements

A few patches improving the "flatten" subcommand in bitbake-layers, prompted by Yocto bug #1654, to allow only flattening some of the configured layers as well as warn when recipes/bbappends are outside the new flattened layer's paths. I'm hoping to be able to improve it further in future to be able to automatically put files in the correct place but this will have to wait until the next development cycle.

The patches (against Poky, but which apply cleanly against bitbake master with -p2) are available in the git repository at:
git://git.yoctoproject.org/poky-contrib paule/bitbake-layers-fix4
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=paule/bitbake-layers-fix4

Paul Eggleton (3):
bitbake-layers: flatten: allow specifying layers to flatten
bitbake-layers: flatten: warn the user if output structure is
incorrect
bitbake-layers: close files in apply_append()

 bitbake/bin/bitbake-layers |  115 ++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 107 insertions(+), 8 deletions(-)
Signature · 1 line
1.7.5.4
#1 lore raw

PATCH 1/3 bitbake-layers: flatten: allow specifying layers to flatten

You can now optionally specify two or more layers to flatten into the output, rather than flattening all of the layers in the current configuration (but this is still the default behaviour if no layers are specified). Note that this means the output layer may still contain bbappends where the corresponding recipes are not present in the list of layers to flatten. There is also a caveat when a layer not being flattened would be "inbetween" the flattened layers (see the command help for details.)

Implements feature request in [YOCTO #1564].

---
 bitbake/bin/bitbake-layers |   75 +++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 67 insertions(+), 8 deletions(-)
bitbake/bin/bitbake-layers +67 -8
index b2781bb..572487d 100755
@@ -139,9 +139,10 @@ Highest priority recipes are listed with the recipes they overlay as subitems.
     def do_flatten(self, args):
         """flattens layer configuration into a separate output directory.
 
-usage: flatten <outputdir>
+usage: flatten [layer1 layer2 [layer3]...] <outputdir>
 
-Takes the current layer configuration and builds a "flattened" directory
+Takes the specified layers (or all layers in the current layer
+configuration if none are specified) and builds a "flattened" directory
 containing the contents of all layers, with any overlayed recipes removed
 and bbappends appended to the corresponding recipes. Note that some manual
 cleanup may still be necessary afterwards, in particular:
@@ -149,21 +150,59 @@ cleanup may still be necessary afterwards, in particular:
 * where non-recipe files (such as patches) are overwritten (the flatten
   command will show a warning for these)
 * where anything beyond the normal layer setup has been added to
-  layer.conf (only the lowest priority layer's layer.conf is used)
+  layer.conf (only the lowest priority number layer's layer.conf is used)
 * overridden/appended items from bbappends will need to be tidied up
+
+Warning: if you flatten several layers where another layer is intended to
+be used "inbetween" them (in layer priority order) such that recipes /
+bbappends in the layers interact, and then attempt to use the new output
+layer together with that other layer, you may no longer get the same
+build results (as the layer priority order has effectively changed).
 """
         arglist = args.split()
-        if len(arglist) != 1:
+        if len(arglist) < 1:
             logger.error('Please specify an output directory')
             self.do_help('flatten')
             return
 
-        if os.path.exists(arglist[0]) and os.listdir(arglist[0]):
-            logger.error('Directory %s exists and is non-empty, please clear it out first' % arglist[0])
+        if len(arglist) == 2:
+            logger.error('If you specify layers to flatten you must specify at least two')
+            self.do_help('flatten')
+            return
+
+        outputdir = arglist[-1]
+        if os.path.exists(outputdir) and os.listdir(outputdir):
+            logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
             return
 
         self.check_prepare_cooker()
         layers = (self.config_data.getVar('BBLAYERS', True) or "").split()
+        if len(arglist) > 2:
+            layernames = arglist[:-1]
+            found_layernames = []
+            found_layerdirs = []
+            for layerdir in layers:
+                for layername, _, regex, _ in self.cooker.status.bbfile_config_priorities:
+                    if layername in layernames:
+                        if regex.match(os.path.join(layerdir, 'test')):
+                            found_layerdirs.append(layerdir)
+                            found_layernames.append(layername)
+                            break
+
+            for layername in layernames:
+                if not layername in found_layernames:
+                    logger.error('Unable to find layer %s in current configuration, please run "%s show_layers" to list configured layers' % (layername, os.path.basename(sys.argv[0])))
+                    return
+            layers = found_layerdirs
+
+        # Ensure a specified path matches our list of layers
+        def layer_path_match(path):
+            for layerdir in layers:
+                if path.startswith(os.path.join(layerdir, '')):
+                    return layerdir
+            return None
+
+        appended_recipes = []
         for layer in layers:
             overlayed = []
             for f in self.cooker.overlayed.iterkeys():
@@ -181,7 +220,7 @@ cleanup may still be necessary afterwards, in particular:
                         ext = os.path.splitext(f1)[1]
                         if ext != '.bbappend':
                             fdest = f1full[len(layer):]
-                            fdest = os.path.normpath(os.sep.join([arglist[0],fdest]))
+                            fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
                             bb.utils.mkdirhier(os.path.dirname(fdest))
                             if os.path.exists(fdest):
                                 if f1 == 'layer.conf' and root.endswith('/conf'):
@@ -196,7 +235,27 @@ cleanup may still be necessary afterwards, in particular:
                                     if appends:
                                         logger.plain('  Applying appends to %s' % fdest )
                                         for appendname in appends:
-                                            self.apply_append(appendname, fdest)
+                                            if layer_path_match(appendname):
+                                                self.apply_append(appendname, fdest)
+                                    appended_recipes.append(f1)
+
+        # Take care of when some layers are excluded and yet we have included bbappends for those recipes
+        for recipename in self.cooker_data.appends.iterkeys():
+            if recipename not in appended_recipes:
+                appends = self.cooker_data.appends[recipename]
+                first_append = None
+                for appendname in appends:
+                    layer = layer_path_match(appendname)
+                    if layer:
+                        if first_append:
+                            self.apply_append(appendname, first_append)
+                        else:
+                            fdest = appendname[len(layer):]
+                            fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
+                            bb.utils.mkdirhier(os.path.dirname(fdest))
+                            bb.utils.copyfile(appendname, fdest)
+                            first_append = fdest
+
 
     def get_append_layer(self, appendname):
         for layer, _, regex, _ in self.cooker.status.bbfile_config_priorities:
Signature · 1 line
1.7.5.4
#2 lore raw

PATCH 2/3 bitbake-layers: flatten: warn the user if output structure is incorrect

In reply to Paul Eggleton

If you flatten layers that have different directory structures you may not end up with a usable layer in the output directory - some files won't be picked up by BitBake.

To try to avoid this problem, once flattening has completed, get the BBFILES entries that correspond to the layer from which the output layer's conf/layer.conf came from, and check through all of the .bb/.bbappend files in the output directory to see if any will not be referred to by BBFILES in the output layer. If any are found, show a warning to the user.

---
 bitbake/bin/bitbake-layers |   38 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 38 insertions(+), 0 deletions(-)
bitbake/bin/bitbake-layers +38 -0
index 572487d..b4c4127 100755
@@ -8,6 +8,7 @@ import cmd
 import logging
 import os
 import sys
+import fnmatch
 
 bindir = os.path.dirname(__file__)
 topdir = os.path.dirname(bindir)
@@ -152,6 +153,8 @@ cleanup may still be necessary afterwards, in particular:
 * where anything beyond the normal layer setup has been added to
   layer.conf (only the lowest priority number layer's layer.conf is used)
 * overridden/appended items from bbappends will need to be tidied up
+* when the flattened layers do not have the same directory structure (the
+  flatten command should show a warning when this will cause a problem)
 
 Warning: if you flatten several layers where another layer is intended to
 be used "inbetween" them (in layer priority order) such that recipes /
@@ -194,6 +197,8 @@ build results (as the layer priority order has effectively changed).
                     logger.error('Unable to find layer %s in current configuration, please run "%s show_layers" to list configured layers' % (layername, os.path.basename(sys.argv[0])))
                     return
             layers = found_layerdirs
+        else:
+            layernames = []
 
         # Ensure a specified path matches our list of layers
         def layer_path_match(path):
@@ -256,6 +261,39 @@ build results (as the layer priority order has effectively changed).
                             bb.utils.copyfile(appendname, fdest)
                             first_append = fdest
 
+        # Get the regex for the first layer in our list (which is where the conf/layer.conf file will
+        # have come from)
+        first_regex = None
+        layerdir = layers[0]
+        for layername, pattern, regex, _ in self.cooker.status.bbfile_config_priorities:
+            if (not layernames) or layername in layernames:
+                if regex.match(os.path.join(layerdir, 'test')):
+                    first_regex = regex
+                    break
+
+        if first_regex:
+            # Find the BBFILES entries that match (which will have come from this conf/layer.conf file)
+            bbfiles = str(self.config_data.getVar('BBFILES', True)).split()
+            bbfiles_layer = []
+            for item in bbfiles:
+                if first_regex.match(item):
+                    newpath = os.path.join(outputdir, item[len(layerdir)+1:])
+                    bbfiles_layer.append(newpath)
+
+            if bbfiles_layer:
+                # Check that all important layer files match BBFILES
+                for root, dirs, files in os.walk(outputdir):
+                    for f1 in files:
+                        ext = os.path.splitext(f1)[1]
+                        if ext in ['.bb', '.bbappend']:
+                            f1full = os.sep.join([root, f1])
+                            entry_found = False
+                            for item in bbfiles_layer:
+                                if fnmatch.fnmatch(f1full, item):
+                                    entry_found = True
+                                    break
+                            if not entry_found:
+                                logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full)
 
     def get_append_layer(self, appendname):
         for layer, _, regex, _ in self.cooker.status.bbfile_config_priorities:
Signature · 1 line
1.7.5.4
#3 lore raw

PATCH 3/3 bitbake-layers: close files in apply_append()

In reply to Paul Eggleton

It's recommended practice to close files when finished with them and the code in this function was not doing this.

---
 bitbake/bin/bitbake-layers |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
bitbake/bin/bitbake-layers +2 -0
index b4c4127..b4cfd55 100755
@@ -307,6 +307,8 @@ build results (as the layer priority order has effectively changed).
         recipefile.write('\n')
         recipefile.write('##### bbappended from %s #####\n' % self.get_append_layer(appendname))
         recipefile.writelines(appendfile.readlines())
+        recipefile.close()
+        appendfile.close()
 
     def do_show_appends(self, args):
         """list bbappend files and recipe files they apply to
Signature · 1 line
1.7.5.4
#4 lore raw
In reply to Paul Eggleton
Quoted 13 lines · Paul Eggleton

A few patches improving the "flatten" subcommand in bitbake-layers, prompted by Yocto bug #1654, to allow only flattening some of the configured layers as well as warn when recipes/bbappends are outside the new flattened layer's paths. I'm hoping to be able to improve it further in future to be able to automatically put files in the correct place but this will have to wait until the next development cycle.

The patches (against Poky, but which apply cleanly against bitbake master with -p2) are available in the git repository at:
git://git.yoctoproject.org/poky-contrib paule/bitbake-layers-fix4
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=paule/bitbake-layers-fix4

Quoted 5 lines

Paul Eggleton (3):
bitbake-layers: flatten: allow specifying layers to flatten
bitbake-layers: flatten: warn the user if output structure is
incorrect
bitbake-layers: close files in apply_append()

Merged to master, thanks.

Richard