From: Paul Barker <paul@pbarker.dev>
To: openembedded-core@lists.openembedded.org
Cc: Paul Barker <paul@pbarker.dev>
Subject: [PATCH v2 1/4] oelib: utils: Support filtering default features
Date: Tue, 31 Mar 2026 20:29:30 +0100 [thread overview]
Message-ID: <20260331-default-features-v2-1-f73b43d8bd57@pbarker.dev> (raw)
In-Reply-To: <20260331-default-features-v2-0-f73b43d8bd57@pbarker.dev>
The new library function filter_default_features() allows us to support
opting out of any default features without having to use :remove.
Signed-off-by: Paul Barker <paul@pbarker.dev>
---
meta/lib/oe/utils.py | 34 ++++++++++++++++++++++++++
meta/lib/oeqa/selftest/cases/oelib/utils.py | 38 ++++++++++++++++++++++++++++-
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/meta/lib/oe/utils.py b/meta/lib/oe/utils.py
index afcfeda0c6d5..52f2f1bd55e0 100644
--- a/meta/lib/oe/utils.py
+++ b/meta/lib/oe/utils.py
@@ -83,6 +83,31 @@ def set_intersect(variable1, variable2, d):
val2 = set(d.getVar(variable2).split())
return " ".join(val1 & val2)
+def set_difference(variable1, variable2, d):
+ """
+ Expand both variables, interpret them as lists of strings, and return the
+ intersection as a flattened string.
+
+ For example:
+ s1 = "a b c"
+ s2 = "b c d"
+ s3 = set_difference(s1, s2)
+ => s3 = "a"
+ """
+ val1 = d.getVar(variable1)
+ if not val1:
+ return ""
+ val2 = d.getVar(variable2)
+ if not val2:
+ return val1
+
+ val1 = set(val1.split())
+ val2 = set(val2.split())
+
+ # Return a sorted string to ensure that the result is consistent between
+ # parser runs.
+ return " ".join(sorted(val1 - val2))
+
def prune_suffix(var, suffixes, d):
# See if var ends with any of the suffixes listed and
# remove it if found
@@ -133,6 +158,15 @@ def features_backfill(var,d):
if addfeatures:
d.appendVar(var, " " + " ".join(addfeatures))
+def filter_default_features(varname, d):
+ # Process default features to exclude features which the user has opted out
+ # of. The result is appended to the target variable (e.g. DISTRO_FEATURES
+ # or MACHINE_FEATURES).
+ default_features = set_difference(varname + "_DEFAULTS",
+ varname + "_OPTED_OUT",
+ d)
+ d.appendVar(varname, " " + default_features)
+
def all_distro_features(d, features, truevalue="1", falsevalue=""):
"""
Returns truevalue if *all* given features are set in DISTRO_FEATURES,
diff --git a/meta/lib/oeqa/selftest/cases/oelib/utils.py b/meta/lib/oeqa/selftest/cases/oelib/utils.py
index 0cb46425a02d..f886b00e18ab 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/utils.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/utils.py
@@ -8,7 +8,7 @@ import sys
from unittest.case import TestCase
from contextlib import contextmanager
from io import StringIO
-from oe.utils import packages_filter_out_system, trim_version, multiprocess_launch
+from oe.utils import packages_filter_out_system, trim_version, multiprocess_launch, filter_default_features
class TestPackagesFilterOutSystem(TestCase):
def test_filter(self):
@@ -102,3 +102,39 @@ class TestMultiprocessLaunch(TestCase):
with captured_output() as (out, err):
self.assertRaises(bb.BBHandledException, multiprocess_launch, testfunction, ["1", "2", "3", "4", "5", "6"], d, extraargs=(d,))
self.assertIn("KeyError: 'Invalid number 2'", out.getvalue())
+
+
+class TestDefaultFeatures(TestCase):
+ def test_filter_default_features(self):
+ try:
+ import bb
+ d = bb.data_smart.DataSmart()
+ except ImportError:
+ self.skipTest("Cannot import bb")
+
+ # Test with nothing opted out
+ d.setVar("DISTRO_FEATURES", "")
+ d.setVar("DISTRO_FEATURES_DEFAULTS", "alpha beta gamma")
+ filter_default_features("DISTRO_FEATURES", d)
+ self.assertEqual(d.getVar("DISTRO_FEATURES"), "alpha beta gamma")
+
+ # opt out of a single feature
+ d.setVar("DISTRO_FEATURES", "")
+ d.setVar("DISTRO_FEATURES_DEFAULTS", "alpha beta gamma")
+ d.setVar("DISTRO_FEATURES_OPTED_OUT", "beta")
+ filter_default_features("DISTRO_FEATURES", d)
+ self.assertEqual(d.getVar("DISTRO_FEATURES"), "alpha gamma")
+
+ # opt out of everything
+ d.setVar("DISTRO_FEATURES", "")
+ d.setVar("DISTRO_FEATURES_DEFAULTS", "alpha beta gamma")
+ d.setVar("DISTRO_FEATURES_OPTED_OUT", "gamma alpha beta")
+ filter_default_features("DISTRO_FEATURES", d)
+ self.assertEqual(d.getVar("DISTRO_FEATURES"), "")
+
+ # opt out of something that isn't in our defaults
+ d.setVar("DISTRO_FEATURES", "")
+ d.setVar("DISTRO_FEATURES_DEFAULTS", "alpha beta gamma")
+ d.setVar("DISTRO_FEATURES_OPTED_OUT", "omega")
+ filter_default_features("DISTRO_FEATURES", d)
+ self.assertEqual(d.getVar("DISTRO_FEATURES"), "alpha beta gamma")
--
2.43.0
next prev parent reply other threads:[~2026-03-31 19:29 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 19:29 [PATCH v2 0/4] Support opt-out of any default machine and distro features Paul Barker
2026-03-31 19:29 ` Paul Barker [this message]
2026-03-31 19:29 ` [PATCH v2 2/4] meta: Support opting out of any " Paul Barker
2026-04-01 14:40 ` [OE-core] " Mathieu Dubois-Briand
2026-04-01 15:00 ` Paul Barker
2026-03-31 19:29 ` [PATCH v2 3/4] meta: Support opting out of any machine features Paul Barker
2026-03-31 19:29 ` [PATCH v2 4/4] lib: oe: Drop backfill support Paul Barker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260331-default-features-v2-1-f73b43d8bd57@pbarker.dev \
--to=paul@pbarker.dev \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox