浏览代码

Don't overwrite config files. And retain file permissions when upgrading config.

Dan Helfman 8 年之前
父节点
当前提交
5ff016238e

+ 2 - 0
borgmatic/commands/convert_config.py

@@ -78,6 +78,7 @@ def main():  # pragma: no cover
         args = parse_arguments(*sys.argv[1:])
         args = parse_arguments(*sys.argv[1:])
         schema = yaml.round_trip_load(open(validate.schema_filename()).read())
         schema = yaml.round_trip_load(open(validate.schema_filename()).read())
         source_config = legacy.parse_configuration(args.source_config_filename, legacy.CONFIG_FORMAT)
         source_config = legacy.parse_configuration(args.source_config_filename, legacy.CONFIG_FORMAT)
+        source_config_file_mode = os.stat(args.source_config_filename).st_mode
         source_excludes = (
         source_excludes = (
             open(args.source_excludes_filename).read().splitlines()
             open(args.source_excludes_filename).read().splitlines()
             if args.source_excludes_filename
             if args.source_excludes_filename
@@ -87,6 +88,7 @@ def main():  # pragma: no cover
         destination_config = convert.convert_legacy_parsed_config(source_config, source_excludes, schema)
         destination_config = convert.convert_legacy_parsed_config(source_config, source_excludes, schema)
 
 
         generate.write_configuration(args.destination_config_filename, destination_config)
         generate.write_configuration(args.destination_config_filename, destination_config)
+        os.chmod(args.destination_config_filename, source_config_file_mode)
 
 
         # TODO: As a backstop, check that the written config can actually be read and parsed, and
         # TODO: As a backstop, check that the written config can actually be read and parsed, and
         # that it matches the destination config data structure that was written.
         # that it matches the destination config data structure that was written.

+ 4 - 0
borgmatic/config/generate.py

@@ -1,4 +1,5 @@
 from collections import OrderedDict
 from collections import OrderedDict
+import os
 
 
 from ruamel import yaml
 from ruamel import yaml
 
 
@@ -44,6 +45,9 @@ def write_configuration(config_filename, config):
     Given a target config filename and a config data structure of nested OrderedDicts, write out the
     Given a target config filename and a config data structure of nested OrderedDicts, write out the
     config to file as YAML.
     config to file as YAML.
     '''
     '''
+    if os.path.exists(config_filename):
+        raise FileExistsError('{} already exists. Aborting.'.format(config_filename))
+
     with open(config_filename, 'w') as config_file:
     with open(config_filename, 'w') as config_file:
         config_file.write(yaml.round_trip_dump(config, indent=INDENT, block_seq_indent=INDENT))
         config_file.write(yaml.round_trip_dump(config, indent=INDENT, block_seq_indent=INDENT))
 
 

+ 12 - 0
borgmatic/tests/integration/config/test_generate.py

@@ -1,7 +1,9 @@
 from io import StringIO
 from io import StringIO
+import os
 import sys
 import sys
 
 
 from flexmock import flexmock
 from flexmock import flexmock
+import pytest
 
 
 from borgmatic.config import generate as module
 from borgmatic.config import generate as module
 
 
@@ -15,12 +17,22 @@ def test_insert_newline_before_comment_does_not_raise():
 
 
 
 
 def test_write_configuration_does_not_raise():
 def test_write_configuration_does_not_raise():
+    flexmock(os.path).should_receive('exists').and_return(False)
     builtins = flexmock(sys.modules['builtins'])
     builtins = flexmock(sys.modules['builtins'])
     builtins.should_receive('open').and_return(StringIO())
     builtins.should_receive('open').and_return(StringIO())
 
 
     module.write_configuration('config.yaml', {})
     module.write_configuration('config.yaml', {})
 
 
 
 
+def test_write_configuration_with_already_existing_file_raises():
+    flexmock(os.path).should_receive('exists').and_return(True)
+    builtins = flexmock(sys.modules['builtins'])
+    builtins.should_receive('open').and_return(StringIO())
+
+    with pytest.raises(FileExistsError):
+        module.write_configuration('config.yaml', {})
+
+
 def test_add_comments_to_configuration_does_not_raise():
 def test_add_comments_to_configuration_does_not_raise():
     # Ensure that it can deal with fields both in the schema and missing from the schema.
     # Ensure that it can deal with fields both in the schema and missing from the schema.
     config = module.yaml.comments.CommentedMap([('foo', 33), ('bar', 44), ('baz', 55)])
     config = module.yaml.comments.CommentedMap([('foo', 33), ('bar', 44), ('baz', 55)])