Skip to content

Commit 99d6120

Browse files
committed
build(bootstrap): handle empty input and "none" in prompt retry
The sanitizer prompt rejected empty input on retry attempts because validation only checked for empty/none on the first prompt, not after reprompt. Also, "none" was shown as a valid option but wasn't accepted. Fixes #1140
1 parent 8da09e3 commit 99d6120

File tree

1 file changed

+46
-33
lines changed

1 file changed

+46
-33
lines changed

bootstrap.py

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -581,44 +581,57 @@ def repl(match):
581581
def reprompt_option(self, name, prompt_text):
582582
return self.prompt_option(name, prompt_text, force_prompt=True)
583583

584+
def prompt_validated_option(self, name, prompt_text, valid_values, normalizer=None, allow_empty=False):
585+
"""
586+
Prompts for an option with validation and retry support.
587+
588+
:param name: The option name.
589+
:param prompt_text: The prompt to display.
590+
:param valid_values: List of valid values (canonical forms).
591+
:param normalizer: Optional function to normalize input before comparison.
592+
If None, uses case-insensitive comparison.
593+
:param allow_empty: If True, empty input is accepted (returns '').
594+
:return: The validated value.
595+
"""
596+
if normalizer is None:
597+
normalizer = lambda v: v.lower()
598+
599+
def match_value(input_val):
600+
if allow_empty and (not input_val or input_val.lower() == "none"):
601+
return ''
602+
for v in valid_values:
603+
if normalizer(v) == normalizer(input_val):
604+
return v
605+
return None
606+
607+
valid_display = ', '.join(valid_values)
608+
if allow_empty:
609+
valid_display += ', or none'
610+
611+
for attempt in range(2):
612+
if attempt == 0:
613+
value = self.prompt_option(name, prompt_text)
614+
else:
615+
value = self.reprompt_option(name, prompt_text)
616+
617+
matched = match_value(value)
618+
if matched is not None:
619+
setattr(self.options, name, matched)
620+
return matched
621+
622+
print(f"Invalid {name.replace('_', ' ')} '{value}'. Must be one of: {valid_display}.")
623+
624+
raise ValueError(f"Invalid {name.replace('_', ' ')} '{value}'. Must be one of: {valid_display}.")
625+
584626
def prompt_build_type_option(self, name):
585-
value = self.prompt_option(name, "Build type")
586627
valid_build_types = ["Debug", "Release", "RelWithDebInfo", "MinSizeRel", "OptimizedDebug", "DebugFast"]
587-
for t in valid_build_types:
588-
if t.lower().replace("-", "") == value.lower().replace("-", ""):
589-
if t == "DebugFast":
590-
value = "DebugFast"
591-
setattr(self.options, name, t)
592-
return value
593-
print(f"Invalid build type '{value}'. Must be one of: {', '.join(valid_build_types)}.")
594-
value = self.reprompt_option(name, "Build type")
595-
for t in valid_build_types:
596-
if t.lower().replace("-", "") == value.lower().replace("-", ""):
597-
if t == "DebugFast":
598-
value = "DebugFast"
599-
setattr(self.options, name, t)
600-
return value
601-
print(f"Invalid build type '{value}'. Must be one of: {', '.join(valid_build_types)}.")
602-
raise ValueError(f"Invalid build type '{value}'. Must be one of: {', '.join(valid_build_types)}.")
628+
normalizer = lambda v: v.lower().replace("-", "")
629+
return self.prompt_validated_option(name, "Build type", valid_build_types, normalizer=normalizer)
603630

604631
def prompt_sanitizer_option(self, name):
605-
value = self.prompt_option(name, "Sanitizer (asan/ubsan/msan/tsan/none)")
606-
if not value:
607-
value = ''
608-
return value
609632
valid_sanitizers = ["ASan", "UBSan", "MSan", "TSan"]
610-
for t in valid_sanitizers:
611-
if t.lower() == value.lower():
612-
setattr(self.options, name, t)
613-
return value
614-
print(f"Invalid sanitizer '{value}'. Must be one of: {', '.join(valid_sanitizers)}.")
615-
value = self.reprompt_option(name, "Sanitizer (asan/ubsan/msan/tsan/none)")
616-
for t in valid_sanitizers:
617-
if t.lower() == value.lower():
618-
setattr(self.options, name, t)
619-
return value
620-
print(f"Invalid sanitizer '{value}'. Must be one of: {', '.join(valid_sanitizers)}.")
621-
raise ValueError(f"Invalid sanitizer '{value}'. Must be one of: {', '.join(valid_sanitizers)}.")
633+
return self.prompt_validated_option(
634+
name, "Sanitizer (asan/ubsan/msan/tsan/none)", valid_sanitizers, allow_empty=True)
622635

623636
def supports_ansi(self):
624637
return bool(self.ui.color_enabled)

0 commit comments

Comments
 (0)