diff options
Diffstat (limited to 'py/config/options.py')
-rw-r--r-- | py/config/options.py | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/py/config/options.py b/py/config/options.py new file mode 100644 index 0000000000..e4165e51ee --- /dev/null +++ b/py/config/options.py @@ -0,0 +1,283 @@ +class Option(object): + """ + Base class for all Options + + .. py:attribute:: undef=True + + Whether to undefine the option in the header file when "disabled". + + .. py:attribute:: limit=None + + List or min,max to restrict the option to. Depends on option type. + + .. py:attribute:: quote=False + + Whether to quote the value in the header. + + .. py:attribute:: tag=list + + List of tags for this option. At least one is required. + """ + + tag_map = { + "general": "General settings", + "build": "Build options", + "network": "Network option", + "storage": "Storage option" + } + + + def __init__(self, value=None): + self.name = self.__class__.__name__ + + + # Do not set a default if no_default set. + if not hasattr(self, "no_default"): + self.no_default = True + + # Whether to quote the value + if not hasattr(self, "quote"): + self.quote = False + + # Tag sanity check. + if not hasattr(self, "tag") or not self.tag: + self._fatal("At least one tag is required") + elif type(self.tag) is not list: + self._fatal("%s.tag: must be a list().") + elif not set(self.tag).issubset(self.tag_map): + missing = [x for x in self.tag if x not in self.tag_map] + self._fatal("Tag(s) %s do not exist." % missing) + else: + duplicates = set([x for x in self.tag if self.tag.count(x) > 1]) + if duplicates: + self._fatal("duplicate tags: %s" % ", ".join(duplicates)) + + + # Value limit + if not hasattr(self, "limit"): + self.limit = None + + if value is not None: + self.validate(value) + self.value = value + elif self.no_default and not hasattr(self, "value"): + raise Exception("no_default is set you must supply a value in bsp config") + else: + self.validate(self.value) + + def __add__(self, value): + """ + Hack around only a _set. Need a _convert and _set in each type of option. + + :rtype: Depends on subclass + :return: Two options added together + """ + current = self.value + self._set(value) + optsum = self.value + self.value = current + return current + optsum + + + def validate(self, value): + """Validate option.""" + self._fatal("Must be set in subclass.") + + + def set(self, value): + """Set option value""" + if value is None: +# self.value = self.default #XXX: why is this here, a artifact? + return + + self._set(value) + + + def _fatal(self, str): + """Fatal error""" + raise Exception("(%s)%s: %s" % (self.__class__.__bases__[0].__name__, self.__class__.__name__, str)) + + + def config_get(self): + """ + Get string suitable for config.cfg + + :rtype: string + :return: Pre-formatted Windows `.ini` block. + """ + + from textwrap import TextWrapper + + wrapper = TextWrapper() + wrapper.width = 75 + wrapper.initial_indent = "# " + wrapper.subsequent_indent = "# " + + opt = [] + opt += wrapper.wrap(self.descr.strip()) + opt += ["%s = %s" % (self.__class__.__name__, self._str_value())] + return "\n".join(opt) + + + def _str_value(self): + """ + Get option as a string. + + :rtype: string + :return: Option value as a string. + """ + raise Exception("Needs to be implmented in subclass.") + + + def set_config_header(self, ctx): + """ + 1. If value is an integer always define it beacuse it could be 0. + 2. If value is empty "" or boolean=False undefine it + 3. if self.undef == True (undefine if false) undefine it. + + :param ctx: waf context + """ + if type(self.value) is not int and not self.value and self.undef: + ctx.undefine(self.name) + return + self._set_config_header(ctx) + + + def set_config_build(self, ctx): + """ + Set option inside waf as part of the build. + + :param ctx: waf context + """ + if type(self.value) is list: + ctx.env.append_value(self.name, self.value) + else: + setattr(ctx.env, self.name, self.value) + + + +class Boolean(Option): + """Boolean option value.""" + + def validate(self, value): + """Validate as one of: 1, 0, true, false""" + + if type(value) is not bool: + self._fatal("Not a boolean value (True|False): %s" % type(value)) + + def _str_value(self): + return str(self.value) + + # XXX: This is wrong (works for now!) + def _set(self, value): + + if type(value) is str: + if value.lower() == "true": + value = True + elif value.lower() == "false": + value = False + else: + self._fatal("Internal error in Boolean._set()") + + self.validate(value) + self.value = value + + def _set_config_header(self, ctx): + """Set value in config header.""" + + if self.undef: + ctx.define_cond(self.name, 1 if self.value else 0) + else: + ctx.define(self.name, 0) + + + + +class String(Option): + def validate(self, value): + """Verify value is a string and is in `limit` if defined.""" + if type(value) is not str: + self._fatal("Not a string: %s (%s)" % (value, type(value))) + + if self.limit: + if type(limit) is not list: + self._fatal("Only lists are supported as a limiter for strings.") + + if value not in limit: + self._fatal("%s not in list of accepted values: %s" % (value, limit)) + + def _str_value(self): + return self.value + + def _set(self, value): + """Set string, strips bounding whitespace.""" + self.validate(value) + self.value = value.strip() + + def _set_config_header(self, ctx): + """Define in header.""" + ctx.define(self.name, self.value, quote=self.quote) + + +class StringList(Option): + def validate(self, value): + """Validate list of strings""" + if type(value) is not list: + self._fatal("Not a list: %s (%s)" % (value, type(value))) + + for v in value: + if type(v) is not str: + self._fatal("Value %s is not a String." % v) + +#XXX: Needs to be fixed. +# if self.limit: +# if type(limit) is not list: +# self._fatal("Only lists are supported as a limiter for strings.") + +# if value not in limit: +# self._fatal("%s not in list of accepted values: %s" % (value, limit)) + + def _str_value(self): + return " ".join(self.value) + + def _set(self, value): + """Make sure value is a list otherwise split into one delimited by whitespace.""" + + if type(value) is not list: + value = value.split(" ") + value = [x for x in value if x] + + self.validate(value) + self.value = value + + def _set_config_header(self, ctx): + ctx.define(self.name, self.value, quote=self.quote) + + + +class Integer(Option): + def validate(self, value): + """Verify value is an int and in limit if defined.""" + if type(value) is not int: + self._fatal("Not an integer: %s (%s)" % (value, type(value))) + + if self.limit: + if type(limit) is list: + if value not in limit: + self._fatal("%s not in list of accepted values: %s" % (value, limit)) + + if type(limit) is tuple: + min, max = limit + if value < min or value > max: + self._fatal("%s is outside min/max: %s/%s" % (value, min, max)) + + def _str_value(self): + return str(self.value) + + def _set(self, value): + value = int(value) #XXX: configparser doesn't convert this anymore, sigh. + self.validate(value) + self.value = value + + def _set_config_header(self, ctx): + ctx.define(self.name, self.value, quote=self.quote) |