Merge pull request #588 from adamcik/feature/config-defaults

Initialize config with commented out defaults.
This commit is contained in:
Stein Magnus Jodal 2013-11-22 22:56:01 -08:00
commit 933b2b336f
4 changed files with 75 additions and 15 deletions

View File

@ -40,9 +40,6 @@ def main():
signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks)
try:
create_file_structures()
check_old_locations()
root_cmd = commands.RootCommand()
config_cmd = commands.ConfigCommand()
deps_cmd = commands.DepsCommand()
@ -61,6 +58,9 @@ def main():
args = root_cmd.parse(mopidy_args)
create_file_structures_and_config(args, installed_extensions)
check_old_locations()
config, config_errors = config_lib.load(
args.config_files, installed_extensions, args.config_overrides)
@ -123,9 +123,22 @@ def main():
raise
def create_file_structures():
def create_file_structures_and_config(args, extensions):
path.get_or_create_dir(b'$XDG_DATA_DIR/mopidy')
path.get_or_create_file(b'$XDG_CONFIG_DIR/mopidy/mopidy.conf')
path.get_or_create_dir(b'$XDG_CONFIG_DIR/mopidy')
# Initialize whatever the last config file is with defaults
config_file = args.config_files[-1]
if os.path.exists(config_file):
return
try:
default = config_lib.format_initial(extensions)
path.get_or_create_file(config_file, mkdir=False, content=default)
logger.info('Initialized %s with default config', config_file)
except IOError as e:
logger.warning('Unable to initialize %s with default config: %s',
config_file, e)
def check_old_locations():

View File

@ -10,7 +10,7 @@ import re
from mopidy.config import keyring
from mopidy.config.schemas import * # noqa
from mopidy.config.types import * # noqa
from mopidy.utils import path
from mopidy.utils import path, versioning
logger = logging.getLogger('mopidy.config')
@ -41,6 +41,18 @@ _proxy_schema['password'] = Secret(optional=True)
_schemas = [_logging_schema, _loglevels_schema, _audio_schema, _proxy_schema]
_INITIAL_HELP = """
# For further information about options in this file see:
# http://docs.mopidy.com/
#
# The initial commented out values reflect the defaults as of:
# %(versions)s
#
# Available options and defaults might have changed since then,
# run `mopidy config` to see the current effective config and
# `mopidy --version` to check the current version.
"""
def read(config_file):
"""Helper to load config defaults in same way across core and extensions"""
@ -66,7 +78,25 @@ def format(config, extensions, comments=None, display=True):
# need to know about extensions.
schemas = _schemas[:]
schemas.extend(e.get_config_schema() for e in extensions)
return _format(config, comments or {}, schemas, display)
return _format(config, comments or {}, schemas, display, False)
def format_initial(extensions):
config_dir = os.path.dirname(__file__)
defaults = [read(os.path.join(config_dir, 'default.conf'))]
defaults.extend(e.get_default_config() for e in extensions)
raw_config = _load([], defaults, [])
schemas = _schemas[:]
schemas.extend(e.get_config_schema() for e in extensions)
config, errors = _validate(raw_config, schemas)
versions = ['Mopidy %s' % versioning.get_version()]
for extension in sorted(extensions, key=lambda ext: ext.dist_name):
versions.append('%s %s' % (extension.dist_name, extension.version))
description = _INITIAL_HELP.strip() % {'versions': '\n# '.join(versions)}
return description + '\n\n' + _format(config, {}, schemas, False, True)
def _load(files, defaults, overrides):
@ -128,7 +158,7 @@ def _validate(raw_config, schemas):
return config, errors
def _format(config, comments, schemas, display):
def _format(config, comments, schemas, display, disable):
output = []
for schema in schemas:
serialized = schema.serialize(
@ -142,9 +172,11 @@ def _format(config, comments, schemas, display):
if value is not None:
output[-1] += b' ' + value
if comment:
output[-1] += b' # ' + comment.capitalize()
output[-1] += b' ; ' + comment.capitalize()
if disable:
output[-1] = re.sub(r'^', b'#', output[-1], flags=re.M)
output.append(b'')
return b'\n'.join(output)
return b'\n'.join(output).strip()
def _preprocess(config_string):

View File

@ -37,14 +37,17 @@ def get_or_create_dir(dir_path):
return dir_path
def get_or_create_file(file_path):
def get_or_create_file(file_path, mkdir=True, content=None):
if not isinstance(file_path, bytes):
raise ValueError('Path is not a bytestring.')
file_path = expand_path(file_path)
get_or_create_dir(os.path.dirname(file_path))
if mkdir:
get_or_create_dir(os.path.dirname(file_path))
if not os.path.isfile(file_path):
logger.info('Creating file %s', file_path)
open(file_path, 'w').close()
with open(file_path, 'w') as fh:
if content:
fh.write(content)
return file_path

View File

@ -102,17 +102,29 @@ class GetOrCreateFileTest(unittest.TestCase):
def test_create_file_with_name_of_existing_dir_throws_ioerror(self):
conflicting_dir = os.path.join(self.parent)
self.assertRaises(IOError, path.get_or_create_file, conflicting_dir)
with self.assertRaises(IOError):
path.get_or_create_file(conflicting_dir)
def test_create_dir_with_unicode(self):
with self.assertRaises(ValueError):
file_path = unicode(os.path.join(self.parent, b'test'))
path.get_or_create_file(file_path)
def test_create_dir_with_none(self):
def test_create_file_with_none(self):
with self.assertRaises(ValueError):
path.get_or_create_file(None)
def test_create_dir_without_mkdir(self):
file_path = os.path.join(self.parent, b'foo', b'bar')
with self.assertRaises(IOError):
path.get_or_create_file(file_path, mkdir=False)
def test_create_dir_with_default_content(self):
file_path = os.path.join(self.parent, b'test')
created = path.get_or_create_file(file_path, content=b'foobar')
with open(created) as fh:
self.assertEqual(fh.read(), b'foobar')
class PathToFileURITest(unittest.TestCase):
def test_simple_path(self):