[oe] [RFC] [PATCH 1/2] Implement variable typing

Chris Larson kergoth at gmail.com
Tue Nov 9 23:18:27 UTC 2010


From: Chris Larson <chris_larson at mentor.com>

This implementation consists of two components:

- oe.types python module, whose job it is to construct objects of the defined
  type for a given variable in the metadata
- typecheck.bbclass, which iterates over all configuration variables with a
  type defined and uses oe.types to check the validity of the values

This gives us a few benefits:

- Automatic sanity checking of all configuration variables with a defined type
- Avoid duplicating the "how do I make use of the value of this variable"
  logic between its users.  For variables like PATH, this is simply a split(),
  for boolean variables, the duplication can result in confusing, or even
  mismatched semantics (is this 0/1, empty/nonempty, what?)
- Make it easier to create a configuration UI, as the type information could
  be used to provide a better interface than a text edit box (e.g checkbox for
  'boolean', dropdown for 'choice')

This functionality is entirely opt-in right now.  To enable the configuration
variable type checking, simply INHERIT += "typecheck".  Example of a failing
type check:

BAZ = "foo"
BAZ[type] = "boolean"

$ bitbake -p
FATAL: BAZ: Invalid boolean value 'foo'
$

Examples of leveraging oe.types in a python snippet:

PACKAGES[type] = "list"

python () {
    import oe.types
    for pkg in oe.types.value("PACKAGES", d):
        bb.note("package: %s" % pkg)
}

LIBTOOL_HAS_SYSROOT = "yes"
LIBTOOL_HAS_SYSROOT[type] = "boolean"

python () {
    import oe.types
    assert(oe.types.value("LIBTOOL_HAS_SYSROOT", d) == True)
}

Signed-off-by: Chris Larson <chris_larson at mentor.com>
---
 classes/typecheck.bbclass |   12 +++++++
 lib/oe/types.py           |   77 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 0 deletions(-)
 create mode 100644 classes/typecheck.bbclass
 create mode 100644 lib/oe/types.py

diff --git a/classes/typecheck.bbclass b/classes/typecheck.bbclass
new file mode 100644
index 0000000..646cd4e
--- /dev/null
+++ b/classes/typecheck.bbclass
@@ -0,0 +1,12 @@
+# Check types of bitbake configuration variables
+#
+# See oe.types for details.
+
+python check_types() {
+    import oe.types
+    if isinstance(e, bb.event.ConfigParsed):
+        for key in e.data.keys():
+            if e.data.getVarFlag(key, "type"):
+                oe.types.value(key, e.data)
+}
+addhandler check_types
diff --git a/lib/oe/types.py b/lib/oe/types.py
new file mode 100644
index 0000000..df6785f
--- /dev/null
+++ b/lib/oe/types.py
@@ -0,0 +1,77 @@
+# Constructs objects of the specified type for a given variable in the
+# metadata.  The 'type' flag of the variable defines which of the factory
+# functions in this module will be called.
+#
+# If no type is defined, the value() function will simply return the expanded
+# string value as is.
+
+class OEList(list):
+    def __init__(self, value, separator):
+        self.separator = separator
+        __builtins__["list"].__init__(self, value)
+
+    def __str__(self):
+        return self.separator.join(self)
+
+def boolean(key, metadata):
+    value = metadata.getVar(key, True)
+    strvalue = str(value).lower()
+    if strvalue in ('yes', 'y', 'true', 't', '1'):
+        return True
+    elif strvalue in ('no', 'n', 'false', 'f', '0'):
+        return False
+    raise ValueError("Invalid boolean value '%s'" % strvalue)
+
+def list(key, metadata):
+    value = metadata.getVar(key, True)
+    separator = metadata.getVarFlag(key, "separator") or " "
+    return OEList(value.split(separator), separator)
+
+def integer(key, metadata):
+    return int(metadata.getVar(key, True))
+
+def choice(key, metadata):
+    value = metadata.getVar(key, True).upper()
+    choices = metadata.getVarFlag(key, "choices")
+    if not choices:
+        raise ValueError("No 'choices' flag set for variable  '%s'" % key)
+
+    for choice in choices.split():
+        if choice.upper() == value:
+            break
+    else:
+        raise ValueError("Invalid choice '%s' for '%s'.  Valid choices: %s" %
+                         (value, key, choices))
+    return value
+
+def regex(key, metadata):
+    import re
+    value = metadata.getVar(key, True)
+    flagval = 0
+    flags = metadata.getVarFlag(key, "regexflags")
+    if flags:
+        for flag in flags.split():
+            flag = flag.upper()
+            try:
+                flagval |= getattr(re, flag)
+            except AttributeError:
+                raise ValueError("Invalid regex flag '%s'" % flag)
+    try:
+        return re.compile(value, flagval)
+    except Exception, exc:
+        raise ValueError("Invalid value '%s' for regex(): %s" % (value, exc))
+
+def value(key, d):
+    import bb
+    var_type = d.getVarFlag(key, "type")
+    if var_type:
+        try:
+            func = globals()[var_type]
+        except KeyError:
+            raise TypeError("Invalid variable type: %s" % var_type)
+        try:
+            return func(key, d)
+        except ValueError, exc:
+            bb.fatal("%s: %s" % (key, str(exc)))
+    else:
+        return d.getVar(key, True)
-- 
1.7.2.3





More information about the Openembedded-devel mailing list