diff --git a/cibuildwheel/bashlex_eval.py b/cibuildwheel/bashlex_eval.py index 4cc9c053..122b50b3 100644 --- a/cibuildwheel/bashlex_eval.py +++ b/cibuildwheel/bashlex_eval.py @@ -51,28 +51,24 @@ def evaluate_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: - word_start = node.pos[0] - word_end = node.pos[1] - word_string = context.input[word_start:word_end] - letters = list(word_string) + value = node.word for part in node.parts: - part_start = part.pos[0] - word_start - part_end = part.pos[1] - word_start + part_string = context.input[part.pos[0]:part.pos[1]] + part_value = evaluate_node(part, context=context) - # Set all the characters in the part to None - for i in range(part_start, part_end): - letters[i] = '' + if part_string not in value: + raise RuntimeError( + 'bash parse failed. part "{}" not found in "{}". Word was "{}". Full input was "{}"'.format( + part_string, value, node.word, context.input, + ) + ) - letters[part_start] = evaluate_node(part, context=context) - - # remove the None letters and concat - value = ''.join(letters) + value = value.replace(part_string, part_value, 1) print('node value:', value) - # apply bash-like quotes/whitespace treatment - return ' '.join(word.strip() for word in shlex.split(value)) + return value def evaluate_command_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str: diff --git a/unit_test/environment_test.py b/unit_test/environment_test.py index 5a0cf613..0827cc0d 100644 --- a/unit_test/environment_test.py +++ b/unit_test/environment_test.py @@ -114,3 +114,12 @@ def test_substitution_with_backslash(): }) assert environment_dict.get('PATH2') == 'somewhere_else;c:\\folder\\' + + +def test_awkwardly_quoted_variable(): + environment_recipe = parse_environment('VAR2=something"like this""$VAR1"$VAR1$(echo "theres more")"$(echo "and more!")"') + + # pass the existing process env so PATH is available + environment_dict = environment_recipe.as_dictionary({'VAR1': 'but wait'}) + + assert environment_dict.get('VAR2') == 'somethinglike thisbut waitbut waittheres moreand more!'