Merge pull request #107 from knutz3n/feature/interactive-settings
This commit is contained in:
commit
b8d4af8367
@ -70,6 +70,9 @@ Please note that 0.5.0 requires some updated dependencies, as listed under
|
|||||||
|
|
||||||
- Improve :option:`--list-settings` output. (Fixes: :issue:`91`)
|
- Improve :option:`--list-settings` output. (Fixes: :issue:`91`)
|
||||||
|
|
||||||
|
- Added :option:`--interactive` for reading missing local settings from
|
||||||
|
``stdin``. (Fixes: :issue:`96`)
|
||||||
|
|
||||||
- Tag cache generator:
|
- Tag cache generator:
|
||||||
|
|
||||||
- Made it possible to abort :command:`mopidy-scan` with CTRL+C.
|
- Made it possible to abort :command:`mopidy-scan` with CTRL+C.
|
||||||
|
|||||||
@ -28,15 +28,15 @@ from mopidy.utils.settings import list_settings_optparse_callback
|
|||||||
logger = logging.getLogger('mopidy.core')
|
logger = logging.getLogger('mopidy.core')
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
options = parse_options()
|
|
||||||
setup_logging(options.verbosity_level, options.save_debug_log)
|
|
||||||
setup_settings()
|
|
||||||
setup_gobject_loop()
|
|
||||||
setup_gstreamer()
|
|
||||||
setup_mixer()
|
|
||||||
setup_backend()
|
|
||||||
setup_frontends()
|
|
||||||
try:
|
try:
|
||||||
|
options = parse_options()
|
||||||
|
setup_logging(options.verbosity_level, options.save_debug_log)
|
||||||
|
setup_settings(options.interactive)
|
||||||
|
setup_gobject_loop()
|
||||||
|
setup_gstreamer()
|
||||||
|
setup_mixer()
|
||||||
|
setup_backend()
|
||||||
|
setup_frontends()
|
||||||
while ActorRegistry.get_all():
|
while ActorRegistry.get_all():
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
logger.info(u'No actors left. Exiting...')
|
logger.info(u'No actors left. Exiting...')
|
||||||
@ -49,6 +49,9 @@ def parse_options():
|
|||||||
parser.add_option('--help-gst',
|
parser.add_option('--help-gst',
|
||||||
action='store_true', dest='help_gst',
|
action='store_true', dest='help_gst',
|
||||||
help='show GStreamer help options')
|
help='show GStreamer help options')
|
||||||
|
parser.add_option('-i', '--interactive',
|
||||||
|
action='store_true', dest='interactive',
|
||||||
|
help='ask interactively for required settings which is missing')
|
||||||
parser.add_option('-q', '--quiet',
|
parser.add_option('-q', '--quiet',
|
||||||
action='store_const', const=0, dest='verbosity_level',
|
action='store_const', const=0, dest='verbosity_level',
|
||||||
help='less output (warning level)')
|
help='less output (warning level)')
|
||||||
@ -63,11 +66,11 @@ def parse_options():
|
|||||||
help='list current settings')
|
help='list current settings')
|
||||||
return parser.parse_args(args=mopidy_args)[0]
|
return parser.parse_args(args=mopidy_args)[0]
|
||||||
|
|
||||||
def setup_settings():
|
def setup_settings(interactive):
|
||||||
get_or_create_folder('~/.mopidy/')
|
get_or_create_folder('~/.mopidy/')
|
||||||
get_or_create_file('~/.mopidy/settings.py')
|
get_or_create_file('~/.mopidy/settings.py')
|
||||||
try:
|
try:
|
||||||
settings.validate()
|
settings.validate(interactive)
|
||||||
except SettingsError, e:
|
except SettingsError, e:
|
||||||
logger.error(e.message)
|
logger.error(e.message)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
# Absolute import needed to import ~/.mopidy/settings.py and not ourselves
|
# Absolute import needed to import ~/.mopidy/settings.py and not ourselves
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
import getpass
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
@ -63,12 +64,28 @@ class SettingsProxy(object):
|
|||||||
else:
|
else:
|
||||||
super(SettingsProxy, self).__setattr__(attr, value)
|
super(SettingsProxy, self).__setattr__(attr, value)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self, interactive):
|
||||||
|
if interactive:
|
||||||
|
self._read_missing_settings_from_stdin(self.default, self.local)
|
||||||
if self.get_errors():
|
if self.get_errors():
|
||||||
logger.error(u'Settings validation errors: %s',
|
logger.error(u'Settings validation errors: %s',
|
||||||
indent(self.get_errors_as_string()))
|
indent(self.get_errors_as_string()))
|
||||||
raise SettingsError(u'Settings validation failed.')
|
raise SettingsError(u'Settings validation failed.')
|
||||||
|
|
||||||
|
def _read_missing_settings_from_stdin(self, default, local):
|
||||||
|
for setting, value in default.iteritems():
|
||||||
|
if isinstance(value, basestring) and len(value) == 0:
|
||||||
|
local[setting] = self._read_from_stdin(setting + u': ')
|
||||||
|
|
||||||
|
def _read_from_stdin(self, prompt):
|
||||||
|
if u'_PASSWORD' in prompt:
|
||||||
|
return (getpass.getpass(prompt)
|
||||||
|
.decode(sys.stdin.encoding, 'ignore'))
|
||||||
|
else:
|
||||||
|
sys.stdout.write(prompt)
|
||||||
|
return (sys.stdin.readline().strip()
|
||||||
|
.decode(sys.stdin.encoding, 'ignore'))
|
||||||
|
|
||||||
def get_errors(self):
|
def get_errors(self):
|
||||||
return validate_settings(self.default, self.local)
|
return validate_settings(self.default, self.local)
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ class HelpTest(unittest.TestCase):
|
|||||||
self.assert_('--version' in output)
|
self.assert_('--version' in output)
|
||||||
self.assert_('--help' in output)
|
self.assert_('--help' in output)
|
||||||
self.assert_('--help-gst' in output)
|
self.assert_('--help-gst' in output)
|
||||||
|
self.assert_('--interactive' in output)
|
||||||
self.assert_('--quiet' in output)
|
self.assert_('--quiet' in output)
|
||||||
self.assert_('--verbose' in output)
|
self.assert_('--verbose' in output)
|
||||||
self.assert_('--save-debug-log' in output)
|
self.assert_('--save-debug-log' in output)
|
||||||
|
|||||||
@ -149,6 +149,12 @@ class SettingsProxyTest(unittest.TestCase):
|
|||||||
actual = self.settings.TEST
|
actual = self.settings.TEST
|
||||||
self.assertEqual(actual, './test')
|
self.assertEqual(actual, './test')
|
||||||
|
|
||||||
|
def test_interactive_input_of_missing_defaults(self):
|
||||||
|
self.settings.default['TEST'] = ''
|
||||||
|
interactive_input = 'input'
|
||||||
|
self.settings._read_from_stdin = lambda _: interactive_input
|
||||||
|
self.settings.validate(interactive=True)
|
||||||
|
self.assertEqual(interactive_input, self.settings.TEST)
|
||||||
|
|
||||||
class FormatSettingListTest(unittest.TestCase):
|
class FormatSettingListTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user