build/plat: improve handling of get_override().

The existing functionality of get_override was poorly specified and
ill-purposed for boolean flags. This change extracts the core
variable retrieval logic to a helper function and adds a new handler
`get_override_flag` which special cases boolean flags.

The new behavior will also perform type checking on kwargs and inform
the user of the desired type expected.
This commit is contained in:
Irides 2022-04-05 15:39:34 -05:00 committed by Catherine
parent 07c6ea5af2
commit 9eb208c332

View file

@ -315,6 +315,50 @@ class TemplatedPlatform(Platform):
rtlil_text, self._name_map = rtlil.convert_fragment(fragment, name=name)
# Retrieve an override specified in either the environment or as a kwarg.
# expected_type parameter is used to assert the type of kwargs, passing `None` will disable
# type checking.
def _extract_override(var, *, expected_type):
deprecated_var_env = "NMIGEN_{}".format(var)
var_env = "AMARANTH_{}".format(var)
if deprecated_var_env in os.environ or var_env in os.environ:
# On Windows, there is no way to define an "empty but set" variable; it is tempting
# to use a quoted empty string, but it doesn't do what one would expect. Recognize
# this as a useful pattern anyway, and treat `set VAR=""` on Windows the same way
# `export VAR=` is treated on Linux.
if var_env in os.environ:
var_env_value = os.environ[var_env]
elif deprecated_var_env in os.environ:
var_env_value = os.environ[deprecated_var_env]
return re.sub(r'^\"\"$', "", var_env_value)
elif var in kwargs:
if not isinstance(kwargs[var], expected_type) and not expected_type is None:
raise TypeError("Override '{}' must be a {}, not {!r}".format(var, expected_type.__name__, kwargs[var]))
else:
return kwargs[var]
else:
return jinja2.Undefined(name=var)
def get_override(var):
value = _extract_override(var, expected_type=str)
return value
def get_override_flag(var):
value = _extract_override(var, expected_type=bool)
if isinstance(value, str):
value = value.lower()
if value in ("0", "no", "n", "false", ""):
return False
if value in ("1", "yes", "y", "true"):
return True
else:
raise ValueError("Override '{}' must be one of "
"(\"0\", \"n\", \"no\", \"false\", \"\") "
"or "
"(\"1\", \"y\", \"yes\", \"true\"), not {!r}"
.format(var, value))
return value
def emit_rtlil():
return rtlil_text
@ -354,27 +398,6 @@ class TemplatedPlatform(Platform):
return "\n".join(commands)
def get_override(var):
deprecated_var_env = "NMIGEN_{}".format(var)
var_env = "AMARANTH_{}".format(var)
if deprecated_var_env in os.environ or var_env in os.environ:
# On Windows, there is no way to define an "empty but set" variable; it is tempting
# to use a quoted empty string, but it doesn't do what one would expect. Recognize
# this as a useful pattern anyway, and treat `set VAR=""` on Windows the same way
# `export VAR=` is treated on Linux.
if var_env in os.environ:
var_env_value = os.environ[var_env]
elif deprecated_var_env in os.environ:
var_env_value = os.environ[deprecated_var_env]
return re.sub(r'^\"\"$', "", var_env_value)
elif var in kwargs:
if isinstance(kwargs[var], str):
return textwrap.dedent(kwargs[var]).strip()
else:
return kwargs[var]
else:
return jinja2.Undefined(name=var)
@jinja2.pass_context
def invoke_tool(context, name):
env_var = tool_env_var(name)
@ -409,13 +432,13 @@ class TemplatedPlatform(Platform):
return '"' + re.sub(r"([$[\\])", r"\\\1", string) + '"'
def verbose(arg):
if get_override("verbose"):
if get_override_flag("verbose"):
return arg
else:
return jinja2.Undefined(name="quiet")
def quiet(arg):
if get_override("verbose"):
if get_override_flag("verbose"):
return jinja2.Undefined(name="quiet")
else:
return arg
@ -443,6 +466,7 @@ class TemplatedPlatform(Platform):
"syntax": syntax,
"invoke_tool": invoke_tool,
"get_override": get_override,
"get_override_flag": get_override_flag,
"verbose": verbose,
"quiet": quiet,
"autogenerated": autogenerated,