tools: Update kconfiglib to 13.7.1

This fixes the crash on MacOs under Python 3 and improves the menuconfig
colors on some terminals.
This commit is contained in:
Roland Dobai 2020-01-13 12:04:54 +01:00
parent 647cb628a1
commit 3909208852
2 changed files with 118 additions and 104 deletions

View File

@ -554,7 +554,7 @@ from glob import iglob
from os.path import dirname, exists, expandvars, islink, join, realpath
VERSION = (13, 3, 2)
VERSION = (13, 7, 1)
# File layout:
@ -865,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
@ -930,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 missing
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", "")
@ -1052,8 +1080,9 @@ class Kconfig(object):
self._readline = self._open(join(self.srctree, filename), "r").readline
try:
# Parse the Kconfig files
self._parse_block(None, self.top_node, self.top_node)
# Parse the Kconfig files. Returns the last node, which we
# terminate with '.next = None'.
self._parse_block(None, self.top_node, self.top_node).next = None
self.top_node.list = self.top_node.next
self.top_node.next = None
except UnicodeDecodeError as e:
@ -1363,6 +1392,28 @@ class Kconfig(object):
elif self.warn_assign_override:
self._warn(msg, filename, linenr)
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
@ -2163,9 +2214,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
@ -2182,7 +2233,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
@ -2844,7 +2895,7 @@ class Kconfig(object):
#
# prev:
# The previous menu node. New nodes will be added after this one (by
# modifying their 'next' pointer).
# modifying 'next' pointers).
#
# 'prev' is reused to parse a list of child menu nodes (for a menu or
# Choice): After parsing the children, the 'next' pointer is assigned
@ -2880,7 +2931,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"
@ -2966,7 +3017,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
@ -2986,7 +3037,7 @@ class Kconfig(object):
self.comments.append(node)
self._parse_properties(node)
self._parse_props(node)
prev.next = prev = node
@ -3018,7 +3069,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
@ -3036,17 +3087,16 @@ class Kconfig(object):
"no corresponding 'menu'" if t0 is _T_ENDMENU else
"unrecognized construct")
# End of file reached. Terminate the final node and return it.
# End of file reached. Return the last node.
if end_token:
raise KconfigError(
"expected '{}' at end of '{}'"
"error: expected '{}' at end of '{}'"
.format("endchoice" if end_token is _T_ENDCHOICE else
"endif" if end_token is _T_ENDIF else
"endmenu",
self.filename))
prev.next = None
return prev
def _parse_cond(self):
@ -3060,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.
@ -3086,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)
@ -3116,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()))
@ -3217,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
@ -3413,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
@ -3424,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
@ -3459,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
@ -3817,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))
@ -5336,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()
@ -6158,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():
@ -6184,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:
@ -6278,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.
@ -6286,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
@ -6744,8 +6772,7 @@ def _error_if_fn(kconf, _, cond, msg):
def _shell_fn(kconf, _, command):
# Only import as needed, to save some startup time
import subprocess
import subprocess # Only import as needed, to save some startup time
stdout, stderr = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE

View File

@ -328,10 +328,10 @@ _STYLES = {
# Blue-tinted style loosely resembling lxdialog
"aquatic": """
path=fg:cyan,bg:blue,bold
separator=fg:white,bg:cyan,bold
path=fg:white,bg:blue
separator=fg:white,bg:cyan
help=path
frame=fg:white,bg:cyan,bold
frame=fg:white,bg:cyan
body=fg:white,bg:blue
edit=fg:black,bg:white
"""
@ -1107,8 +1107,7 @@ def _enter_menu(menu):
global _menu_scroll
if not menu.is_menuconfig:
# Not a menu
return False
return False # Not a menu
shown_sub = _shown_nodes(menu)
# Never enter empty menus. We depend on having a current node.
@ -1349,7 +1348,6 @@ def _draw_main():
term_width = _width(_stdscr)
#
# Update the separator row below the menu path
#
@ -1396,7 +1394,6 @@ def _draw_main():
_menu_win.noutrefresh()
#
# Update the bottom separator window
#
@ -1421,7 +1418,6 @@ def _draw_main():
_bot_sep_win.noutrefresh()
#
# Update the help window, which shows either key bindings or help texts
#
@ -1442,7 +1438,6 @@ def _draw_main():
_help_win.noutrefresh()
#
# Update the top row with the menu path.
#
@ -2302,7 +2297,6 @@ def _draw_jump_to_dialog(edit_box, matches_win, bot_sep_win, help_win,
edit_width = _width(edit_box) - 2
#
# Update list of matches
#
@ -2333,7 +2327,6 @@ def _draw_jump_to_dialog(edit_box, matches_win, bot_sep_win, help_win,
matches_win.noutrefresh()
#
# Update bottom separator line
#
@ -2346,7 +2339,6 @@ def _draw_jump_to_dialog(edit_box, matches_win, bot_sep_win, help_win,
bot_sep_win.noutrefresh()
#
# Update help window at bottom
#
@ -2358,7 +2350,6 @@ def _draw_jump_to_dialog(edit_box, matches_win, bot_sep_win, help_win,
help_win.noutrefresh()
#
# Update edit box. We do this last since it makes it handy to position the
# cursor.
@ -2448,12 +2439,10 @@ def _info_dialog(node, from_jump_to_dialog):
# Support starting a search from within the information dialog
if from_jump_to_dialog:
# Avoid recursion
return
return # Avoid recursion
if _jump_to_dialog():
# Jumped to a symbol. Cancel the information dialog.
return
return # Jumped to a symbol. Cancel the information dialog.
# Stay in the information dialog if the jump-to dialog was
# canceled. Resize it in case the terminal was resized while the
@ -2500,7 +2489,6 @@ def _draw_info_dialog(node, lines, scroll, top_line_win, text_win,
text_win_height, text_win_width = text_win.getmaxyx()
# Note: The top row is deliberately updated last. See _draw_main().
#
@ -2514,7 +2502,6 @@ def _draw_info_dialog(node, lines, scroll, top_line_win, text_win,
text_win.noutrefresh()
#
# Update bottom separator line
#
@ -2527,7 +2514,6 @@ def _draw_info_dialog(node, lines, scroll, top_line_win, text_win,
bot_sep_win.noutrefresh()
#
# Update help window at bottom
#
@ -2539,7 +2525,6 @@ def _draw_info_dialog(node, lines, scroll, top_line_win, text_win,
help_win.noutrefresh()
#
# Update top row
#
@ -2598,8 +2583,7 @@ def _info_str(node):
_kconfig_def_info(choice)
)
# node.item in (MENU, COMMENT)
return _kconfig_def_info(node)
return _kconfig_def_info(node) # node.item in (MENU, COMMENT)
def _name_info(sc):
@ -2956,7 +2940,6 @@ def _edit_text(c, s, i, hscroll, width):
max_scroll = max(len(s) - width + 1, 0)
hscroll = min(i - width + _SCROLL_OFFSET + 1, max_scroll)
return s, i, hscroll
@ -3106,8 +3089,7 @@ def _check_valid(sym, s):
# Otherwise, displays an error and returns False.
if sym.orig_type not in (INT, HEX):
# Anything goes for non-int/hex symbols
return True
return True # Anything goes for non-int/hex symbols
base = 10 if sym.orig_type == INT else 16
try:
@ -3164,12 +3146,17 @@ def _is_num(name):
def _getch_compat(win):
# Uses get_wch() if available (Python 3.3+) and getch() otherwise. Also
# handles a PDCurses resizing quirk.
# Uses get_wch() if available (Python 3.3+) and getch() otherwise.
#
# Also falls back on getch() if get_wch() raises curses.error, to work
# around an issue when resizing the terminal on at least macOS Catalina.
# See https://github.com/ulfalizer/Kconfiglib/issues/84.
#
# Also handles a PDCurses resizing quirk.
if hasattr(win, "get_wch"):
try:
c = win.get_wch()
else:
except (AttributeError, curses.error):
c = win.getch()
if 0 <= c <= 255:
c = chr(c)