From 7bda4f835f0055240461da88489cc31cef1992a4 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 7 Apr 2015 23:43:32 +0200 Subject: [PATCH] xdg: Add XDG dir utils --- mopidy/utils/xdg.py | 56 +++++++++++++++++++++++++++++++++ tests/utils/test_xdg.py | 69 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 mopidy/utils/xdg.py create mode 100644 tests/utils/test_xdg.py diff --git a/mopidy/utils/xdg.py b/mopidy/utils/xdg.py new file mode 100644 index 00000000..ffc6de22 --- /dev/null +++ b/mopidy/utils/xdg.py @@ -0,0 +1,56 @@ +from __future__ import absolute_import, unicode_literals + +import ConfigParser +import io +import os + + +def get_dirs(): + """Returns a dict of all the known XDG Base Directories for the current user. + + The keys ``XDG_CACHE_DIR``, ``XDG_CONFIG_DIR``, and ``XDG_DATA_DIR`` is + always available. + + Additional keys, like ``XDG_MUSIC_DIR``, may be available if the + ``$XDG_CONFIG_DIR/user-dirs.dirs`` file exists and is parseable. + + See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + for the XDG Base Directory specification. + """ + + dirs = { + 'XDG_CACHE_DIR': ( + os.environ.get('XDG_CACHE_HOME') or + os.path.expanduser(b'~/.cache')), + 'XDG_CONFIG_DIR': ( + os.environ.get('XDG_CONFIG_HOME') or + os.path.expanduser(b'~/.config')), + 'XDG_DATA_DIR': ( + os.environ.get('XDG_DATA_HOME') or + os.path.expanduser(b'~/.local/share')), + } + + dirs.update(_get_user_dirs(dirs['XDG_CONFIG_DIR'])) + + return dirs + + +def _get_user_dirs(xdg_config_dir): + dirs_file = os.path.join(xdg_config_dir, 'user-dirs.dirs') + + if not os.path.exists(dirs_file): + return {} + + with open(dirs_file, 'rb') as fh: + data = fh.read() + + data = b'[XDG_USER_DIRS]\n' + data + data = data.replace(b'$HOME', os.path.expanduser(b'~')) + data = data.replace(b'"', b'') + + config = ConfigParser.RawConfigParser() + config.readfp(io.BytesIO(data)) + + return { + k.decode('utf-8').upper(): os.path.abspath(v) + for k, v in config.items('XDG_USER_DIRS') if v is not None} diff --git a/tests/utils/test_xdg.py b/tests/utils/test_xdg.py new file mode 100644 index 00000000..eab595a4 --- /dev/null +++ b/tests/utils/test_xdg.py @@ -0,0 +1,69 @@ +from __future__ import unicode_literals + +import os + +import mock + +import pytest + +from mopidy.utils import xdg + + +@pytest.yield_fixture +def environ(): + patcher = mock.patch.dict(os.environ, clear=True) + yield patcher.start() + patcher.stop() + + +def test_cache_dir_default(environ): + assert xdg.get_dirs()['XDG_CACHE_DIR'] == os.path.expanduser(b'~/.cache') + + +def test_cache_dir_from_env(environ): + os.environ['XDG_CACHE_HOME'] = '/foo/bar' + + assert xdg.get_dirs()['XDG_CACHE_DIR'] == '/foo/bar' + + +def test_config_dir_default(environ): + assert xdg.get_dirs()['XDG_CONFIG_DIR'] == os.path.expanduser(b'~/.config') + + +def test_config_dir_from_env(environ): + os.environ['XDG_CONFIG_HOME'] = '/foo/bar' + + assert xdg.get_dirs()['XDG_CONFIG_DIR'] == '/foo/bar' + + +def test_data_dir_default(environ): + assert xdg.get_dirs()['XDG_DATA_DIR'] == os.path.expanduser( + b'~/.local/share') + + +def test_data_dir_from_env(environ): + os.environ['XDG_DATA_HOME'] = '/foo/bar' + + assert xdg.get_dirs()['XDG_DATA_DIR'] == '/foo/bar' + + +def test_user_dirs(environ, tmpdir): + os.environ['XDG_CONFIG_HOME'] = str(tmpdir) + + with open(os.path.join(str(tmpdir), 'user-dirs.dirs'), 'wb') as fh: + fh.write('# Some comments\n') + fh.write('XDG_MUSIC_DIR="$HOME/Music2"\n') + + result = xdg.get_dirs() + + assert result['XDG_MUSIC_DIR'] == os.path.expanduser(b'~/Music2') + assert 'XDG_DOWNLOAD_DIR' not in result + + +def test_user_dirs_when_no_dirs_file(environ, tmpdir): + os.environ['XDG_CONFIG_HOME'] = str(tmpdir) + + result = xdg.get_dirs() + + assert 'XDG_MUSIC_DIR' not in result + assert 'XDG_DOWNLOAD_DIR' not in result