More test coverage, and simplification of config generation.
This commit is contained in:
parent
c7803a2814
commit
f581f4b8d9
6 changed files with 165 additions and 40 deletions
|
@ -3,6 +3,7 @@ syntax: glob
|
|||
*.pyc
|
||||
*.swp
|
||||
.cache
|
||||
.coverage
|
||||
.tox
|
||||
build
|
||||
dist
|
||||
|
|
39
borgmatic/commands/generate_config.py
Normal file
39
borgmatic/commands/generate_config.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from __future__ import print_function
|
||||
from argparse import ArgumentParser
|
||||
import os
|
||||
from subprocess import CalledProcessError
|
||||
import sys
|
||||
|
||||
from ruamel import yaml
|
||||
|
||||
from borgmatic import borg
|
||||
from borgmatic.config import convert, generate, validate
|
||||
|
||||
|
||||
DEFAULT_DESTINATION_CONFIG_FILENAME = '/etc/borgmatic/config.yaml'
|
||||
|
||||
|
||||
def parse_arguments(*arguments):
|
||||
'''
|
||||
Given command-line arguments with which this script was invoked, parse the arguments and return
|
||||
them as an ArgumentParser instance.
|
||||
'''
|
||||
parser = ArgumentParser(description='Generate a sample borgmatic YAML configuration file.')
|
||||
parser.add_argument(
|
||||
'-d', '--destination',
|
||||
dest='destination_filename',
|
||||
default=DEFAULT_DESTINATION_CONFIG_FILENAME,
|
||||
help='Destination YAML configuration filename. Default: {}'.format(DEFAULT_DESTINATION_CONFIG_FILENAME),
|
||||
)
|
||||
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
args = parse_arguments(*sys.argv[1:])
|
||||
|
||||
generate.generate_sample_configuration(args.destination_filename, validate.schema_filename())
|
||||
except (ValueError, OSError) as error:
|
||||
print(error, file=sys.stderr)
|
||||
sys.exit(1)
|
|
@ -6,15 +6,6 @@ from ruamel import yaml
|
|||
INDENT = 4
|
||||
|
||||
|
||||
def write_configuration(config_filename, config):
|
||||
'''
|
||||
Given a target config filename and a config data structure of nested OrderedDicts, write out the
|
||||
config to file as YAML.
|
||||
'''
|
||||
with open(config_filename, 'w') as config_file:
|
||||
config_file.write(yaml.round_trip_dump(config, indent=INDENT, block_seq_indent=INDENT))
|
||||
|
||||
|
||||
def _insert_newline_before_comment(config, field_name):
|
||||
'''
|
||||
Using some ruamel.yaml black magic, insert a blank line in the config right befor the given
|
||||
|
@ -26,6 +17,37 @@ def _insert_newline_before_comment(config, field_name):
|
|||
)
|
||||
|
||||
|
||||
def _schema_to_sample_configuration(schema, level=0):
|
||||
'''
|
||||
Given a loaded configuration schema, generate and return sample config for it. Include comments
|
||||
for each section based on the schema "desc" description.
|
||||
'''
|
||||
example = schema.get('example')
|
||||
if example:
|
||||
return example
|
||||
|
||||
config = yaml.comments.CommentedMap([
|
||||
(
|
||||
section_name,
|
||||
_schema_to_sample_configuration(section_schema, level + 1),
|
||||
)
|
||||
for section_name, section_schema in schema['map'].items()
|
||||
])
|
||||
|
||||
add_comments_to_configuration(config, schema, indent=(level * INDENT))
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def write_configuration(config_filename, config):
|
||||
'''
|
||||
Given a target config filename and a config data structure of nested OrderedDicts, write out the
|
||||
config to file as YAML.
|
||||
'''
|
||||
with open(config_filename, 'w') as config_file:
|
||||
config_file.write(yaml.round_trip_dump(config, indent=INDENT, block_seq_indent=INDENT))
|
||||
|
||||
|
||||
def add_comments_to_configuration(config, schema, indent=0):
|
||||
'''
|
||||
Using descriptions from a schema as a source, add those descriptions as comments to the given
|
||||
|
@ -37,7 +59,7 @@ def add_comments_to_configuration(config, schema, indent=0):
|
|||
description = field_schema.get('desc')
|
||||
|
||||
# No description to use? Skip it.
|
||||
if not schema or not description:
|
||||
if not field_schema or not description:
|
||||
continue
|
||||
|
||||
config.yaml_set_comment_before_after_key(
|
||||
|
@ -49,36 +71,6 @@ def add_comments_to_configuration(config, schema, indent=0):
|
|||
_insert_newline_before_comment(config, field_name)
|
||||
|
||||
|
||||
def _section_schema_to_sample_configuration(section_schema):
|
||||
'''
|
||||
Given the schema for a particular config section, generate and return sample config for that
|
||||
section. Include comments for each field based on the schema "desc" description.
|
||||
'''
|
||||
section_config = yaml.comments.CommentedMap([
|
||||
(field_name, field_schema['example'])
|
||||
for field_name, field_schema in section_schema['map'].items()
|
||||
])
|
||||
|
||||
add_comments_to_configuration(section_config, section_schema, indent=INDENT)
|
||||
|
||||
return section_config
|
||||
|
||||
|
||||
def _schema_to_sample_configuration(schema):
|
||||
'''
|
||||
Given a loaded configuration schema, generate and return sample config for it. Include comments
|
||||
for each section based on the schema "desc" description.
|
||||
'''
|
||||
config = yaml.comments.CommentedMap([
|
||||
(section_name, _section_schema_to_sample_configuration(section_schema))
|
||||
for section_name, section_schema in schema['map'].items()
|
||||
])
|
||||
|
||||
add_comments_to_configuration(config, schema)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def generate_sample_configuration(config_filename, schema_filename):
|
||||
'''
|
||||
Given a target config filename and the path to a schema filename in pykwalify YAML schema
|
||||
|
|
43
borgmatic/tests/integration/config/test_generate.py
Normal file
43
borgmatic/tests/integration/config/test_generate.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from io import StringIO
|
||||
import sys
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.config import generate as module
|
||||
|
||||
|
||||
def test_insert_newline_before_comment_does_not_raise():
|
||||
field_name = 'foo'
|
||||
config = module.yaml.comments.CommentedMap([(field_name, 33)])
|
||||
config.yaml_set_comment_before_after_key(key=field_name, before='Comment',)
|
||||
|
||||
module._insert_newline_before_comment(config, field_name)
|
||||
|
||||
|
||||
def test_write_configuration_does_not_raise():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').and_return(StringIO())
|
||||
|
||||
module.write_configuration('config.yaml', {})
|
||||
|
||||
|
||||
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.
|
||||
config = module.yaml.comments.CommentedMap([('foo', 33), ('bar', 44), ('baz', 55)])
|
||||
schema = {
|
||||
'map': {
|
||||
'foo': {'desc': 'Foo'},
|
||||
'bar': {'desc': 'Bar'},
|
||||
}
|
||||
}
|
||||
|
||||
module.add_comments_to_configuration(config, schema)
|
||||
|
||||
|
||||
def test_generate_sample_configuration_does_not_raise():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('schema.yaml').and_return('')
|
||||
flexmock(module).should_receive('write_configuration')
|
||||
flexmock(module).should_receive('_schema_to_sample_configuration')
|
||||
|
||||
module.generate_sample_configuration('config.yaml', 'schema.yaml')
|
49
borgmatic/tests/unit/config/test_generate.py
Normal file
49
borgmatic/tests/unit/config/test_generate.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.config import generate as module
|
||||
|
||||
|
||||
def test_schema_to_sample_configuration_generates_config_with_examples():
|
||||
flexmock(module.yaml.comments).should_receive('CommentedMap').replace_with(OrderedDict)
|
||||
flexmock(module).should_receive('add_comments_to_configuration')
|
||||
schema = {
|
||||
'map': OrderedDict([
|
||||
(
|
||||
'section1', {
|
||||
'map': {
|
||||
'field1': OrderedDict([
|
||||
('example', 'Example 1')
|
||||
]),
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
'section2', {
|
||||
'map': OrderedDict([
|
||||
('field2', {'example': 'Example 2'}),
|
||||
('field3', {'example': 'Example 3'}),
|
||||
]),
|
||||
}
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
config = module._schema_to_sample_configuration(schema)
|
||||
|
||||
assert config == OrderedDict([
|
||||
(
|
||||
'section1',
|
||||
OrderedDict([
|
||||
('field1', 'Example 1'),
|
||||
]),
|
||||
),
|
||||
(
|
||||
'section2',
|
||||
OrderedDict([
|
||||
('field2', 'Example 2'),
|
||||
('field3', 'Example 3'),
|
||||
]),
|
||||
)
|
||||
])
|
1
setup.py
1
setup.py
|
@ -26,6 +26,7 @@ setup(
|
|||
'console_scripts': [
|
||||
'borgmatic = borgmatic.commands.borgmatic:main',
|
||||
'convert-borgmatic-config = borgmatic.commands.convert_config:main',
|
||||
'generate-borgmatic-config = borgmatic.commands.generate_config:main',
|
||||
]
|
||||
},
|
||||
obsoletes=[
|
||||
|
|
Loading…
Reference in a new issue