diff mbox series

bb/utils: add layer_path() function

Message ID 20251117153649.3611181-1-ross.burton@arm.com
State New
Headers show
Series bb/utils: add layer_path() function | expand

Commit Message

Ross Burton Nov. 17, 2025, 3:36 p.m. UTC
Add layer_path() which will return the path to a layer. Useful to
programatically find other layers at build time, or from tinfoil.

Signed-off-by: Ross Burton <ross.burton@arm.com>
---
 lib/bb/tests/utils.py | 30 ++++++++++++++++++++++++++++++
 lib/bb/utils.py       | 16 ++++++++++++++++
 2 files changed, 46 insertions(+)

Comments

Richard Purdie Nov. 19, 2025, 12:35 p.m. UTC | #1
On Mon, 2025-11-17 at 15:36 +0000, Ross Burton via lists.openembedded.org wrote:
> diff --git a/lib/bb/utils.py b/lib/bb/utils.py
> index 366836bfc9..8106ada29c 100644
> --- a/lib/bb/utils.py
> +++ b/lib/bb/utils.py
> @@ -1902,6 +1902,22 @@ def get_file_layer(filename, d, collection_res={}):
>  
>      return result
>  
> +def layer_path(layername, d):
> +    """
> +    Return the path to the specified layer, or raises KeyError if the layer
> +    cannot be found.
> +    """
> +    bbpath = d.getVar("BBPATH").split(":")
> +    pattern = d.getVar('BBFILE_PATTERN_' + layername)
> +    if not pattern:
> +        raise KeyError(f"Cannot find BBFILE_PATTERN for {layername}")
> +
> +    # Sort and reverse to protect against BBFILE_PATTERNs that don't have
> +    # trailing slashes
> +    for path in reversed(sorted(bbpath)):
> +        if re.match(pattern, path + "/"):
> +            return path
> +    raise KeyError(f"Could not match BBFILE_PATTERN for {layername}")
>  
>  # Constant taken from http://linux.die.net/include/linux/prctl.h
>  PR_SET_PDEATHSIG = 1

I have a concern with this. I think having such an API is good but I am
worried about the implementation details. If we add this it means we
have two different pieces of code handling layer pattern matching. I'm
a bit worried this function could return one thing while the parse
process could do something slightly differently.

I think in the next development cycle, we may be better off clearing
out some of the legacy collection API since layers are clearly the
better solution to that problem. I'd hope that allows us to simplify
the code and allow a function like this to be abstracted.

Cheers,

Richard
diff mbox series

Patch

diff --git a/lib/bb/tests/utils.py b/lib/bb/tests/utils.py
index 52b7bf85bf..13c3c16a75 100644
--- a/lib/bb/tests/utils.py
+++ b/lib/bb/tests/utils.py
@@ -703,3 +703,33 @@  class FilemodeTests(unittest.TestCase):
         with self.assertRaises(ValueError):
             bb.utils.to_filemode("999")
 
+class LayerPathTests(unittest.TestCase):
+    def parsehelper(self, content, suffix=".bb"):
+        f = tempfile.NamedTemporaryFile(mode="wt", suffix=suffix)
+        f.write(content)
+        f.flush()
+        return f
+
+    def test_layer_path(self):
+        config = """
+BBPATH = "/layer/core:/layer/bsptwo:/layer/bsp:/layer/malformed"
+BBFILE_PATTERN_core = "^/layer/core/"
+BBFILE_PATTERN_bsp = "^/layer/bsp/"
+BBFILE_PATTERN_bsptwo = "^/layer/bsptwo/"
+BBFILE_PATTERN_malformed = "^/layer/mal-formed/"
+        """
+        d = bb.data.init()
+        bb.parse.siggen = bb.siggen.init(d)
+        with self.parsehelper(config) as f:
+            d = bb.parse.handle(f.name, d)['']
+
+        self.assertEqual(bb.utils.layer_path("core", d), "/layer/core")
+        self.assertEqual(bb.utils.layer_path("bsp", d), "/layer/bsp")
+        self.assertEqual(bb.utils.layer_path("bsptwo", d), "/layer/bsptwo")
+
+        with self.assertRaises(KeyError):
+            bb.utils.layer_path("no-such-layer", d)
+
+        with self.assertRaises(KeyError):
+            bb.utils.layer_path("malformed", d)
+
diff --git a/lib/bb/utils.py b/lib/bb/utils.py
index 366836bfc9..8106ada29c 100644
--- a/lib/bb/utils.py
+++ b/lib/bb/utils.py
@@ -1902,6 +1902,22 @@  def get_file_layer(filename, d, collection_res={}):
 
     return result
 
+def layer_path(layername, d):
+    """
+    Return the path to the specified layer, or raises KeyError if the layer
+    cannot be found.
+    """
+    bbpath = d.getVar("BBPATH").split(":")
+    pattern = d.getVar('BBFILE_PATTERN_' + layername)
+    if not pattern:
+        raise KeyError(f"Cannot find BBFILE_PATTERN for {layername}")
+
+    # Sort and reverse to protect against BBFILE_PATTERNs that don't have
+    # trailing slashes
+    for path in reversed(sorted(bbpath)):
+        if re.match(pattern, path + "/"):
+            return path
+    raise KeyError(f"Could not match BBFILE_PATTERN for {layername}")
 
 # Constant taken from http://linux.die.net/include/linux/prctl.h
 PR_SET_PDEATHSIG = 1