From: Paul Barker <paul@pbarker.dev>
To: openembedded-core@lists.openembedded.org
Cc: Paul Barker <paul@pbarker.dev>
Subject: [PATCH v3 1/4] oelib: utils: Support filtering default features
Date: Wed, 01 Apr 2026 18:41:56 +0100 [thread overview]
Message-ID: <20260401-default-features-v3-1-8f4b40401ab7@pbarker.dev> (raw)
In-Reply-To: <20260401-default-features-v3-0-8f4b40401ab7@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..a72a0f5983f1 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").strip(), "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").strip(), "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").strip(), "")
+
+ # 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").strip(), "alpha beta gamma")
--
2.43.0
next prev parent reply other threads:[~2026-04-01 17:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-01 17:41 [PATCH v3 0/4] Support opt-out of any default machine and distro features Paul Barker
2026-04-01 17:41 ` Paul Barker [this message]
2026-04-01 17:41 ` [PATCH v3 2/4] meta: Support opting out of any " Paul Barker
2026-04-22 14:45 ` [OE-core] " Jose Quaresma
[not found] ` <18A8B511426C8EDA.1516946@lists.openembedded.org>
2026-04-22 20:26 ` Jose Quaresma
2026-04-23 9:11 ` Paul Barker
2026-04-23 9:42 ` Jose Quaresma
[not found] ` <18A8F319FD743690.2028604@lists.openembedded.org>
2026-04-24 8:44 ` Jose Quaresma
2026-04-01 17:41 ` [PATCH v3 3/4] meta: Support opting out of any machine features Paul Barker
2026-04-01 17:41 ` [PATCH v3 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=20260401-default-features-v3-1-8f4b40401ab7@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.