Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/next-release/bugfix-configure-10348.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "bugfix",
"category": "configure",
"description": "Fixed an ``UnboundLocalError`` crash in ``aws configure set`` when a nested config block such as ``s3 =`` is empty, or is immediately followed by a comment, a blank line, or a new section header. Fixes `#10348 <https://github.com/aws/aws-cli/issues/10348>`__."
}
25 changes: 16 additions & 9 deletions awscli/customizations/configure/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ def _update_section_contents(self, contents, section_name, new_values):

def _update_subattributes(self, index, contents, values, starting_indent):
index += 1
# Seeded in case there are no lines after the nested option at all.
i = index - 1
for i in range(index, len(contents)):
line = contents[i]
match = self.OPTION_REGEX.search(line)
Expand All @@ -228,16 +230,21 @@ def _update_subattributes(self, index, contents, values, starting_indent):
key_name, option_value)
contents[i] = new_line
del values[key_name]
if starting_indent == current_indent or \
self.SECTION_REGEX.search(line) is not None:
# We've arrived at the starting indent level so we can just
# write out all the values now.
self._insert_new_values(i - 1, contents, values, ' ')
break
if current_indent != starting_indent:
# We're still inside the nested block.
continue
elif self.SECTION_REGEX.search(line) is None:
# Comments, blank lines and the like don't end the block.
continue
# We've arrived at the starting indent level so we can just
# write out all the values now.
self._insert_new_values(i - 1, contents, values, ' ')
break
else:
if starting_indent != current_indent:
# The option is the last option in the file
self._insert_new_values(i, contents, values, ' ')
# The option is the last option in the file
if values and not contents[-1].endswith('\n'):
contents[-1] += '\n'
self._insert_new_values(i, contents, values, ' ')
return i

def _insert_new_values(self, line_number, contents, new_values, indent=''):
Expand Down
72 changes: 72 additions & 0 deletions tests/unit/customizations/configure/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,78 @@ def test_updated_nested_attribute_new_section(self):
'[profile foo]\n'
'foo = bar\n')

def test_add_to_empty_nested_at_end_of_file(self):
original = (
'[default]\n'
's3 =\n'
)
self.assert_update_config(
original, {'__section__': 'default',
's3': {'signature_version': 'newval'}},
'[default]\n'
's3 =\n'
' signature_version = newval\n')

def test_add_to_nested_with_comment_after_nested_key(self):
original = (
'[default]\n'
's3 =\n'
'# a comment\n'
' other = foo\n'
)
self.assert_update_config(
original, {'__section__': 'default',
's3': {'signature_version': 'newval'}},
'[default]\n'
's3 =\n'
'# a comment\n'
' other = foo\n'
' signature_version = newval\n')

def test_add_to_nested_with_new_section_after_nested_key(self):
original = (
'[default]\n'
's3 =\n'
'[profile foo]\n'
'foo = bar\n'
)
self.assert_update_config(
original, {'__section__': 'default',
's3': {'signature_version': 'newval'}},
'[default]\n'
's3 =\n'
' signature_version = newval\n'
'[profile foo]\n'
'foo = bar\n')

def test_add_to_nested_with_blank_line_after_nested_key(self):
original = (
'[default]\n'
's3 =\n'
'\n'
' other = foo\n'
)
self.assert_update_config(
original, {'__section__': 'default',
's3': {'signature_version': 'newval'}},
'[default]\n'
's3 =\n'
'\n'
' other = foo\n'
' signature_version = newval\n')

def test_add_to_empty_nested_without_trailing_newline(self):
original = (
'[default]\n'
's3 ='
)
self.assert_update_config(
original, {'__section__': 'default',
's3': {'signature_version': 'newval'}},
'[default]\n'
's3 =\n'
' signature_version = newval\n')

def test_update_nested_attr_no_prior_nesting(self):
original = (
'[default]\n'
Expand Down