kconfiglib: Update to hide tracebacks for expected errors
Update Kconfiglib to upstream revision 9c0b562c94 to get this commit in: Add Kconfig.__init__() helper flag for suppressing tracebacks Tools that don't use standard_kconfig() currently generate spammy tracebacks for e.g. syntax errors. Add a suppress_traceback flag to Kconfig.__init__() for catching "expected" exceptions and printing them to stderr and exiting with status 1. Use it to make all tools consistently hide tracebacks. Use the new flag to hide tracebacks for expected exceptions in kconfig.py, lint.py, and genrest.py. Some menuconfig robustness tweaks for wonky terminals are included as well, and a new feature for customizing .config and autoconf.h header comments via environment variables. Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
parent
6118ca2785
commit
e181e1b773
5 changed files with 222 additions and 142 deletions
|
@ -105,7 +105,7 @@ def init():
|
|||
|
||||
args = parse_args()
|
||||
|
||||
kconf = kconfiglib.Kconfig(args.kconfig)
|
||||
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
|
||||
out_dir = args.out_dir
|
||||
index_desc = args.index_desc
|
||||
separate_all_index = args.separate_all_index
|
||||
|
|
|
@ -29,7 +29,8 @@ def main():
|
|||
args = parse_args()
|
||||
|
||||
print("Parsing Kconfig tree in " + args.kconfig_root)
|
||||
kconf = Kconfig(args.kconfig_root, warn_to_stderr=False)
|
||||
kconf = Kconfig(args.kconfig_root, warn_to_stderr=False,
|
||||
suppress_traceback=True)
|
||||
|
||||
# Warn for assignments to undefined symbols
|
||||
kconf.warn_assign_undef = True
|
||||
|
|
|
@ -554,7 +554,7 @@ from glob import iglob
|
|||
from os.path import dirname, exists, expandvars, islink, join, realpath
|
||||
|
||||
|
||||
VERSION = (13, 2, 0)
|
||||
VERSION = (13, 5, 0)
|
||||
|
||||
|
||||
# File layout:
|
||||
|
@ -773,8 +773,8 @@ class Kconfig(object):
|
|||
See Kconfig.load_config() as well.
|
||||
|
||||
srctree:
|
||||
The value of the $srctree environment variable when the configuration was
|
||||
loaded, or the empty string if $srctree wasn't set. This gives nice
|
||||
The value the $srctree environment variable had when the Kconfig instance
|
||||
was created, or the empty string if $srctree wasn't set. This gives nice
|
||||
behavior with os.path.join(), which treats "" as the current directory,
|
||||
without adding "./".
|
||||
|
||||
|
@ -789,13 +789,22 @@ class Kconfig(object):
|
|||
if multiple configurations are loaded with different values for $srctree.
|
||||
|
||||
config_prefix:
|
||||
The value of the $CONFIG_ environment variable when the configuration was
|
||||
loaded. This is the prefix used (and expected) on symbol names in .config
|
||||
files and C headers. Defaults to "CONFIG_". Used in the same way in the C
|
||||
tools.
|
||||
The value the CONFIG_ environment variable had when the Kconfig instance
|
||||
was created, or "CONFIG_" if CONFIG_ wasn't set. This is the prefix used
|
||||
(and expected) on symbol names in .config files and C headers. Used in
|
||||
the same way in the C tools.
|
||||
|
||||
Like for srctree, only the value of $CONFIG_ when the configuration is
|
||||
loaded matters.
|
||||
config_header:
|
||||
The value the KCONFIG_CONFIG_HEADER environment variable had when the
|
||||
Kconfig instance was created, or the empty string if
|
||||
KCONFIG_CONFIG_HEADER wasn't set. This string is inserted verbatim at the
|
||||
beginning of configuration files. See write_config().
|
||||
|
||||
header_header:
|
||||
The value the KCONFIG_AUTOHEADER_HEADER environment variable had when the
|
||||
Kconfig instance was created, or the empty string if
|
||||
KCONFIG_AUTOHEADER_HEADER wasn't set. This string is inserted verbatim at
|
||||
the beginning of header files. See write_autoconf().
|
||||
|
||||
filename/linenr:
|
||||
The current parsing location, for use in Python preprocessor functions.
|
||||
|
@ -810,11 +819,13 @@ class Kconfig(object):
|
|||
"_warn_assign_no_prompt",
|
||||
"choices",
|
||||
"comments",
|
||||
"config_header",
|
||||
"config_prefix",
|
||||
"const_syms",
|
||||
"defconfig_list",
|
||||
"defined_syms",
|
||||
"env_vars",
|
||||
"header_header",
|
||||
"kconfig_filenames",
|
||||
"m",
|
||||
"menus",
|
||||
|
@ -854,7 +865,7 @@ class Kconfig(object):
|
|||
#
|
||||
|
||||
def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True,
|
||||
encoding="utf-8"):
|
||||
encoding="utf-8", suppress_traceback=False):
|
||||
"""
|
||||
Creates a new Kconfig object by parsing Kconfig files.
|
||||
Note that Kconfig files are not the same as .config files (which store
|
||||
|
@ -919,7 +930,35 @@ class Kconfig(object):
|
|||
anyway.
|
||||
|
||||
Related PEP: https://www.python.org/dev/peps/pep-0538/
|
||||
|
||||
suppress_traceback (default: False):
|
||||
Helper for tools. When True, any EnvironmentError or KconfigError
|
||||
generated during parsing is caught, the exception message is printed
|
||||
to stderr together with the command name, and sys.exit(1) is called
|
||||
(which generates SystemExit).
|
||||
|
||||
This hides the Python traceback for "expected" errors like syntax
|
||||
errors in Kconfig files.
|
||||
|
||||
Other exceptions besides EnvironmentError and KconfigError are still
|
||||
propagated when suppress_traceback is True.
|
||||
"""
|
||||
try:
|
||||
self._init(filename, warn, warn_to_stderr, encoding)
|
||||
except (EnvironmentError, KconfigError) as e:
|
||||
if suppress_traceback:
|
||||
cmd = sys.argv[0] # Empty string if missisng
|
||||
if cmd:
|
||||
cmd += ": "
|
||||
# Some long exception messages have extra newlines for better
|
||||
# formatting when reported as an unhandled exception. Strip
|
||||
# them here.
|
||||
sys.exit(cmd + str(e).strip())
|
||||
raise
|
||||
|
||||
def _init(self, filename, warn, warn_to_stderr, encoding):
|
||||
# See __init__()
|
||||
|
||||
self._encoding = encoding
|
||||
|
||||
self.srctree = os.getenv("srctree", "")
|
||||
|
@ -943,6 +982,9 @@ class Kconfig(object):
|
|||
self._unset_match = _re_match(r"# {}([^ ]+) is not set".format(
|
||||
self.config_prefix))
|
||||
|
||||
self.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "")
|
||||
self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "")
|
||||
|
||||
self.syms = {}
|
||||
self.const_syms = {}
|
||||
self.defined_syms = []
|
||||
|
@ -1349,8 +1391,29 @@ class Kconfig(object):
|
|||
elif self.warn_assign_override:
|
||||
self._warn(msg, filename, linenr)
|
||||
|
||||
def write_autoconf(self, filename,
|
||||
header="/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"):
|
||||
def load_allconfig(self, filename):
|
||||
"""
|
||||
Helper for all*config. Loads (merges) the configuration file specified
|
||||
by KCONFIG_ALLCONFIG, if any. See Documentation/kbuild/kconfig.txt in
|
||||
the Linux kernel.
|
||||
|
||||
Disables warnings for duplicated assignments within configuration files
|
||||
for the duration of the call
|
||||
(kconf.warn_assign_override/warn_assign_redun = False), and restores
|
||||
the previous warning settings at the end. The KCONFIG_ALLCONFIG
|
||||
configuration file is expected to override symbols.
|
||||
|
||||
Exits with sys.exit() (which raises a SystemExit exception) and prints
|
||||
an error to stderr if KCONFIG_ALLCONFIG is set but the configuration
|
||||
file can't be opened.
|
||||
|
||||
filename:
|
||||
Command-specific configuration filename - "allyes.config",
|
||||
"allno.config", etc.
|
||||
"""
|
||||
load_allconfig(self, filename)
|
||||
|
||||
def write_autoconf(self, filename=None, header=None):
|
||||
r"""
|
||||
Writes out symbol values as a C header file, matching the format used
|
||||
by include/generated/autoconf.h in the kernel.
|
||||
|
@ -1364,22 +1427,37 @@ class Kconfig(object):
|
|||
like the modification time and possibly triggering redundant work in
|
||||
build tools.
|
||||
|
||||
filename:
|
||||
Self-explanatory.
|
||||
filename (default: None):
|
||||
Path to write header to.
|
||||
|
||||
header (default: "/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"):
|
||||
Text that will be inserted verbatim at the beginning of the file. You
|
||||
would usually want it enclosed in '/* */' to make it a C comment,
|
||||
and include a final terminating newline.
|
||||
If None (the default), the path in the environment variable
|
||||
KCONFIG_AUTOHEADER is used if set, and "include/generated/autoconf.h"
|
||||
otherwise. This is compatible with the C tools.
|
||||
|
||||
header (default: None):
|
||||
Text inserted verbatim at the beginning of the file. You would
|
||||
usually want it enclosed in '/* */' to make it a C comment, and
|
||||
include a trailing newline.
|
||||
|
||||
If None (the default), the value of the environment variable
|
||||
KCONFIG_AUTOHEADER_HEADER had when the Kconfig instance was created
|
||||
will be used if it was set, and no header otherwise. See the
|
||||
Kconfig.header_header attribute.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = os.getenv("KCONFIG_AUTOHEADER",
|
||||
"include/generated/autoconf.h")
|
||||
|
||||
self._write_if_changed(filename, self._autoconf_contents(header))
|
||||
|
||||
def _autoconf_contents(self, header):
|
||||
# write_autoconf() helper. Returns the contents to write as a string,
|
||||
# with 'header' at the beginning.
|
||||
# with 'header' or KCONFIG_AUTOHEADER_HEADER at the beginning.
|
||||
|
||||
# "".join()ed later
|
||||
chunks = [header]
|
||||
if header is None:
|
||||
header = self.header_header
|
||||
|
||||
chunks = [header] # "".join()ed later
|
||||
add = chunks.append
|
||||
|
||||
for sym in self.unique_defined_syms:
|
||||
|
@ -1415,9 +1493,8 @@ class Kconfig(object):
|
|||
|
||||
return "".join(chunks)
|
||||
|
||||
def write_config(self, filename=None,
|
||||
header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n",
|
||||
save_old=True, verbose=None):
|
||||
def write_config(self, filename=None, header=None, save_old=True,
|
||||
verbose=None):
|
||||
r"""
|
||||
Writes out symbol values in the .config format. The format matches the
|
||||
C implementation, including ordering.
|
||||
|
@ -1439,16 +1516,21 @@ class Kconfig(object):
|
|||
(OSError/IOError). KconfigError is never raised here.
|
||||
|
||||
filename (default: None):
|
||||
Filename to save configuration to (a string).
|
||||
Path to write configuration to (a string).
|
||||
|
||||
If None (the default), the filename in the environment variable
|
||||
If None (the default), the path in the environment variable
|
||||
KCONFIG_CONFIG is used if set, and ".config" otherwise. See
|
||||
standard_config_filename().
|
||||
|
||||
header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
||||
Text that will be inserted verbatim at the beginning of the file. You
|
||||
would usually want each line to start with '#' to make it a comment,
|
||||
and include a final terminating newline.
|
||||
header (default: None):
|
||||
Text inserted verbatim at the beginning of the file. You would
|
||||
usually want each line to start with '#' to make it a comment, and
|
||||
include a trailing newline.
|
||||
|
||||
if None (the default), the value of the environment variable
|
||||
KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will
|
||||
be used if it was set, and no header otherwise. See the
|
||||
Kconfig.config_header attribute.
|
||||
|
||||
save_old (default: True):
|
||||
If True and <filename> already exists, a copy of it will be saved to
|
||||
|
@ -1493,7 +1575,7 @@ class Kconfig(object):
|
|||
|
||||
def _config_contents(self, header):
|
||||
# write_config() helper. Returns the contents to write as a string,
|
||||
# with 'header' at the beginning.
|
||||
# with 'header' or KCONFIG_CONFIG_HEADER at the beginning.
|
||||
#
|
||||
# More memory friendly would be to 'yield' the strings and
|
||||
# "".join(_config_contents()), but it was a bit slower on my system.
|
||||
|
@ -1505,13 +1587,15 @@ class Kconfig(object):
|
|||
for sym in self.unique_defined_syms:
|
||||
sym._visited = False
|
||||
|
||||
if header is None:
|
||||
header = self.config_header
|
||||
|
||||
chunks = [header] # "".join()ed later
|
||||
add = chunks.append
|
||||
|
||||
# Did we just print an '# end of ...' comment?
|
||||
after_end_comment = False
|
||||
|
||||
# "".join()ed later
|
||||
chunks = [header]
|
||||
add = chunks.append
|
||||
|
||||
node = self.top_node
|
||||
while 1:
|
||||
# Jump to the next node with an iterative tree walk
|
||||
|
@ -1564,8 +1648,7 @@ class Kconfig(object):
|
|||
add("\n#\n# {}\n#\n".format(node.prompt[0]))
|
||||
after_end_comment = False
|
||||
|
||||
def write_min_config(self, filename,
|
||||
header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
||||
def write_min_config(self, filename, header=None):
|
||||
"""
|
||||
Writes out a "minimal" configuration file, omitting symbols whose value
|
||||
matches their default value. The format matches the one produced by
|
||||
|
@ -1581,12 +1664,17 @@ class Kconfig(object):
|
|||
(OSError/IOError). KconfigError is never raised here.
|
||||
|
||||
filename:
|
||||
Self-explanatory.
|
||||
Path to write minimal configuration to.
|
||||
|
||||
header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"):
|
||||
Text that will be inserted verbatim at the beginning of the file. You
|
||||
would usually want each line to start with '#' to make it a comment,
|
||||
and include a final terminating newline.
|
||||
header (default: None):
|
||||
Text inserted verbatim at the beginning of the file. You would
|
||||
usually want each line to start with '#' to make it a comment, and
|
||||
include a final terminating newline.
|
||||
|
||||
if None (the default), the value of the environment variable
|
||||
KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will
|
||||
be used if it was set, and no header otherwise. See the
|
||||
Kconfig.config_header attribute.
|
||||
|
||||
Returns a string with a message saying which file got saved. This is
|
||||
meant to reduce boilerplate in tools, which can do e.g.
|
||||
|
@ -1603,9 +1691,12 @@ class Kconfig(object):
|
|||
|
||||
def _min_config_contents(self, header):
|
||||
# write_min_config() helper. Returns the contents to write as a string,
|
||||
# with 'header' at the beginning.
|
||||
# with 'header' or KCONFIG_CONFIG_HEADER at the beginning.
|
||||
|
||||
chunks = [header]
|
||||
if header is None:
|
||||
header = self.config_header
|
||||
|
||||
chunks = [header] # "".join()ed later
|
||||
add = chunks.append
|
||||
|
||||
for sym in self.unique_defined_syms:
|
||||
|
@ -2122,9 +2213,9 @@ class Kconfig(object):
|
|||
# it's part of a different construct
|
||||
if self._reuse_tokens:
|
||||
self._reuse_tokens = False
|
||||
# self._tokens_i is known to be 1 here, because _parse_properties()
|
||||
# leaves it like that when it can't recognize a line (or parses
|
||||
# a help text)
|
||||
# self._tokens_i is known to be 1 here, because _parse_props()
|
||||
# leaves it like that when it can't recognize a line (or parses a
|
||||
# help text)
|
||||
return True
|
||||
|
||||
# readline() returns '' over and over at EOF, which we rely on for help
|
||||
|
@ -2141,7 +2232,7 @@ class Kconfig(object):
|
|||
|
||||
self._tokens = self._tokenize(line)
|
||||
# Initialize to 1 instead of 0 to factor out code from _parse_block()
|
||||
# and _parse_properties(). They immediately fetch self._tokens[0].
|
||||
# and _parse_props(). They immediately fetch self._tokens[0].
|
||||
self._tokens_i = 1
|
||||
|
||||
return True
|
||||
|
@ -2839,7 +2930,7 @@ class Kconfig(object):
|
|||
|
||||
sym.nodes.append(node)
|
||||
|
||||
self._parse_properties(node)
|
||||
self._parse_props(node)
|
||||
|
||||
if node.is_menuconfig and not node.prompt:
|
||||
self._warn("the menuconfig symbol {} has no prompt"
|
||||
|
@ -2925,7 +3016,7 @@ class Kconfig(object):
|
|||
|
||||
self.menus.append(node)
|
||||
|
||||
self._parse_properties(node)
|
||||
self._parse_props(node)
|
||||
self._parse_block(_T_ENDMENU, node, node)
|
||||
node.list = node.next
|
||||
|
||||
|
@ -2945,7 +3036,7 @@ class Kconfig(object):
|
|||
|
||||
self.comments.append(node)
|
||||
|
||||
self._parse_properties(node)
|
||||
self._parse_props(node)
|
||||
|
||||
prev.next = prev = node
|
||||
|
||||
|
@ -2977,7 +3068,7 @@ class Kconfig(object):
|
|||
|
||||
choice.nodes.append(node)
|
||||
|
||||
self._parse_properties(node)
|
||||
self._parse_props(node)
|
||||
self._parse_block(_T_ENDCHOICE, node, node)
|
||||
node.list = node.next
|
||||
|
||||
|
@ -3019,7 +3110,7 @@ class Kconfig(object):
|
|||
|
||||
return expr
|
||||
|
||||
def _parse_properties(self, node):
|
||||
def _parse_props(self, node):
|
||||
# Parses and adds properties to the MenuNode 'node' (type, 'prompt',
|
||||
# 'default's, etc.) Properties are later copied up to symbols and
|
||||
# choices in a separate pass after parsing, in e.g.
|
||||
|
@ -3045,7 +3136,7 @@ class Kconfig(object):
|
|||
|
||||
if t0 in _TYPE_TOKENS:
|
||||
# Relies on '_T_BOOL is BOOL', etc., to save a conversion
|
||||
self._set_type(node, t0)
|
||||
self._set_type(node.item, t0)
|
||||
if self._tokens[1] is not None:
|
||||
self._parse_prompt(node)
|
||||
|
||||
|
@ -3075,7 +3166,7 @@ class Kconfig(object):
|
|||
self._parse_cond()))
|
||||
|
||||
elif t0 in _DEF_TOKEN_TO_TYPE:
|
||||
self._set_type(node, _DEF_TOKEN_TO_TYPE[t0])
|
||||
self._set_type(node.item, _DEF_TOKEN_TO_TYPE[t0])
|
||||
node.defaults.append((self._parse_expr(False),
|
||||
self._parse_cond()))
|
||||
|
||||
|
@ -3176,13 +3267,15 @@ class Kconfig(object):
|
|||
self._reuse_tokens = True
|
||||
return
|
||||
|
||||
def _set_type(self, node, new_type):
|
||||
# UNKNOWN is falsy
|
||||
if node.item.orig_type and node.item.orig_type is not new_type:
|
||||
self._warn("{} defined with multiple types, {} will be used"
|
||||
.format(node.item.name_and_loc, TYPE_TO_STR[new_type]))
|
||||
def _set_type(self, sc, new_type):
|
||||
# Sets the type of 'sc' (symbol or choice) to 'new_type'
|
||||
|
||||
node.item.orig_type = new_type
|
||||
# UNKNOWN is falsy
|
||||
if sc.orig_type and sc.orig_type is not new_type:
|
||||
self._warn("{} defined with multiple types, {} will be used"
|
||||
.format(sc.name_and_loc, TYPE_TO_STR[new_type]))
|
||||
|
||||
sc.orig_type = new_type
|
||||
|
||||
def _parse_prompt(self, node):
|
||||
# 'prompt' properties override each other within a single definition of
|
||||
|
@ -3372,7 +3465,7 @@ class Kconfig(object):
|
|||
# The calculated sets might be larger than necessary as we don't do any
|
||||
# complex analysis of the expressions.
|
||||
|
||||
make_depend_on = _make_depend_on # Micro-optimization
|
||||
depend_on = _depend_on # Micro-optimization
|
||||
|
||||
# Only calculate _dependents for defined symbols. Constant and
|
||||
# undefined symbols could theoretically be selected/implied, but it
|
||||
|
@ -3383,29 +3476,29 @@ class Kconfig(object):
|
|||
# The prompt conditions
|
||||
for node in sym.nodes:
|
||||
if node.prompt:
|
||||
make_depend_on(sym, node.prompt[1])
|
||||
depend_on(sym, node.prompt[1])
|
||||
|
||||
# The default values and their conditions
|
||||
for value, cond in sym.defaults:
|
||||
make_depend_on(sym, value)
|
||||
make_depend_on(sym, cond)
|
||||
depend_on(sym, value)
|
||||
depend_on(sym, cond)
|
||||
|
||||
# The reverse and weak reverse dependencies
|
||||
make_depend_on(sym, sym.rev_dep)
|
||||
make_depend_on(sym, sym.weak_rev_dep)
|
||||
depend_on(sym, sym.rev_dep)
|
||||
depend_on(sym, sym.weak_rev_dep)
|
||||
|
||||
# The ranges along with their conditions
|
||||
for low, high, cond in sym.ranges:
|
||||
make_depend_on(sym, low)
|
||||
make_depend_on(sym, high)
|
||||
make_depend_on(sym, cond)
|
||||
depend_on(sym, low)
|
||||
depend_on(sym, high)
|
||||
depend_on(sym, cond)
|
||||
|
||||
# The direct dependencies. This is usually redundant, as the direct
|
||||
# dependencies get propagated to properties, but it's needed to get
|
||||
# invalidation solid for 'imply', which only checks the direct
|
||||
# dependencies (even if there are no properties to propagate it
|
||||
# to).
|
||||
make_depend_on(sym, sym.direct_dep)
|
||||
depend_on(sym, sym.direct_dep)
|
||||
|
||||
# In addition to the above, choice symbols depend on the choice
|
||||
# they're in, but that's handled automatically since the Choice is
|
||||
|
@ -3418,11 +3511,11 @@ class Kconfig(object):
|
|||
# The prompt conditions
|
||||
for node in choice.nodes:
|
||||
if node.prompt:
|
||||
make_depend_on(choice, node.prompt[1])
|
||||
depend_on(choice, node.prompt[1])
|
||||
|
||||
# The default symbol conditions
|
||||
for _, cond in choice.defaults:
|
||||
make_depend_on(choice, cond)
|
||||
depend_on(choice, cond)
|
||||
|
||||
def _add_choice_deps(self):
|
||||
# Choices also depend on the choice symbols themselves, because the
|
||||
|
@ -3776,7 +3869,7 @@ class Kconfig(object):
|
|||
.format(sym.name_and_loc))
|
||||
|
||||
def _parse_error(self, msg):
|
||||
raise KconfigError("{}couldn't parse '{}': {}".format(
|
||||
raise KconfigError("{}error: couldn't parse '{}': {}".format(
|
||||
"" if self.filename is None else
|
||||
"{}:{}: ".format(self.filename, self.linenr),
|
||||
self._line.strip(), msg))
|
||||
|
@ -5295,8 +5388,8 @@ class Choice(object):
|
|||
|
||||
self._cached_selection = _NO_CACHED_SELECTION
|
||||
|
||||
# is_constant is checked by _make_depend_on(). Just set it to avoid
|
||||
# having to special-case choices.
|
||||
# is_constant is checked by _depend_on(). Just set it to avoid having
|
||||
# to special-case choices.
|
||||
self.is_constant = self.is_optional = False
|
||||
|
||||
# See Kconfig._build_dep()
|
||||
|
@ -6117,17 +6210,9 @@ def standard_kconfig(description=None):
|
|||
metavar="KCONFIG",
|
||||
default="Kconfig",
|
||||
nargs="?",
|
||||
help="Kconfig file (default: Kconfig)")
|
||||
help="Top-level Kconfig file (default: Kconfig)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Suppress backtraces for expected exceptions
|
||||
try:
|
||||
return Kconfig(args.kconfig)
|
||||
except (EnvironmentError, KconfigError) as e:
|
||||
# Some long exception messages have extra newlines for better
|
||||
# formatting when reported as an unhandled exception. Strip them here.
|
||||
sys.exit(str(e).strip())
|
||||
return Kconfig(parser.parse_args().kconfig, suppress_traceback=True)
|
||||
|
||||
|
||||
def standard_config_filename():
|
||||
|
@ -6143,25 +6228,9 @@ def standard_config_filename():
|
|||
|
||||
def load_allconfig(kconf, filename):
|
||||
"""
|
||||
Helper for all*config. Loads (merges) the configuration file specified by
|
||||
KCONFIG_ALLCONFIG, if any. See Documentation/kbuild/kconfig.txt in the
|
||||
Linux kernel.
|
||||
|
||||
Disables warnings for duplicated assignments within configuration files for
|
||||
the duration of the call (kconf.warn_assign_override/warn_assign_redun = False),
|
||||
and restores the previous warning settings at the end. The
|
||||
KCONFIG_ALLCONFIG configuration file is expected to override symbols.
|
||||
|
||||
Exits with sys.exit() (which raises a SystemExit exception) and prints an
|
||||
error to stderr if KCONFIG_ALLCONFIG is set but the configuration file
|
||||
can't be opened.
|
||||
|
||||
kconf:
|
||||
Kconfig instance to load the configuration in.
|
||||
|
||||
filename:
|
||||
Command-specific configuration filename - "allyes.config",
|
||||
"allno.config", etc.
|
||||
Use Kconfig.load_allconfig() instead, which was added in Kconfiglib 13.4.0.
|
||||
Supported for backwards compatibility. Might be removed at some point after
|
||||
a long period of deprecation warnings.
|
||||
"""
|
||||
allconfig = os.getenv("KCONFIG_ALLCONFIG")
|
||||
if allconfig is None:
|
||||
|
@ -6237,7 +6306,7 @@ def _visibility(sc):
|
|||
return vis
|
||||
|
||||
|
||||
def _make_depend_on(sc, expr):
|
||||
def _depend_on(sc, expr):
|
||||
# Adds 'sc' (symbol or choice) as a "dependee" to all symbols in 'expr'.
|
||||
# Constant symbols in 'expr' are skipped as they can never change value
|
||||
# anyway.
|
||||
|
@ -6245,11 +6314,11 @@ def _make_depend_on(sc, expr):
|
|||
if expr.__class__ is tuple:
|
||||
# AND, OR, NOT, or relation
|
||||
|
||||
_make_depend_on(sc, expr[1])
|
||||
_depend_on(sc, expr[1])
|
||||
|
||||
# NOTs only have a single operand
|
||||
if expr[0] is not NOT:
|
||||
_make_depend_on(sc, expr[2])
|
||||
_depend_on(sc, expr[2])
|
||||
|
||||
elif not expr.is_constant:
|
||||
# Non-constant symbol, or choice
|
||||
|
|
|
@ -151,7 +151,7 @@ def init_kconfig():
|
|||
BOARD_DIR="boards/*/*",
|
||||
ARCH="*")
|
||||
|
||||
kconf = kconfiglib.Kconfig()
|
||||
kconf = kconfiglib.Kconfig(suppress_traceback=True)
|
||||
|
||||
|
||||
def modules_file_dir():
|
||||
|
|
|
@ -137,13 +137,16 @@ If there's an error in the style definition or if a missing style is assigned
|
|||
to, the assignment will be ignored, along with a warning being printed on
|
||||
stderr.
|
||||
|
||||
The 'default' theme is always implicitly parsed first (or the 'monochrome'
|
||||
theme if the terminal lacks colors), so the following two settings have the
|
||||
same effect:
|
||||
The 'default' theme is always implicitly parsed first, so the following two
|
||||
settings have the same effect:
|
||||
|
||||
MENUCONFIG_STYLE="selection=fg:white,bg:red"
|
||||
MENUCONFIG_STYLE="default selection=fg:white,bg:red"
|
||||
|
||||
If the terminal doesn't support colors, the 'monochrome' theme is used, and
|
||||
MENUCONFIG_STYLE is ignored. The assumption is that the environment is broken
|
||||
somehow, and that the important thing is to get something usable.
|
||||
|
||||
|
||||
Other features
|
||||
==============
|
||||
|
@ -182,12 +185,15 @@ See the https://github.com/zephyrproject-rtos/windows-curses repository.
|
|||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
_IS_WINDOWS = os.name == "nt" # Are we running on Windows?
|
||||
|
||||
try:
|
||||
import curses
|
||||
except ImportError as e:
|
||||
if sys.platform != "win32":
|
||||
if not _IS_WINDOWS:
|
||||
raise
|
||||
sys.exit("""\
|
||||
menuconfig failed to import the standard Python 'curses' library. Try
|
||||
|
@ -206,7 +212,6 @@ Exception:
|
|||
|
||||
import errno
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
|
@ -312,19 +317,18 @@ _STYLES = {
|
|||
text=
|
||||
""",
|
||||
|
||||
# Blue tinted style loosely resembling lxdialog
|
||||
# Blue-tinted style loosely resembling lxdialog
|
||||
"aquatic": """
|
||||
path=fg:cyan,bg:blue,bold
|
||||
separator=fg:white,bg:cyan,bold
|
||||
help=path
|
||||
frame=fg:white,bg:cyan,bold
|
||||
body=fg:brightwhite,bg:blue
|
||||
body=fg:white,bg:blue
|
||||
edit=fg:black,bg:white
|
||||
"""
|
||||
}
|
||||
|
||||
# Standard colors definition
|
||||
_STYLE_STD_COLORS = {
|
||||
_NAMED_COLORS = {
|
||||
# Basic colors
|
||||
"black": curses.COLOR_BLACK,
|
||||
"red": curses.COLOR_RED,
|
||||
|
@ -550,9 +554,6 @@ def _style_to_curses(style_def):
|
|||
def parse_color(color_def):
|
||||
color_def = color_def.split(":", 1)[1]
|
||||
|
||||
if color_def in _STYLE_STD_COLORS:
|
||||
return _color_from_num(_STYLE_STD_COLORS[color_def])
|
||||
|
||||
# HTML format, #RRGGBB
|
||||
if re.match("#[A-Fa-f0-9]{6}", color_def):
|
||||
return _color_from_rgb((
|
||||
|
@ -560,19 +561,20 @@ def _style_to_curses(style_def):
|
|||
int(color_def[3:5], 16),
|
||||
int(color_def[5:7], 16)))
|
||||
|
||||
try:
|
||||
color_num = _color_from_num(int(color_def, 0))
|
||||
except ValueError:
|
||||
_warn("Ignoring color ", color_def, "that's neither predefined "
|
||||
"nor a number")
|
||||
|
||||
return -1
|
||||
if color_def in _NAMED_COLORS:
|
||||
color_num = _color_from_num(_NAMED_COLORS[color_def])
|
||||
else:
|
||||
try:
|
||||
color_num = _color_from_num(int(color_def, 0))
|
||||
except ValueError:
|
||||
_warn("Ignoring color", color_def, "that's neither "
|
||||
"predefined nor a number")
|
||||
return -1
|
||||
|
||||
if not -1 <= color_num < curses.COLORS:
|
||||
_warn("Ignoring color {}, which is outside the range "
|
||||
"-1..curses.COLORS-1 (-1..{})"
|
||||
.format(color_def, curses.COLORS - 1))
|
||||
|
||||
return -1
|
||||
|
||||
return color_num
|
||||
|
@ -605,15 +607,26 @@ def _style_to_curses(style_def):
|
|||
|
||||
def _init_styles():
|
||||
if curses.has_colors():
|
||||
curses.use_default_colors()
|
||||
try:
|
||||
curses.use_default_colors()
|
||||
except curses.error:
|
||||
# Ignore errors on funky terminals that support colors but not
|
||||
# using default colors. Worst it can do is break transparency and
|
||||
# the like. Ran across this with the MSYS2/winpty setup in
|
||||
# https://github.com/msys2/MINGW-packages/issues/5823, though there
|
||||
# seems to be a lot of general brokenness there.
|
||||
pass
|
||||
|
||||
# Use the 'monochrome' style template as the base on terminals without
|
||||
# color
|
||||
_parse_style("default" if curses.has_colors() else "monochrome", True)
|
||||
|
||||
# Add any user-defined style from the environment
|
||||
if "MENUCONFIG_STYLE" in os.environ:
|
||||
_parse_style(os.environ["MENUCONFIG_STYLE"], False)
|
||||
# Use the 'default' theme as the base, and add any user-defined style
|
||||
# settings from the environment
|
||||
_parse_style("default", True)
|
||||
if "MENUCONFIG_STYLE" in os.environ:
|
||||
_parse_style(os.environ["MENUCONFIG_STYLE"], False)
|
||||
else:
|
||||
# Force the 'monochrome' theme if the terminal doesn't support colors.
|
||||
# MENUCONFIG_STYLE is likely to mess things up here (though any colors
|
||||
# would be ignored), so ignore it.
|
||||
_parse_style("monochrome", True)
|
||||
|
||||
|
||||
# color_attribs holds the color pairs we've already created, indexed by a
|
||||
|
@ -3274,8 +3287,5 @@ def _change_c_lc_ctype_to_utf8():
|
|||
return
|
||||
|
||||
|
||||
# Are we running on Windows?
|
||||
_IS_WINDOWS = os.name == "nt"
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue