Skip to content

Commit aa26289

Browse files
ulfalizernashif
authored andcommitted
kconfig: Get rid of leading/trailing whitespace in prompts
Leading/trailing whitespace in prompts requires ugly workarounds in genrest.py, as e.g. *prompt * is invalid RST. strip() all prompts in Kconfiglib and get rid of the genrest.py workarounds. Add a warning too. The Kconfiglib update has some unrelated cleanups and fixes (that won't affect Zephyr). Signed-off-by: Ulf Magnusson <[email protected]>
1 parent f93ca23 commit aa26289

File tree

5 files changed

+117
-133
lines changed

5 files changed

+117
-133
lines changed

doc/scripts/genrest/genrest.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,9 @@ def write_kconfig_rst():
8888
# Add an index entry for the symbol that links to its RST file. Also
8989
# list its prompt(s), if any. (A symbol can have multiple prompts if it
9090
# has multiple definitions.)
91-
#
92-
# The strip() avoids RST choking on stuff like *foo *, when people
93-
# accidentally include leading/trailing whitespace in prompts.
9491
index_rst += " * - :option:`CONFIG_{}`\n - {}\n".format(
9592
sym.name,
96-
" / ".join(node.prompt[0].strip()
93+
" / ".join(node.prompt[0]
9794
for node in sym.nodes if node.prompt))
9895

9996
write_if_updated(os.path.join(out_dir, "index.rst"), index_rst)
@@ -104,7 +101,7 @@ def write_sym_rst(sym, out_dir):
104101
kconf = sym.kconfig
105102

106103
# List all prompts on separate lines
107-
prompt_str = "\n\n".join("*{}*".format(node.prompt[0].strip())
104+
prompt_str = "\n\n".join("*{}*".format(node.prompt[0])
108105
for node in sym.nodes if node.prompt) \
109106
or "*(No prompt -- not directly user assignable.)*"
110107

@@ -187,9 +184,7 @@ def menu_path(node):
187184
path = " → " + menu.prompt[0] + path
188185
menu = menu.parent
189186

190-
# The strip() avoids RST choking on leading/trailing whitespace in
191-
# prompts
192-
return ("(top menu)" + path).strip()
187+
return "(top menu)" + path
193188

194189
heading = "Kconfig definition"
195190
if len(sym.nodes) > 1:

drivers/crypto/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ config SYS_LOG_CRYPTO_LEVEL
4242
- 4 DEBUG, write SYS_LOG_DBG in addition to previous levels
4343

4444
config CRYPTO_TINYCRYPT_SHIM
45-
bool "Enable TinyCrypt shim driver [EXPERIMENTAL] "
45+
bool "Enable TinyCrypt shim driver [EXPERIMENTAL]"
4646
default n
4747
select TINYCRYPT
4848
select TINYCRYPT_AES
@@ -69,7 +69,7 @@ config CRYPTO_TINYCRYPT_SHIM_DRV_NAME
6969
Device name for TinyCrypt Pseudo device.
7070

7171
config CRYPTO_MBEDTLS_SHIM
72-
bool "Enable mbedTLS shim driver [EXPERIMENTAL] "
72+
bool "Enable mbedTLS shim driver [EXPERIMENTAL]"
7373
default n
7474
select MBEDTLS
7575
select MBEDTLS_ENABLE_HEAP

kernel/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ config INT_LATENCY_BENCHMARK
268268

269269
config EXECUTION_BENCHMARKING
270270
bool
271-
prompt "Timing metrics "
271+
prompt "Timing metrics"
272272
default n
273273
help
274274
This option enables the tracking of various times inside the kernel

scripts/kconfig/kconfiglib.py

Lines changed: 110 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,6 @@
9595
environment variable is referenced inside the Kconfig files.
9696
9797
98-
Gotcha
99-
******
100-
101-
It's important to set $SRCARCH even if you don't care about values and only
102-
want to extract information from Kconfig files, because the top-level Kconfig
103-
file does this (as of writing):
104-
105-
source "arch/$SRCARCH/Kconfig"
106-
107-
If $SRCARCH is not set, this expands to "arch//Kconfig", and arch/Kconfig
108-
happens to be an existing file, giving something that appears to work but is
109-
actually a truncated configuration. The available symbols will differ depending
110-
on the arch as well.
111-
112-
11398
Intro to symbol values
11499
======================
115100
@@ -745,7 +730,7 @@ def mainmenu_text(self):
745730
"""
746731
See the class documentation.
747732
"""
748-
return os.path.expandvars(self.top_node.prompt[0])
733+
return _expand(self.top_node.prompt[0])
749734

750735
@property
751736
def defconfig_filename(self):
@@ -758,7 +743,7 @@ def defconfig_filename(self):
758743
for filename, cond in self.defconfig_list.defaults:
759744
if expr_value(cond):
760745
try:
761-
with self._open(os.path.expandvars(filename.str_value)) as f:
746+
with self._open(_expand(filename.str_value)) as f:
762747
return f.name
763748
except IOError:
764749
continue
@@ -1943,20 +1928,20 @@ def _parse_block(self, end_token, parent, prev):
19431928
prev.next = prev = node
19441929

19451930
elif t0 == _T_SOURCE:
1946-
self._enter_file(os.path.expandvars(self._expect_str_and_eol()))
1931+
self._enter_file(_expand(self._expect_str_and_eol()))
19471932
prev = self._parse_block(None, parent, prev)
19481933
self._leave_file()
19491934

19501935
elif t0 == _T_RSOURCE:
19511936
self._enter_file(os.path.join(
19521937
os.path.dirname(self._filename),
1953-
os.path.expandvars(self._expect_str_and_eol())
1938+
_expand(self._expect_str_and_eol())
19541939
))
19551940
prev = self._parse_block(None, parent, prev)
19561941
self._leave_file()
19571942

19581943
elif t0 in (_T_GSOURCE, _T_GRSOURCE):
1959-
pattern = os.path.expandvars(self._expect_str_and_eol())
1944+
pattern = _expand(self._expect_str_and_eol())
19601945
if t0 == _T_GRSOURCE:
19611946
# Relative gsource
19621947
pattern = os.path.join(os.path.dirname(self._filename),
@@ -2132,21 +2117,9 @@ def _parse_properties(self, node):
21322117
continue
21332118

21342119
if t0 in _TYPE_TOKENS:
2135-
new_type = _TOKEN_TO_TYPE[t0]
2136-
2137-
if node.item.orig_type not in (UNKNOWN, new_type):
2138-
self._warn("{} defined with multiple types, {} will be used"
2139-
.format(_name_and_loc(node.item),
2140-
TYPE_TO_STR[new_type]))
2141-
2142-
node.item.orig_type = new_type
2143-
2120+
self._set_type(node, _TOKEN_TO_TYPE[t0])
21442121
if self._peek_token() is not None:
2145-
if node.prompt:
2146-
self._warn("{} defined with multiple prompts in single location"
2147-
.format(_name_and_loc(node.item)))
2148-
2149-
node.prompt = (self._expect_str(), self._parse_cond())
2122+
self._parse_prompt(node)
21502123

21512124
elif t0 == _T_DEPENDS:
21522125
if not self._check_token(_T_ON):
@@ -2155,59 +2128,7 @@ def _parse_properties(self, node):
21552128
node.dep = self._make_and(node.dep, self._parse_expr(True))
21562129

21572130
elif t0 == _T_HELP:
2158-
# Find first non-blank (not all-space) line and get its
2159-
# indentation
2160-
2161-
if node.help is not None:
2162-
self._warn("{} defined with more than one help text -- "
2163-
"only the last one will be used"
2164-
.format(_name_and_loc(node.item)))
2165-
2166-
# Small optimization. This code is pretty hot.
2167-
readline = self._file.readline
2168-
2169-
while 1:
2170-
line = readline()
2171-
self._linenr += 1
2172-
if not line or not line.isspace():
2173-
break
2174-
2175-
if not line:
2176-
self._warn("{} has 'help' but empty help text"
2177-
.format(_name_and_loc(node.item)))
2178-
2179-
node.help = ""
2180-
break
2181-
2182-
indent = _indentation(line)
2183-
if indent == 0:
2184-
# If the first non-empty lines has zero indent, there is no
2185-
# help text
2186-
self._warn("{} has 'help' but empty help text"
2187-
.format(_name_and_loc(node.item)))
2188-
2189-
node.help = ""
2190-
self._saved_line = line # "Unget" the line
2191-
break
2192-
2193-
help_lines = [_dedent_rstrip(line, indent)]
2194-
# Small optimization
2195-
add_help_line = help_lines.append
2196-
2197-
# The help text goes on till the first non-empty line with less
2198-
# indent
2199-
2200-
while 1:
2201-
line = readline()
2202-
self._linenr += 1
2203-
if not (line and (line.isspace() or \
2204-
_indentation(line) >= indent)):
2205-
break
2206-
2207-
add_help_line(_dedent_rstrip(line, indent))
2208-
2209-
node.help = "\n".join(help_lines).rstrip() + "\n"
2210-
self._saved_line = line # "Unget" the line
2131+
self._parse_help(node)
22112132

22122133
elif t0 == _T_SELECT:
22132134
if not isinstance(node.item, Symbol):
@@ -2228,27 +2149,12 @@ def _parse_properties(self, node):
22282149
self._parse_cond()))
22292150

22302151
elif t0 in (_T_DEF_BOOL, _T_DEF_TRISTATE):
2231-
new_type = _TOKEN_TO_TYPE[t0]
2232-
2233-
if node.item.orig_type not in (UNKNOWN, new_type):
2234-
self._warn("{} defined with multiple types, {} will be used"
2235-
.format(_name_and_loc(node.item),
2236-
TYPE_TO_STR[new_type]))
2237-
2238-
node.item.orig_type = new_type
2239-
2152+
self._set_type(node, _TOKEN_TO_TYPE[t0])
22402153
node.defaults.append((self._parse_expr(False),
22412154
self._parse_cond()))
22422155

22432156
elif t0 == _T_PROMPT:
2244-
# 'prompt' properties override each other within a single
2245-
# definition of a symbol, but additional prompts can be added
2246-
# by defining the symbol multiple times
2247-
if node.prompt:
2248-
self._warn("{} defined with multiple prompts in single location"
2249-
.format(_name_and_loc(node.item)))
2250-
2251-
node.prompt = (self._expect_str(), self._parse_cond())
2157+
self._parse_prompt(node)
22522158

22532159
elif t0 == _T_RANGE:
22542160
node.ranges.append((self._expect_sym(),
@@ -2263,15 +2169,15 @@ def _parse_properties(self, node):
22632169
env_var = self._expect_str_and_eol()
22642170
node.item.env_var = env_var
22652171

2266-
if env_var not in os.environ:
2172+
if env_var in os.environ:
2173+
node.defaults.append(
2174+
(self._lookup_const_sym(os.environ[env_var]),
2175+
self.y))
2176+
else:
22672177
self._warn("{1} has 'option env=\"{0}\"', "
22682178
"but the environment variable {0} is not "
22692179
"set".format(node.item.name, env_var),
22702180
self._filename, self._linenr)
2271-
else:
2272-
node.defaults.append(
2273-
(self._lookup_const_sym(os.environ[env_var]),
2274-
self.y))
22752181

22762182
elif self._check_token(_T_DEFCONFIG_LIST):
22772183
if not self.defconfig_list:
@@ -2329,6 +2235,92 @@ def _parse_properties(self, node):
23292235
self._tokens_i = -1
23302236
return
23312237

2238+
def _set_type(self, node, new_type):
2239+
if node.item.orig_type not in (UNKNOWN, new_type):
2240+
self._warn("{} defined with multiple types, {} will be used"
2241+
.format(_name_and_loc(node.item),
2242+
TYPE_TO_STR[new_type]))
2243+
2244+
node.item.orig_type = new_type
2245+
2246+
def _parse_prompt(self, node):
2247+
# 'prompt' properties override each other within a single definition of
2248+
# a symbol, but additional prompts can be added by defining the symbol
2249+
# multiple times
2250+
if node.prompt:
2251+
self._warn("{} defined with multiple prompts in single location"
2252+
.format(_name_and_loc(node.item)))
2253+
2254+
prompt = self._expect_str()
2255+
if prompt != prompt.strip():
2256+
self._warn("{} has leading or trailing whitespace in its prompt"
2257+
.format(_name_and_loc(node.item)))
2258+
2259+
# This avoid issues for e.g. reStructuredText documentation, where
2260+
# '*prompt *' is invalid
2261+
prompt = prompt.strip()
2262+
2263+
node.prompt = (prompt, self._parse_cond())
2264+
2265+
def _parse_help(self, node):
2266+
# Find first non-blank (not all-space) line and get its indentation
2267+
2268+
if node.help is not None:
2269+
self._warn("{} defined with more than one help text -- only the "
2270+
"last one will be used"
2271+
.format(_name_and_loc(node.item)))
2272+
2273+
# Small optimization. This code is pretty hot.
2274+
readline = self._file.readline
2275+
2276+
while 1:
2277+
line = readline()
2278+
self._linenr += 1
2279+
if not line or not line.isspace():
2280+
break
2281+
2282+
if not line:
2283+
self._warn("{} has 'help' but empty help text"
2284+
.format(_name_and_loc(node.item)))
2285+
2286+
node.help = ""
2287+
return
2288+
2289+
indent = _indentation(line)
2290+
if indent == 0:
2291+
# If the first non-empty lines has zero indent, there is no help
2292+
# text
2293+
self._warn("{} has 'help' but empty help text"
2294+
.format(_name_and_loc(node.item)))
2295+
2296+
node.help = ""
2297+
self._saved_line = line # "Unget" the line
2298+
return
2299+
2300+
# The help text goes on till the first non-empty line with less indent
2301+
# than the first line
2302+
2303+
help_lines = []
2304+
# Small optimization
2305+
add_help_line = help_lines.append
2306+
2307+
while line and (line.isspace() or _indentation(line) >= indent):
2308+
# De-indent 'line' by 'indent' spaces and rstrip() it to remove any
2309+
# newlines (which gets rid of other trailing whitespace too, but
2310+
# that's fine).
2311+
#
2312+
# This prepares help text lines in a speedy way: The [indent:]
2313+
# might already remove trailing newlines for lines shorter than
2314+
# indent (e.g. empty lines). The rstrip() makes it consistent,
2315+
# meaning we can join the lines with "\n" later.
2316+
add_help_line(line.expandtabs()[indent:].rstrip())
2317+
2318+
line = readline()
2319+
self._linenr += 1
2320+
2321+
node.help = "\n".join(help_lines).rstrip() + "\n"
2322+
self._saved_line = line # "Unget" the line
2323+
23322324
def _parse_expr(self, transform_m):
23332325
# Parses an expression from the tokens in Kconfig._tokens using a
23342326
# simple top-down approach. See the module docstring for the expression
@@ -4532,6 +4524,15 @@ def _make_depend_on(sym, expr):
45324524
_internal_error("Internal error while fetching symbols from an "
45334525
"expression with token stream {}.".format(expr))
45344526

4527+
def _expand(s):
4528+
# The predefined UNAME_RELEASE symbol is expanded in one of the 'default's
4529+
# of the DEFCONFIG_LIST symbol in the Linux kernel. This function maintains
4530+
# compatibility with it even though environment variables in strings are
4531+
# now expanded directly.
4532+
4533+
# platform.uname() has an internal cache, so this is speedy enough
4534+
return os.path.expandvars(s.replace("$UNAME_RELEASE", platform.uname()[2]))
4535+
45354536
def _parenthesize(expr, type_):
45364537
# expr_str() helper. Adds parentheses around expressions of type 'type_'.
45374538

@@ -4546,18 +4547,6 @@ def _indentation(line):
45464547
line = line.expandtabs()
45474548
return len(line) - len(line.lstrip())
45484549

4549-
def _dedent_rstrip(line, indent):
4550-
# De-indents 'line' by 'indent' spaces and rstrip()s it to remove any
4551-
# newlines (which gets rid of other trailing whitespace too, but that's
4552-
# fine).
4553-
#
4554-
# Used to prepare help text lines in a speedy way: The [indent:] might
4555-
# already remove trailing newlines for lines shorter than indent (e.g.
4556-
# empty lines). The rstrip() makes it consistent, meaning we can join the
4557-
# lines with "\n" later.
4558-
4559-
return line.expandtabs()[indent:].rstrip()
4560-
45614550
def _is_base_n(s, n):
45624551
try:
45634552
int(s, n)

subsys/settings/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ config SETTINGS_FCB_NUM_AREAS
4242
int
4343
default 8
4444
depends on SETTINGS && SETTINGS_FCB
45-
prompt "Number of flash areas used by the settings subsystem "
45+
prompt "Number of flash areas used by the settings subsystem"
4646
help
4747
Number of areas to allocate in the settings FCB. A smaller number is
4848
used if the flash hardware cannot support this value.

0 commit comments

Comments
 (0)