From cadcc3073441e4105064e1f4ecca79cc431c8cab Mon Sep 17 00:00:00 2001 From: gryf Date: Sun, 25 Dec 2016 19:03:30 +0100 Subject: [PATCH] Added utility module with common functions --- fs_uae_wrapper/utils.py | 133 +++++++++++++++++++++++++++++++++++++++- tests/test_utils.py | 68 ++++++++++++++++++++ 2 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 tests/test_utils.py diff --git a/fs_uae_wrapper/utils.py b/fs_uae_wrapper/utils.py index a5a5a77..c17cb0b 100644 --- a/fs_uae_wrapper/utils.py +++ b/fs_uae_wrapper/utils.py @@ -1,11 +1,16 @@ """ Misc utilities """ +from distutils import spawn import os import subprocess import sys +try: + import configparser +except ImportError: + import ConfigParser as configparser -from fs_uae_wrapper.wrapper import WRAPPER_KEY +from fs_uae_wrapper import WRAPPER_KEY ARCHIVERS = {'.tar': ['tar', 'xf'], @@ -20,6 +25,19 @@ ARCHIVERS = {'.tar': ['tar', 'xf'], '.lzx': ['unlzx']} +def get_config_options(conf): + """Read config file and return options as a dict""" + parser = configparser.SafeConfigParser() + try: + parser.read(conf) + except configparser.ParsingError: + # Configuration syntax is wrong + return None + + return {key: val for section in parser.sections() + for key, val in parser.items(section)} + + def extract_archive(arch_name): """ Extract provided archive to current directory @@ -46,7 +64,7 @@ def extract_archive(arch_name): return True -def merge_options(configuration, wrapper_options): +def merge_wrapper_options(configuration, wrapper_options): """ Merge dictionaries with wrapper options into one. Commandline options have precedence. @@ -59,3 +77,114 @@ def merge_options(configuration, wrapper_options): options.update(wrapper_options) return options + + +def options_to_dict(commandline): + """ + "Parse" commandline switches and return them as dictionary + """ + options = {} + for option in commandline: + if option.startswith('--'): + if '=' in option: + key, val = option[2:].split('=') + options[key.strip()] = val.strip() + else: + options[option[2:].strip()] = '1' + + return options + + +def merge_all_options(configuration, commandline): + """ + Merge dictionaries with wrapper options into one. Commandline options + have precedence. + """ + options = {} + for key, val in configuration: + options[key] = val + + options.update(options_to_dict(commandline)) + + return options + + +def interpolate_variables(string, config_path, base=None): + """ + Interpolate variables used in fs-uae configuration files, like: + - $CONFIG + - $HOME + - $EXE + - $APP + - $DOCUMENTS + - $BASE + """ + + if '$CONFIG' in string: + string = string.replace('$CONFIG', + os.path.dirname(os.path.abspath(config_path))) + if '$HOME' in string: + string = string.replace('$HOME', os.path.expandvars('$HOME')) + + if '$EXE' in string: + string = string.replace('$EXE', spawn.find_executable('fs-uae')) + + if '$APP' in string: + string = string.replace('$APP', spawn.find_executable('fs-uae')) + + if '$DOCUMENTS' in string: + xdg_docs = os.getenv('XDG_DOCUMENTS_DIR', + os.path.expanduser('~/Documents')) + string = string.replace('$DOCUMENTS', xdg_docs) + + if base: + if '$BASE' in string: + string = string.replace('$BASE', base) + + return string + + +def get_config(conf_file): + """ + Try to find configuration files and collect data from it. + Will search for paths described in https://fs-uae.net/paths + - ~/Documents/FS-UAE/Configurations/Default.fs-uae + - ~/Documents/FS-UAE/Configurations/Host.fs-uae + - ~/FS-UAE/Configurations/Default.fs-uae + - ~/FS-UAE/Configurations/Host.fs-uae + - ~/.config/fs-uae/fs-uae.conf + - ./fs-uae.conf + - ./Config.fs-uae + """ + + xdg_conf = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) + user = os.path.expanduser('~/') + paths = ((os.path.join(xdg_conf, 'fs-uae/fs-uae.conf'), + os.path.join(xdg_conf, 'fs-uae/')), + (os.path.join(user, + 'Documents/FS-UAE/Configurations/Default.fs-uae'), + os.path.join(user, 'Documents/FS-UAE')), + (os.path.join(user, 'FS-UAE/Configurations/Default.fs-uae'), + os.path.join(user, 'FS-UAE'))) + + for path, conf_dir in paths: + if os.path.exists(path): + config = get_config_options(path) + config.update(get_config_options(conf_file)) + break + else: + conf_dir = None + config = get_config_options(conf_file) + + if 'base_dir' in config: + base_dir = interpolate_variables(config['base_dir'], conf_file) + host = os.path.join(base_dir, 'Configurations/Host.fs-uae') + + if os.path.exists(host): + config.update(get_config_options(host)) + # overwrite host options again via provided custom/relative conf + config.update(get_config_options(conf_file)) + elif conf_dir: + config['_base_dir'] = conf_dir + + return config diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..27e7119 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,68 @@ +import os +import sys +from tempfile import mkstemp, mkdtemp +from unittest import TestCase +import shutil + +from fs_uae_wrapper import utils + + +class TestUtils(TestCase): + + def setUp(self): + fd, self.fname = mkstemp() + self.dirname = mkdtemp() + os.close(fd) + self._argv = sys.argv[:] + sys.argv = ['fs-uae-wrapper'] + self.curdir = os.path.abspath(os.curdir) + + def tearDown(self): + os.chdir(self.curdir) + shutil.rmtree(self.dirname) + os.unlink(self.fname) + sys.argv = self._argv[:] + + def test_get_config_options(self): + + configs = ["[conf]\nwrapper=foo\n", + "[conf]\n wrapper =foo\n", + "[conf]\n wrapper = foo\n", + "[conf]\nwrapper = foo \n"] + + for cfg in configs: + with open(self.fname, 'w') as fobj: + fobj.write(cfg) + + val = utils.get_config_options(self.fname) + self.assertDictEqual(val, {'wrapper': 'foo'}) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nwraper=foo\n") + conf = utils.get_config_options(self.fname) + self.assertDictEqual(conf, {'wraper': 'foo'}) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nwrapper\n") + conf = utils.get_config_options(self.fname) + self.assertIsNone(conf) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nfullscreen = 1\n") + conf = utils.get_config_options(self.fname) + self.assertDictEqual(conf, {'fullscreen': '1'}) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nwrapper= = = something went wrong\n") + conf = utils.get_config_options(self.fname) + self.assertDictEqual(conf, {'wrapper': '= = something went wrong'}) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nwrapper = = \n") + conf = utils.get_config_options(self.fname) + self.assertDictEqual(conf, {'wrapper': '='}) + + with open(self.fname, 'w') as fobj: + fobj.write("[conf]\nwrapper = \n") + conf = utils.get_config_options(self.fname) + self.assertDictEqual(conf, {'wrapper': ''})