From d67a78c3f86751a551b370c32aaf3934e772825f Mon Sep 17 00:00:00 2001 From: kaliko Date: Wed, 5 May 2021 18:30:45 +0200 Subject: [PATCH] Add abstract unix socket support for MPD connection Add unittests for env var parsing --- doc/Changelog | 1 + sima/utils/config.py | 10 ++++--- sima/utils/utils.py | 33 +++++++++++++++-------- tests/test_config.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index c487b0e..0e390f1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,7 @@ MPD_sima v0.18.0.dev0 * Removed obsolete --create-db and --generate-config options * Fixed crash when setting XDG_CONFIG_HOME (closes #50) + * Add abstract unix socket support for MPD connection -- kaliko Wed, 28 Apr 2021 17:21:39 +0200 diff --git a/sima/utils/config.py b/sima/utils/config.py index 854d6df..a46c0c6 100644 --- a/sima/utils/config.py +++ b/sima/utils/config.py @@ -139,7 +139,7 @@ class ConfMan: # CONFIG MANAGER CLASS self.use_envar() self.startopt = options - ## INIT CALLS + # INIT CALLS self.init_config() self.supersedes_config_with_cmd_line_options() # set dbfile @@ -204,9 +204,11 @@ class ConfMan: # CONFIG MANAGER CLASS # honor MPD_HOST format as in mpc(1) for command line option --host if self.startopt.get('host'): if '@' in self.startopt.get('host'): - passwd, host = self.startopt.get('host').split('@') - self.config.set('MPD', 'password', passwd) - self.config.set('MPD', 'host', host) + host, passwd = utils.parse_mpd_host(self.startopt.get('host')) + if passwd: + self.config.set('MPD', 'password', passwd) + if host: + self.config.set('MPD', 'host', host) def use_envar(self): """Use MPD en.var. to set defaults""" diff --git a/sima/utils/utils.py b/sima/utils/utils.py index 8e07e7a..b9dc980 100644 --- a/sima/utils/utils.py +++ b/sima/utils/utils.py @@ -30,7 +30,7 @@ from argparse import ArgumentError, Action from base64 import b64decode as push from codecs import getencoder from datetime import datetime -from os import environ, access, getcwd, W_OK, R_OK +from os import getenv, access, getcwd, W_OK, R_OK from os.path import dirname, isabs, join, normpath, exists, isdir, isfile from time import sleep @@ -45,22 +45,33 @@ def getws(dic): aka = getencoder('rot-13')(str((aka), 'utf-8'))[0] dic.update({'apikey': aka}) +def parse_mpd_host(value): + passwd = host = None + # If password is set: MPD_HOST=pass@host + if '@' in value: + mpd_host_env = value.split('@', 1) + if mpd_host_env[0]: + # A password is actually set + passwd = mpd_host_env[0] + if mpd_host_env[1]: + host = mpd_host_env[1] + elif mpd_host_env[1]: + # No password set but leading @ is an abstract socket + host = '@'+mpd_host_env[1] + else: + # MPD_HOST is a plain host + host = value + return host, passwd + def get_mpd_environ(): """ Retrieve MPD env. var. """ passwd = host = None - mpd_host_env = environ.get('MPD_HOST') - if mpd_host_env: - # If password is set: - # mpd_host_env = ['pass', 'host'] because MPD_HOST=pass@host - mpd_host_env = mpd_host_env.split('@') - mpd_host_env.reverse() - host = mpd_host_env[0] - if len(mpd_host_env) > 1 and mpd_host_env[1]: - passwd = mpd_host_env[1] - return (host, environ.get('MPD_PORT', None), passwd) + if getenv('MPD_HOST'): + host, passwd = parse_mpd_host(getenv('MPD_HOST')) + return (host, getenv('MPD_PORT', None), passwd) def normalize_path(path): diff --git a/tests/test_config.py b/tests/test_config.py index 36ba2ac..eee93bd 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -12,6 +12,11 @@ from sima.lib.logger import set_logger class TestConfMan(unittest.TestCase): + """For some tests we don't care about file access check, then to ensure + checks are properly mocked run test forcing non existent locations: + + XDG_DATA_HOME=/non/existent/ XDG_HOME_CONFIG=/non/existent/ python3 -m unittest -vf tests/test_config.py + """ @patch('sima.utils.config.makedirs') @patch('sima.utils.config.chmod') @@ -46,5 +51,63 @@ class TestConfMan(unittest.TestCase): expected_config = os.path.join(home, '.config', DIRNAME, CONF_FILE) self.assertEqual(constructed_config_location, expected_config) + @patch('sima.utils.config.makedirs') + @patch('sima.utils.config.chmod') + @patch('sima.utils.config.ConfMan.control_facc') + def test_MPD_env_var(self, *args): + host = 'example.org' + passwd = 's2cr34!' + port = '6601' + os.environ.pop('MPD_HOST', None) + os.environ.pop('MPD_PORT', None) + # Test defaults + conf = ConfMan({}) + self.assertEqual(dict(conf.config['MPD']), + {'host': 'localhost', 'port': '6600'}) + # Test provided env. var. + os.environ['MPD_HOST'] = host + conf = ConfMan({}) + self.assertEqual(dict(conf.config['MPD']), + {'host': host, 'port': '6600'}) + os.environ['MPD_HOST'] = f'{passwd}@{host}' + conf = ConfMan({}) + self.assertEqual(dict(conf.config['MPD']), + {'host': host, + 'password': passwd, + 'port': '6600'}) + # Test abstract unix socket support with password + os.environ['MPD_HOST'] = f'{passwd}@@/{host}' + conf = ConfMan({}) + self.assertEqual(dict(conf.config['MPD']), + {'host': f'@/{host}', + 'password': passwd, + 'port': '6600'}) + # Test abstract unix socket support only + os.environ['MPD_HOST'] = f'@/{host}' + conf = ConfMan({}) + self.assertEqual(dict(conf.config['MPD']), + {'host': f'@/{host}', + 'port': '6600'}) + # Test port + os.environ['MPD_PORT'] = f'{port}' + conf = ConfMan({}) + self.assertEqual(conf.config['MPD']['port'], port) + + @patch('sima.utils.config.makedirs') + @patch('sima.utils.config.chmod') + @patch('sima.utils.config.ConfMan.control_facc') + def test_config_origin_priority(self, *args): + # cli provided host overrides env. var. + os.environ['MPD_HOST'] = 'baz.foo' + conf = ConfMan({'host': 'cli.host'}) + self.assertEqual(conf.config['MPD']['host'], 'cli.host') + # cli provided abstract socket overrides env. var. + conf = ConfMan({'host': '@/abstract'}) + self.assertEqual(conf.config['MPD']['host'], '@/abstract') + # cli provided passord and abstract socket overrides env. var. + conf = ConfMan({'host': 'pass!@@/abstract'}) + self.assertEqual(conf.config['MPD']['host'], '@/abstract') + self.assertEqual(conf.config['MPD']['password'], 'pass!') + # VIM MODLINE # vim: ai ts=4 sw=4 sts=4 expandtab fileencoding=utf8 -- 2.39.2