summaryrefslogtreecommitdiffstats
path: root/meta/lib/oe/maketype.py
diff options
context:
space:
mode:
authorChris Larson <chris_larson@mentor.com>2010-11-09 14:48:13 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-05-20 17:34:22 +0100
commite4921fda5b3a18c797acd267f2b1179ac032cd42 (patch)
treeb0a0df97faac10cbc8008e3db55cd81235b76379 /meta/lib/oe/maketype.py
parent4f5209ce31f1cc7fc0c97453b5247640c07e7f31 (diff)
downloadpoky-e4921fda5b3a18c797acd267f2b1179ac032cd42.tar.gz
Implement variable typing (sync from OE)
This implementation consists of two components: - Type creation python modules, 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.data for pkg in oe.data.typed_value("PACKAGES", d): bb.note("package: %s" % pkg) } LIBTOOL_HAS_SYSROOT = "yes" LIBTOOL_HAS_SYSROOT[type] = "boolean" python () { import oe.data assert(oe.data.typed_value("LIBTOOL_HAS_SYSROOT", d) == True) } (From OE-Core rev: a04ce490e933fc7534db33f635b025c25329c564) Signed-off-by: Chris Larson <chris_larson@mentor.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oe/maketype.py')
-rw-r--r--meta/lib/oe/maketype.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/meta/lib/oe/maketype.py b/meta/lib/oe/maketype.py
new file mode 100644
index 0000000000..0e9dbc67fb
--- /dev/null
+++ b/meta/lib/oe/maketype.py
@@ -0,0 +1,100 @@
1"""OpenEmbedded variable typing support
2
3Types are defined in the metadata by name, using the 'type' flag on a
4variable. Other flags may be utilized in the construction of the types. See
5the arguments of the type's factory for details.
6"""
7
8import bb
9import inspect
10import types
11
12available_types = {}
13
14class MissingFlag(TypeError):
15 """A particular flag is required to construct the type, but has not been
16 provided."""
17 def __init__(self, flag, type):
18 self.flag = flag
19 self.type = type
20 TypeError.__init__(self)
21
22 def __str__(self):
23 return "Type '%s' requires flag '%s'" % (self.type, self.flag)
24
25def factory(var_type):
26 """Return the factory for a specified type."""
27 if var_type is None:
28 raise TypeError("No type specified. Valid types: %s" %
29 ', '.join(available_types))
30 try:
31 return available_types[var_type]
32 except KeyError:
33 raise TypeError("Invalid type '%s':\n Valid types: %s" %
34 (var_type, ', '.join(available_types)))
35
36def create(value, var_type, **flags):
37 """Create an object of the specified type, given the specified flags and
38 string value."""
39 obj = factory(var_type)
40 objflags = {}
41 for flag in obj.flags:
42 if flag not in flags:
43 if flag not in obj.optflags:
44 raise MissingFlag(flag, var_type)
45 else:
46 objflags[flag] = flags[flag]
47
48 return obj(value, **objflags)
49
50def get_callable_args(obj):
51 """Grab all but the first argument of the specified callable, returning
52 the list, as well as a list of which of the arguments have default
53 values."""
54 if type(obj) is type:
55 obj = obj.__init__
56
57 args, varargs, keywords, defaults = inspect.getargspec(obj)
58 flaglist = []
59 if args:
60 if len(args) > 1 and args[0] == 'self':
61 args = args[1:]
62 flaglist.extend(args)
63
64 optional = set()
65 if defaults:
66 optional |= set(flaglist[-len(defaults):])
67 return flaglist, optional
68
69def factory_setup(name, obj):
70 """Prepare a factory for use."""
71 args, optional = get_callable_args(obj)
72 extra_args = args[1:]
73 if extra_args:
74 obj.flags, optional = extra_args, optional
75 obj.optflags = set(optional)
76 else:
77 obj.flags = obj.optflags = ()
78
79 if not hasattr(obj, 'name'):
80 obj.name = name
81
82def register(name, factory):
83 """Register a type, given its name and a factory callable.
84
85 Determines the required and optional flags from the factory's
86 arguments."""
87 factory_setup(name, factory)
88 available_types[factory.name] = factory
89
90
91# Register all our included types
92for name in dir(types):
93 if name.startswith('_'):
94 continue
95
96 obj = getattr(types, name)
97 if not callable(obj):
98 continue
99
100 register(name, obj)