diff --git a/awscli/customizations/configure/writer.py b/awscli/customizations/configure/writer.py index 83825a53dab6..78fe84d15eea 100644 --- a/awscli/customizations/configure/writer.py +++ b/awscli/customizations/configure/writer.py @@ -215,30 +215,36 @@ def _update_section_contents(self, contents, section_name, new_values): def _update_subattributes(self, index, contents, values, starting_indent): index += 1 + last_subattribute_line = index - 1 for i in range(index, len(contents)): line = contents[i] + if self.SECTION_REGEX.search(line) is not None: + self._insert_new_values(i - 1, contents, values, ' ') + return i match = self.OPTION_REGEX.search(line) - if match is not None: - current_indent = len( - match.group(1)) - len(match.group(1).lstrip()) - key_name = match.group(1).strip() - if key_name in values: - option_value = values[key_name] - new_line = '%s%s = %s\n' % (' ' * current_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: + if match is None: + last_subattribute_line = i + continue + current_indent = len( + match.group(1)) - len(match.group(1).lstrip()) + if starting_indent == current_indent: # 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, ' ') - return i + return i + key_name = match.group(1).strip() + if key_name in values: + option_value = values[key_name] + new_line = '%s%s = %s\n' % ( + ' ' * current_indent, + key_name, + option_value, + ) + contents[i] = new_line + del values[key_name] + last_subattribute_line = i + self._insert_new_values(last_subattribute_line, contents, values, ' ') + return last_subattribute_line def _insert_new_values(self, line_number, contents, new_values, indent=''): new_contents = [] diff --git a/tests/unit/customizations/configure/test_writer.py b/tests/unit/customizations/configure/test_writer.py index 9c85516762ef..7ce63f7d6e58 100644 --- a/tests/unit/customizations/configure/test_writer.py +++ b/tests/unit/customizations/configure/test_writer.py @@ -295,6 +295,34 @@ def test_add_to_nested_with_nested_in_the_end(self): ' other = foo\n' ' signature_version = newval\n') + def test_add_to_empty_nested_block_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_in_block(self): + original = ( + '[default]\n' + 's3 =\n' + '# comment\n' + ' addressing_style = path\n' + ) + self.assert_update_config( + original, {'__section__': 'default', + 's3': {'signature_version': 'newval'}}, + '[default]\n' + 's3 =\n' + '# comment\n' + ' addressing_style = path\n' + ' signature_version = newval\n') + def test_update_nested_attribute(self): original = ( '[default]\n' @@ -326,6 +354,22 @@ def test_updated_nested_attribute_new_section(self): '[profile foo]\n' 'foo = bar\n') + def test_add_to_nested_with_next_section_header(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_update_nested_attr_no_prior_nesting(self): original = ( '[default]\n' @@ -343,6 +387,20 @@ def test_update_nested_attr_no_prior_nesting(self): '[profile foo]\n' 'foo = bar\n') + def test_nested_attribute_does_not_update_same_indent_sibling(self): + original = ( + '[default]\n' + 's3 =\n' + 'region = oldval\n' + ) + self.assert_update_config( + original, {'__section__': 'default', + 's3': {'region': 'newval'}}, + '[default]\n' + 's3 =\n' + ' region = newval\n' + 'region = oldval\n') + def test_can_handle_empty_section(self): original = ( '[default]\n'