Merge branch 'develop' of https://github.com/AlexandrePTJ/mopidy into feature/gst_proxy

This commit is contained in:
Alexandre Petitjean 2014-02-17 08:25:53 +01:00
parent 963d02fef5
commit 5e6e073cce
8 changed files with 96 additions and 43 deletions

View File

@ -5,17 +5,26 @@ Changelog
This changelog is used to track all major changes to Mopidy.
v0.19.0 (UNRELEASED)
====================
- Nothing yet.
v0.18.2 (UNRELEASED)
v0.18.3 (2014-02-16)
====================
Bug fix release.
- Fix documentation build.
v0.18.2 (2014-02-16)
====================
Bug fix release.
- We now log warnings for wrongly configured extensions, and clearly label them
in ``mopidy config``, but does no longer stop Mopidy from starting because of
misconfigured extensions. (Fixes: :issue:`682`)
- Fix a crash in the server side WebSocket handler caused by connection
problems with clients. (Fixes: :issue:`428`, :issue:`571`)
- Fix the ``time_position`` field of the ``track_playback_ended`` event, which
has been always 0 since v0.18.0. This made scrobbles by Mopidy-Scrobbler not
be persisted by Last.fm, because Mopidy reported that you listened to 0

View File

@ -21,4 +21,4 @@ if (isinstance(pykka.__version__, basestring)
warnings.filterwarnings('ignore', 'could not open display')
__version__ = '0.18.1'
__version__ = '0.18.3'

View File

@ -74,20 +74,28 @@ def main():
log.setup_logging(config, verbosity_level, args.save_debug_log)
enabled_extensions = []
extensions = {
'validate': [], 'config': [], 'disabled': [], 'enabled': []}
for extension in installed_extensions:
if not ext.validate_extension(extension):
config[extension.ext_name] = {'enabled': False}
config_errors[extension.ext_name] = {
'enabled': 'extension disabled by self check.'}
extensions['validate'].append(extension)
elif not config[extension.ext_name]['enabled']:
config[extension.ext_name] = {'enabled': False}
config_errors[extension.ext_name] = {
'enabled': 'extension disabled by user config.'}
extensions['disabled'].append(extension)
elif config_errors.get(extension.ext_name):
config[extension.ext_name]['enabled'] = False
config_errors[extension.ext_name]['enabled'] = (
'extension disabled due to config errors.')
extensions['config'].append(extension)
else:
enabled_extensions.append(extension)
extensions['enabled'].append(extension)
log_extension_info(installed_extensions, enabled_extensions)
log_extension_info(installed_extensions, extensions['enabled'])
# Config and deps commands are simply special cased for now.
if args.command == config_cmd:
@ -96,22 +104,22 @@ def main():
elif args.command == deps_cmd:
return args.command.run()
# Remove errors for extensions that are not enabled:
for extension in installed_extensions:
if extension not in enabled_extensions:
config_errors.pop(extension.ext_name, None)
check_config_errors(config_errors)
check_config_errors(config, config_errors, extensions)
if not extensions['enabled']:
logger.error('No extension enabled, exiting...')
sys.exit(1)
# Read-only config from here on, please.
proxied_config = config_lib.Proxy(config)
if args.extension and args.extension not in enabled_extensions:
if args.extension and args.extension not in extensions['enabled']:
logger.error(
'Unable to run command provided by disabled extension %s',
args.extension.ext_name)
return 1
for extension in enabled_extensions:
for extension in extensions['enabled']:
extension.setup(registry)
# Anything that wants to exit after this point must use
@ -173,13 +181,39 @@ def log_extension_info(all_extensions, enabled_extensions):
'Disabled extensions: %s', ', '.join(disabled_names) or 'none')
def check_config_errors(errors):
if not errors:
return
for section in errors:
for key, msg in errors[section].items():
logger.error('Config value %s/%s %s', section, key, msg)
sys.exit(1)
def check_config_errors(config, errors, extensions):
fatal_errors = []
extension_names = {}
all_extension_names = set()
for state in extensions:
extension_names[state] = set(e.ext_name for e in extensions[state])
all_extension_names.update(extension_names[state])
for section in sorted(errors):
if not errors[section]:
continue
if section not in all_extension_names:
logger.warning('Found fatal %s configuration errors:', section)
fatal_errors.append(section)
elif section in extension_names['config']:
del errors[section]['enabled']
logger.warning('Found %s configuration errors, the extension '
'has been automatically disabled:', section)
else:
continue
for field, msg in errors[section].items():
logger.warning(' %s/%s %s', section, field, msg)
if extensions['config']:
logger.warning('Please fix the extension configuration errors or '
'disable the extensions to silence these messages.')
if fatal_errors:
logger.error('Please fix fatal configuration errors, exiting...')
sys.exit(1)
if __name__ == '__main__':

View File

@ -19,20 +19,25 @@ else:
EMPTY_STRING = ''
FETCH_ERROR = (
'Fetching passwords from your keyring failed. Any passwords '
'stored in the keyring will not be available.')
def fetch():
if not dbus:
logger.debug('Fetching from keyring failed: dbus not installed.')
logger.debug('%s (dbus not installed)', FETCH_ERROR)
return []
try:
bus = dbus.SessionBus()
except dbus.exceptions.DBusException as e:
logger.debug('Fetching from keyring failed: %s', e)
logger.debug('%s (%s)', FETCH_ERROR, e)
return []
if not bus.name_has_owner('org.freedesktop.secrets'):
logger.debug(
'Fetching from keyring failed: secrets service not running.')
'%s (org.freedesktop.secrets service not running)', FETCH_ERROR)
return []
service = _service(bus)
@ -47,7 +52,7 @@ def fetch():
items, prompt = service.Unlock(locked)
if prompt != '/':
_prompt(bus, prompt).Dismiss()
logger.debug('Fetching from keyring failed: keyring is locked.')
logger.debug('%s (Keyring is locked)', FETCH_ERROR)
return []
result = []
@ -65,19 +70,20 @@ def set(section, key, value):
Indicates if storage failed or succeeded.
"""
if not dbus:
logger.debug('Saving %s/%s to keyring failed: dbus not installed.',
logger.debug('Saving %s/%s to keyring failed. (dbus not installed)',
section, key)
return False
try:
bus = dbus.SessionBus()
except dbus.exceptions.DBusException as e:
logger.debug('Saving %s/%s to keyring failed: %s', section, key, e)
logger.debug('Saving %s/%s to keyring failed. (%s)', section, key, e)
return False
if not bus.name_has_owner('org.freedesktop.secrets'):
logger.debug(
'Saving %s/%s to keyring failed: secrets service not running.',
'Saving %s/%s to keyring failed. '
'(org.freedesktop.secrets service not running)',
section, key)
return False
@ -101,14 +107,14 @@ def set(section, key, value):
item, prompt = collection.CreateItem(properties, secret, True)
except dbus.exceptions.DBusException as e:
# TODO: catch IsLocked errors etc.
logger.debug('Saving %s/%s to keyring failed: %s', section, key, e)
logger.debug('Saving %s/%s to keyring failed. (%s)', section, key, e)
return False
if prompt == '/':
return True
_prompt(bus, prompt).Dismiss()
logger.debug('Saving secret %s/%s failed: Keyring is locked',
logger.debug('Saving secret %s/%s failed. (Keyring is locked)',
section, key)
return False

View File

@ -100,10 +100,11 @@ class HttpFrontend(pykka.ThreadingActor, CoreListener):
host=self.hostname, port=self.port)
if self.zeroconf_service.publish():
logger.info('Registered HTTP with Zeroconf as "%s"',
self.zeroconf_service.name)
logger.debug(
'Registered HTTP with Zeroconf as "%s"',
self.zeroconf_service.name)
else:
logger.info('Registering HTTP with Zeroconf failed.')
logger.debug('Registering HTTP with Zeroconf failed.')
def on_stop(self):
if self.zeroconf_service:

View File

@ -48,10 +48,11 @@ class MpdFrontend(pykka.ThreadingActor, CoreListener):
host=self.hostname, port=self.port)
if self.zeroconf_service.publish():
logger.info('Registered MPD with Zeroconf as "%s"',
self.zeroconf_service.name)
logger.debug(
'Registered MPD with Zeroconf as "%s"',
self.zeroconf_service.name)
else:
logger.info('Registering MPD with Zeroconf failed.')
logger.debug('Registering MPD with Zeroconf failed.')
def on_stop(self):
if self.zeroconf_service:

View File

@ -63,7 +63,7 @@ class Zeroconf(object):
"""
if _is_loopback_address(self.host):
logger.info(
logger.debug(
'Zeroconf publish on loopback interface is not supported.')
return False

View File

@ -43,5 +43,7 @@ class VersionTest(unittest.TestCase):
self.assertLess(SV('0.15.0'), SV('0.16.0'))
self.assertLess(SV('0.16.0'), SV('0.17.0'))
self.assertLess(SV('0.17.0'), SV('0.18.0'))
self.assertLess(SV('0.18.0'), SV(__version__))
self.assertLess(SV(__version__), SV('0.18.2'))
self.assertLess(SV('0.18.0'), SV('0.18.1'))
self.assertLess(SV('0.18.1'), SV('0.18.2'))
self.assertLess(SV('0.18.2'), SV(__version__))
self.assertLess(SV(__version__), SV('0.18.4'))