Merge pull request #418 from jodal/feature/show-deps
Update --show-deps to list deps of extensions
This commit is contained in:
commit
c84cb95c3f
@ -55,6 +55,9 @@ and improved.
|
||||
- The command option :option:`mopidy --list-settings` is now named
|
||||
:option:`mopidy --show-config`.
|
||||
|
||||
- The command option :option:`mopidy --list-deps` is now named
|
||||
:option:`mopidy --show-deps`.
|
||||
|
||||
- What configuration files to use can now be specified through the command
|
||||
option :option:`mopidy --config`.
|
||||
|
||||
|
||||
@ -52,9 +52,9 @@ mopidy command
|
||||
together to show the effective document. Secret values like passwords are
|
||||
masked out. Config for disabled extensions are not included.
|
||||
|
||||
.. cmdoption:: --list-deps
|
||||
.. cmdoption:: --show-deps
|
||||
|
||||
List dependencies and their versions.
|
||||
Show dependencies, their versions and installation location.
|
||||
|
||||
.. cmdoption:: --config <file>
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ with others for debugging.
|
||||
Installed dependencies
|
||||
======================
|
||||
|
||||
The command :option:`mopidy --list-deps` will list the paths to and versions of
|
||||
The command :option:`mopidy --show-deps` will list the paths to and versions of
|
||||
any dependency Mopidy or the extensions might need to work. This is very useful
|
||||
data for checking that you're using the right versions, and that you're using
|
||||
the right installation if you have multiple installations of a dependency on
|
||||
|
||||
@ -151,9 +151,9 @@ def parse_options():
|
||||
action='callback', callback=show_config_callback,
|
||||
help='show current config')
|
||||
parser.add_option(
|
||||
b'--list-deps',
|
||||
action='callback', callback=deps.list_deps_optparse_callback,
|
||||
help='list dependencies and their versions')
|
||||
b'--show-deps',
|
||||
action='callback', callback=deps.show_deps_optparse_callback,
|
||||
help='show dependencies and their versions')
|
||||
parser.add_option(
|
||||
b'--config',
|
||||
action='store', dest='config',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import functools
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
@ -8,16 +9,16 @@ import pygst
|
||||
pygst.require('0.10')
|
||||
import gst
|
||||
|
||||
import pykka
|
||||
import pkg_resources
|
||||
|
||||
from . import formatting
|
||||
|
||||
|
||||
def list_deps_optparse_callback(*args):
|
||||
def show_deps_optparse_callback(*args):
|
||||
"""
|
||||
Prints a list of all dependencies.
|
||||
|
||||
Called by optparse when Mopidy is run with the :option:`--list-deps`
|
||||
Called by optparse when Mopidy is run with the :option:`--show-deps`
|
||||
option.
|
||||
"""
|
||||
print format_dependency_list()
|
||||
@ -26,32 +27,47 @@ def list_deps_optparse_callback(*args):
|
||||
|
||||
def format_dependency_list(adapters=None):
|
||||
if adapters is None:
|
||||
dist_names = set([
|
||||
ep.dist.project_name for ep in
|
||||
pkg_resources.iter_entry_points('mopidy.ext')
|
||||
if ep.dist.project_name != 'Mopidy'])
|
||||
dist_infos = [
|
||||
functools.partial(pkg_info, dist_name)
|
||||
for dist_name in dist_names]
|
||||
|
||||
adapters = [
|
||||
platform_info,
|
||||
python_info,
|
||||
functools.partial(pkg_info, 'Mopidy', True)
|
||||
] + dist_infos + [
|
||||
gstreamer_info,
|
||||
pykka_info,
|
||||
pyspotify_info,
|
||||
pylast_info,
|
||||
dbus_info,
|
||||
serial_info,
|
||||
cherrypy_info,
|
||||
ws4py_info,
|
||||
]
|
||||
|
||||
return '\n'.join([_format_dependency(a()) for a in adapters])
|
||||
|
||||
|
||||
def _format_dependency(dep_info):
|
||||
lines = []
|
||||
for adapter in adapters:
|
||||
dep_info = adapter()
|
||||
lines.append('%(name)s: %(version)s' % {
|
||||
'name': dep_info['name'],
|
||||
'version': dep_info.get('version', 'not found'),
|
||||
})
|
||||
if 'path' in dep_info:
|
||||
lines.append(' Imported from: %s' % (
|
||||
os.path.dirname(dep_info['path'])))
|
||||
if 'other' in dep_info:
|
||||
lines.append(' Other: %s' % (
|
||||
formatting.indent(dep_info['other'])),)
|
||||
|
||||
if 'version' not in dep_info:
|
||||
lines.append('%s: not found' % dep_info['name'])
|
||||
else:
|
||||
lines.append('%s: %s from %s' % (
|
||||
dep_info['name'],
|
||||
dep_info['version'],
|
||||
os.path.dirname(dep_info.get('path', 'none')),
|
||||
))
|
||||
|
||||
if 'other' in dep_info:
|
||||
lines.append(' Detailed information: %s' % (
|
||||
formatting.indent(dep_info['other'], places=4)),)
|
||||
|
||||
if dep_info.get('dependencies', []):
|
||||
for sub_dep_info in dep_info['dependencies']:
|
||||
sub_dep_lines = _format_dependency(sub_dep_info)
|
||||
lines.append(
|
||||
formatting.indent(sub_dep_lines, places=2, singles=True))
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
@ -71,13 +87,46 @@ def python_info():
|
||||
}
|
||||
|
||||
|
||||
def pkg_info(project_name=None, include_extras=False):
|
||||
if project_name is None:
|
||||
project_name = 'Mopidy'
|
||||
distribution = pkg_resources.get_distribution(project_name)
|
||||
extras = include_extras and distribution.extras or []
|
||||
dependencies = [
|
||||
pkg_info(d) for d in distribution.requires(extras)]
|
||||
return {
|
||||
'name': distribution.project_name,
|
||||
'version': distribution.version,
|
||||
'path': distribution.location,
|
||||
'dependencies': dependencies,
|
||||
}
|
||||
|
||||
|
||||
def gstreamer_info():
|
||||
other = []
|
||||
other.append('Python wrapper: gst-python %s' % (
|
||||
'.'.join(map(str, gst.get_pygst_version()))))
|
||||
other.append('Relevant elements:')
|
||||
|
||||
found_elements = []
|
||||
missing_elements = []
|
||||
for name, status in _gstreamer_check_elements():
|
||||
other.append(' %s: %s' % (name, 'OK' if status else 'not found'))
|
||||
if status:
|
||||
found_elements.append(name)
|
||||
else:
|
||||
missing_elements.append(name)
|
||||
|
||||
other.append('Relevant elements:')
|
||||
other.append(' Found:')
|
||||
for element in found_elements:
|
||||
other.append(' %s' % element)
|
||||
else:
|
||||
other.append(' none')
|
||||
other.append(' Not found:')
|
||||
for element in missing_elements:
|
||||
other.append(' %s' % element)
|
||||
else:
|
||||
other.append(' none')
|
||||
|
||||
return {
|
||||
'name': 'GStreamer',
|
||||
'version': '.'.join(map(str, gst.get_gst_version())),
|
||||
@ -134,82 +183,3 @@ def _gstreamer_check_elements():
|
||||
gst.registry_get_default().get_feature_list(gst.TYPE_ELEMENT_FACTORY)]
|
||||
return [
|
||||
(element, element in known_elements) for element in elements_to_check]
|
||||
|
||||
|
||||
def pykka_info():
|
||||
return {
|
||||
'name': 'Pykka',
|
||||
'version': pykka.__version__,
|
||||
'path': pykka.__file__,
|
||||
}
|
||||
|
||||
|
||||
def pyspotify_info():
|
||||
dep_info = {'name': 'pyspotify'}
|
||||
try:
|
||||
import spotify
|
||||
if hasattr(spotify, '__version__'):
|
||||
dep_info['version'] = spotify.__version__
|
||||
else:
|
||||
dep_info['version'] = '< 1.3'
|
||||
dep_info['path'] = spotify.__file__
|
||||
dep_info['other'] = 'Built for libspotify API version %d' % (
|
||||
spotify.api_version,)
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def pylast_info():
|
||||
dep_info = {'name': 'pylast'}
|
||||
try:
|
||||
import pylast
|
||||
dep_info['version'] = pylast.__version__
|
||||
dep_info['path'] = pylast.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def dbus_info():
|
||||
dep_info = {'name': 'dbus-python'}
|
||||
try:
|
||||
import dbus
|
||||
dep_info['version'] = dbus.__version__
|
||||
dep_info['path'] = dbus.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def serial_info():
|
||||
dep_info = {'name': 'pyserial'}
|
||||
try:
|
||||
import serial
|
||||
dep_info['version'] = serial.VERSION
|
||||
dep_info['path'] = serial.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def cherrypy_info():
|
||||
dep_info = {'name': 'cherrypy'}
|
||||
try:
|
||||
import cherrypy
|
||||
dep_info['version'] = cherrypy.__version__
|
||||
dep_info['path'] = cherrypy.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def ws4py_info():
|
||||
dep_info = {'name': 'ws4py'}
|
||||
try:
|
||||
import ws4py
|
||||
dep_info['version'] = ws4py.__version__
|
||||
dep_info['path'] = ws4py.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
@ -4,13 +4,15 @@ import re
|
||||
import unicodedata
|
||||
|
||||
|
||||
def indent(string, places=4, linebreak='\n'):
|
||||
def indent(string, places=4, linebreak='\n', singles=False):
|
||||
lines = string.split(linebreak)
|
||||
if len(lines) == 1:
|
||||
if not singles and len(lines) == 1:
|
||||
return string
|
||||
result = ''
|
||||
for line in lines:
|
||||
result += linebreak + ' ' * places + line
|
||||
for i, line in enumerate(lines):
|
||||
lines[i] = ' ' * places + line
|
||||
result = linebreak.join(lines)
|
||||
if not singles:
|
||||
result = linebreak + result
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@ -5,37 +5,8 @@ import platform
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst
|
||||
import pykka
|
||||
|
||||
try:
|
||||
import dbus
|
||||
except ImportError:
|
||||
dbus = False
|
||||
|
||||
try:
|
||||
import pylast
|
||||
except ImportError:
|
||||
pylast = False
|
||||
|
||||
try:
|
||||
import serial
|
||||
except ImportError:
|
||||
serial = False
|
||||
|
||||
try:
|
||||
import spotify
|
||||
except ImportError:
|
||||
spotify = False
|
||||
|
||||
try:
|
||||
import cherrypy
|
||||
except ImportError:
|
||||
cherrypy = False
|
||||
|
||||
try:
|
||||
import ws4py
|
||||
except ImportError:
|
||||
ws4py = False
|
||||
import mock
|
||||
|
||||
from mopidy.utils import deps
|
||||
|
||||
@ -47,17 +18,32 @@ class DepsTest(unittest.TestCase):
|
||||
adapters = [
|
||||
lambda: dict(name='Python', version='FooPython 2.7.3'),
|
||||
lambda: dict(name='Platform', version='Loonix 4.0.1'),
|
||||
lambda: dict(name='Pykka', path='/foo/bar/baz.py', other='Quux')
|
||||
lambda: dict(
|
||||
name='Pykka', version='1.1',
|
||||
path='/foo/bar/baz.py', other='Quux'),
|
||||
lambda: dict(name='Foo'),
|
||||
lambda: dict(name='Mopidy', version='0.13', dependencies=[
|
||||
dict(name='pylast', version='0.5', dependencies=[
|
||||
dict(name='setuptools', version='0.6')
|
||||
])
|
||||
])
|
||||
]
|
||||
|
||||
result = deps.format_dependency_list(adapters)
|
||||
|
||||
self.assertIn('Python: FooPython 2.7.3', result)
|
||||
|
||||
self.assertIn('Platform: Loonix 4.0.1', result)
|
||||
self.assertIn('Pykka: not found', result)
|
||||
self.assertIn('Imported from: /foo/bar', result)
|
||||
|
||||
self.assertIn('Pykka: 1.1 from /foo/bar', result)
|
||||
self.assertNotIn('/baz.py', result)
|
||||
self.assertIn('Quux', result)
|
||||
self.assertIn('Detailed information: Quux', result)
|
||||
|
||||
self.assertIn('Foo: not found', result)
|
||||
|
||||
self.assertIn('Mopidy: 0.13', result)
|
||||
self.assertIn(' pylast: 0.5', result)
|
||||
self.assertIn(' setuptools: 0.6', result)
|
||||
|
||||
def test_platform_info(self):
|
||||
result = deps.platform_info()
|
||||
@ -85,59 +71,39 @@ class DepsTest(unittest.TestCase):
|
||||
'.'.join(map(str, gst.get_pygst_version())), result['other'])
|
||||
self.assertIn('Relevant elements:', result['other'])
|
||||
|
||||
def test_pykka_info(self):
|
||||
result = deps.pykka_info()
|
||||
@mock.patch('pkg_resources.get_distribution')
|
||||
def test_pkg_info(self, get_distribution_mock):
|
||||
dist_mopidy = mock.Mock()
|
||||
dist_mopidy.project_name = 'Mopidy'
|
||||
dist_mopidy.version = '0.13'
|
||||
dist_mopidy.location = '/tmp/example/mopidy'
|
||||
dist_mopidy.requires.return_value = ['Pykka']
|
||||
|
||||
self.assertEquals('Pykka', result['name'])
|
||||
self.assertEquals(pykka.__version__, result['version'])
|
||||
self.assertIn('pykka', result['path'])
|
||||
dist_pykka = mock.Mock()
|
||||
dist_pykka.project_name = 'Pykka'
|
||||
dist_pykka.version = '1.1'
|
||||
dist_pykka.location = '/tmp/example/pykka'
|
||||
dist_pykka.requires.return_value = ['setuptools']
|
||||
|
||||
@unittest.skipUnless(spotify, 'pyspotify not found')
|
||||
def test_pyspotify_info(self):
|
||||
result = deps.pyspotify_info()
|
||||
dist_setuptools = mock.Mock()
|
||||
dist_setuptools.project_name = 'setuptools'
|
||||
dist_setuptools.version = '0.6'
|
||||
dist_setuptools.location = '/tmp/example/setuptools'
|
||||
dist_setuptools.requires.return_value = []
|
||||
|
||||
self.assertEquals('pyspotify', result['name'])
|
||||
self.assertEquals(spotify.__version__, result['version'])
|
||||
self.assertIn('spotify', result['path'])
|
||||
self.assertIn('Built for libspotify API version', result['other'])
|
||||
self.assertIn(str(spotify.api_version), result['other'])
|
||||
get_distribution_mock.side_effect = [
|
||||
dist_mopidy, dist_pykka, dist_setuptools]
|
||||
|
||||
@unittest.skipUnless(pylast, 'pylast not found')
|
||||
def test_pylast_info(self):
|
||||
result = deps.pylast_info()
|
||||
result = deps.pkg_info()
|
||||
|
||||
self.assertEquals('pylast', result['name'])
|
||||
self.assertEquals(pylast.__version__, result['version'])
|
||||
self.assertIn('pylast', result['path'])
|
||||
self.assertEquals('Mopidy', result['name'])
|
||||
self.assertEquals('0.13', result['version'])
|
||||
self.assertIn('mopidy', result['path'])
|
||||
|
||||
@unittest.skipUnless(dbus, 'dbus not found')
|
||||
def test_dbus_info(self):
|
||||
result = deps.dbus_info()
|
||||
dep_info_pykka = result['dependencies'][0]
|
||||
self.assertEquals('Pykka', dep_info_pykka['name'])
|
||||
self.assertEquals('1.1', dep_info_pykka['version'])
|
||||
|
||||
self.assertEquals('dbus-python', result['name'])
|
||||
self.assertEquals(dbus.__version__, result['version'])
|
||||
self.assertIn('dbus', result['path'])
|
||||
|
||||
@unittest.skipUnless(serial, 'serial not found')
|
||||
def test_serial_info(self):
|
||||
result = deps.serial_info()
|
||||
|
||||
self.assertEquals('pyserial', result['name'])
|
||||
self.assertEquals(serial.VERSION, result['version'])
|
||||
self.assertIn('serial', result['path'])
|
||||
|
||||
@unittest.skipUnless(cherrypy, 'cherrypy not found')
|
||||
def test_cherrypy_info(self):
|
||||
result = deps.cherrypy_info()
|
||||
|
||||
self.assertEquals('cherrypy', result['name'])
|
||||
self.assertEquals(cherrypy.__version__, result['version'])
|
||||
self.assertIn('cherrypy', result['path'])
|
||||
|
||||
@unittest.skipUnless(ws4py, 'ws4py not found')
|
||||
def test_ws4py_info(self):
|
||||
result = deps.ws4py_info()
|
||||
|
||||
self.assertEquals('ws4py', result['name'])
|
||||
self.assertEquals(ws4py.__version__, result['version'])
|
||||
self.assertIn('ws4py', result['path'])
|
||||
dep_info_setuptools = dep_info_pykka['dependencies'][0]
|
||||
self.assertEquals('setuptools', dep_info_setuptools['name'])
|
||||
self.assertEquals('0.6', dep_info_setuptools['version'])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user