mirror of
https://github.com/gryf/fs-uae-wrapper.git
synced 2026-02-02 22:25:47 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 148d28dac2 | |||
| 60139d1728 |
19
README.rst
19
README.rst
@@ -157,8 +157,8 @@ Options used:
|
|||||||
|
|
||||||
* ``wrapper`` (required) with ``cd32`` as an value
|
* ``wrapper`` (required) with ``cd32`` as an value
|
||||||
* ``wrapper_archive`` (required) path to the archive with CD32 iso/cue/wav
|
* ``wrapper_archive`` (required) path to the archive with CD32 iso/cue/wav
|
||||||
* ``wrapper_archiver`` (conditionally required) archiver to use for storage
|
* ``wrapper_archiver`` (optional) archiver to use for storage save state -
|
||||||
save state
|
default ``7z``.
|
||||||
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
|
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
|
||||||
message during extracting files
|
message during extracting files
|
||||||
* ``wrapper_save_state`` (optional) if set to "1", will load/archive save state
|
* ``wrapper_save_state`` (optional) if set to "1", will load/archive save state
|
||||||
@@ -175,7 +175,7 @@ fragment of configuration file is saved as ``ChaosEngine.fs-uae``:
|
|||||||
[config]
|
[config]
|
||||||
wrapper = cd32
|
wrapper = cd32
|
||||||
wrapper_archive = ChaosEngine.7z
|
wrapper_archive = ChaosEngine.7z
|
||||||
wrapper_archiver = 7z
|
wrapper_archiver = zip
|
||||||
wrapper_gui_msg = 1
|
wrapper_gui_msg = 1
|
||||||
|
|
||||||
amiga_model = CD32
|
amiga_model = CD32
|
||||||
@@ -219,10 +219,12 @@ archive
|
|||||||
Options used:
|
Options used:
|
||||||
|
|
||||||
* ``wrapper`` (required) with ``archive`` as an value
|
* ``wrapper`` (required) with ``archive`` as an value
|
||||||
* ``wrapper_archive`` (required) path to the archive with assets (usually means
|
* ``wrapper_archive`` (optional) path to the archive with assets (usually means
|
||||||
whole system directories, floppies or hard disk images)
|
whole system directories, floppies or hard disk images), defaults to same
|
||||||
* ``wrapper_archiver`` (conditionally required) archiver to use for storage
|
name as configuration file with some detected archive extension. Note, that
|
||||||
save state
|
name is case sensitive
|
||||||
|
* ``wrapper_archiver`` (optional) archiver to use for storage save state -
|
||||||
|
default ``7z``.
|
||||||
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
|
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
|
||||||
message during extracting files
|
message during extracting files
|
||||||
* ``wrapper_persist_data`` (optional) if set to "1", will compress (possibly
|
* ``wrapper_persist_data`` (optional) if set to "1", will compress (possibly
|
||||||
@@ -277,7 +279,8 @@ savestate
|
|||||||
Options used:
|
Options used:
|
||||||
|
|
||||||
* ``wrapper`` (required) with ``archive`` as an value
|
* ``wrapper`` (required) with ``archive`` as an value
|
||||||
* ``wrapper_archiver`` (required) archiver to use for storage save state
|
* ``wrapper_archiver`` (optional) archiver to use for storage save state -
|
||||||
|
default ``7z``.
|
||||||
|
|
||||||
This module is primarily used to run emulator with read only media attached
|
This module is primarily used to run emulator with read only media attached
|
||||||
(like images of floppies or uncompressed CD-ROMs) and its purpose is to
|
(like images of floppies or uncompressed CD-ROMs) and its purpose is to
|
||||||
|
|||||||
@@ -237,9 +237,9 @@ class Base(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if 'wrapper_archiver' not in self.all_options:
|
if 'wrapper_archiver' not in self.all_options:
|
||||||
logging.error("Configuration lacks of required "
|
logging.warning("Configuration lacks of optional "
|
||||||
"`wrapper_archiver' option.")
|
"`wrapper_archiver' option, fall back to 7z")
|
||||||
return False
|
self.all_options['wrapper_archiver'] = "7z"
|
||||||
|
|
||||||
if not path.which(self.all_options['wrapper_archiver']):
|
if not path.which(self.all_options['wrapper_archiver']):
|
||||||
logging.error("Cannot find archiver `%s'.",
|
logging.error("Cannot find archiver `%s'.",
|
||||||
@@ -295,8 +295,30 @@ class ArchiveBase(Base):
|
|||||||
validation_result = super(ArchiveBase, self)._validate_options()
|
validation_result = super(ArchiveBase, self)._validate_options()
|
||||||
|
|
||||||
if 'wrapper_archive' not in self.all_options:
|
if 'wrapper_archive' not in self.all_options:
|
||||||
sys.stderr.write("Configuration lacks of required "
|
logging.warning("Configuration lacks of optional `wrapper_archive'"
|
||||||
"`wrapper_archive' option.\n")
|
" option.\n")
|
||||||
validation_result = False
|
wrapper_archive = self._get_wrapper_archive_name()
|
||||||
|
if wrapper_archive is None:
|
||||||
|
logging.error("Configuration lacks of optional "
|
||||||
|
"`wrapper_archive', cannot deduct the name by "
|
||||||
|
"configuration file name.\n")
|
||||||
|
validation_result = False
|
||||||
|
self.all_options['wrapper_archive'] = wrapper_archive
|
||||||
|
|
||||||
return validation_result
|
return validation_result
|
||||||
|
|
||||||
|
def _get_wrapper_archive_name(self):
|
||||||
|
"""
|
||||||
|
Return full path to the archive name using configuration file
|
||||||
|
basename and appending one of the expected archive extensions.
|
||||||
|
"""
|
||||||
|
basename = os.path.splitext(self.conf_file)[0]
|
||||||
|
file_list = os.listdir('.')
|
||||||
|
for fname in file_list:
|
||||||
|
for ext in ('.7z', '.lha', '.lzx', '.zip', '.rar', '.tar', '.tgz',
|
||||||
|
'.tar.gz', '.tar.bz2', '.tar.xz'):
|
||||||
|
if ((basename + ext).lower() == fname.lower() and
|
||||||
|
basename == os.path.splitext(fname)[0]):
|
||||||
|
return fname
|
||||||
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Misc utilities
|
|||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
@@ -19,8 +20,8 @@ class CmdOption(dict):
|
|||||||
def add(self, option):
|
def add(self, option):
|
||||||
"""parse and add option to the dictionary"""
|
"""parse and add option to the dictionary"""
|
||||||
if not option.startswith('--'):
|
if not option.startswith('--'):
|
||||||
raise AttributeError("Cannot add option `%s' to the dictionary" %
|
raise AttributeError(f"Cannot add option {option} to the "
|
||||||
option)
|
f"dictionary")
|
||||||
if '=' in option:
|
if '=' in option:
|
||||||
key, val = option.split('=', 1)
|
key, val = option.split('=', 1)
|
||||||
key = key[2:].strip()
|
key = key[2:].strip()
|
||||||
@@ -35,9 +36,9 @@ class CmdOption(dict):
|
|||||||
ret_list = []
|
ret_list = []
|
||||||
for key, val in self.items():
|
for key, val in self.items():
|
||||||
if val != '1':
|
if val != '1':
|
||||||
ret_list.append('--%(k)s=%(v)s' % {'k': key, 'v': val})
|
ret_list.append(f'--{key}={val}')
|
||||||
else:
|
else:
|
||||||
ret_list.append('--%(k)s' % {'k': key})
|
ret_list.append(f'--{key}')
|
||||||
return ret_list
|
return ret_list
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ def create_archive(arch_name, title='', params=None):
|
|||||||
"""
|
"""
|
||||||
msg = ''
|
msg = ''
|
||||||
if title:
|
if title:
|
||||||
msg = "Creating archive for `%s'. Please be patient" % title
|
msg = f"Creating archive for `{title}'. Please be patient"
|
||||||
return operate_archive(arch_name, 'create', msg, params)
|
return operate_archive(arch_name, 'create', msg, params)
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ def extract_archive(arch_name, title='', params=None):
|
|||||||
"""
|
"""
|
||||||
msg = ''
|
msg = ''
|
||||||
if title:
|
if title:
|
||||||
msg = "Extracting files for `%s'. Please be patient" % title
|
msg = f"Extracting files for `{title}'. Please be patient"
|
||||||
return operate_archive(arch_name, 'extract', msg, params)
|
return operate_archive(arch_name, 'extract', msg, params)
|
||||||
|
|
||||||
|
|
||||||
@@ -143,8 +144,9 @@ def interpolate_variables(string, config_path, base=None):
|
|||||||
|
|
||||||
_string = string
|
_string = string
|
||||||
if '$CONFIG' in string:
|
if '$CONFIG' in string:
|
||||||
conf_path = os.path.dirname(os.path.abspath(config_path))
|
conf_path = pathlib.Path(config_path).resolve().parent
|
||||||
string = os.path.abspath(string.replace('$CONFIG', conf_path))
|
string = str(pathlib.Path(string.replace('$CONFIG', str(conf_path)))
|
||||||
|
.resolve())
|
||||||
|
|
||||||
if '$HOME' in string:
|
if '$HOME' in string:
|
||||||
string = string.replace('$HOME', os.path.expandvars('$HOME'))
|
string = string.replace('$HOME', os.path.expandvars('$HOME'))
|
||||||
|
|||||||
40
pyproject.toml
Normal file
40
pyproject.toml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools >= 61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "fs-uae-wrapper"
|
||||||
|
authors = [{name = "Roman Dobosz", email = "gryf73@gmail.com"}]
|
||||||
|
license = {text = "BSD"}
|
||||||
|
description = "Automate archives support and state saves for fs-uae"
|
||||||
|
readme = "README.rst"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
keywords = ["uae", "fs-uae", "amiga", "emulator", "wrapper"]
|
||||||
|
version = "0.9.1"
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Environment :: Console",
|
||||||
|
"Intended Audience :: End Users/Desktop",
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Topic :: System :: Emulators",
|
||||||
|
"Topic :: Games/Entertainment"
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/gryf/fs-uae-wrapper"
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
fs-uae-wrapper = "fs_uae_wrapper.wrapper:run"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
py-modules = ["fs_uae_wrapper"]
|
||||||
|
|
||||||
|
[tool.distutils.bdist_wheel]
|
||||||
|
universal = true
|
||||||
37
setup.cfg
37
setup.cfg
@@ -1,37 +0,0 @@
|
|||||||
[metadata]
|
|
||||||
name = fs-uae-wrapper
|
|
||||||
summary = Automate archives and state for fs-uae
|
|
||||||
description = Automate archives and state for fs-uae
|
|
||||||
long_description = file: README.rst
|
|
||||||
author = Roman Dobosz
|
|
||||||
author_email = gryf73@gmail.com
|
|
||||||
url = https://github.com/gryf/fs-uae-wrapper
|
|
||||||
license = BSD
|
|
||||||
keywords = uae, fs-uae, amiga, emulator, wrapper
|
|
||||||
version = 0.8.3
|
|
||||||
classifier =
|
|
||||||
Development Status :: 5 - Production/Stable
|
|
||||||
Environment :: Console
|
|
||||||
Intended Audience :: End Users/Desktop
|
|
||||||
License :: OSI Approved :: BSD License
|
|
||||||
Operating System :: OS Independent
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.8
|
|
||||||
Programming Language :: Python :: 3.9
|
|
||||||
Programming Language :: Python :: 3.10
|
|
||||||
Topic :: System :: Emulators
|
|
||||||
Topic :: Games/Entertainment
|
|
||||||
|
|
||||||
[install]
|
|
||||||
record = install.log
|
|
||||||
|
|
||||||
[options.entry_points]
|
|
||||||
console_scripts =
|
|
||||||
fs-uae-wrapper = fs_uae_wrapper.wrapper:run
|
|
||||||
|
|
||||||
[files]
|
|
||||||
packages =
|
|
||||||
fs_uae_wrapper
|
|
||||||
|
|
||||||
[bdist_wheel]
|
|
||||||
universal = 1
|
|
||||||
@@ -286,7 +286,7 @@ class TestBase(TestCase):
|
|||||||
which.return_value = '7z'
|
which.return_value = '7z'
|
||||||
bobj.all_options = {'wrapper': 'dummy',
|
bobj.all_options = {'wrapper': 'dummy',
|
||||||
'wrapper_save_state': '1'}
|
'wrapper_save_state': '1'}
|
||||||
self.assertFalse(bobj._validate_options())
|
self.assertTrue(bobj._validate_options())
|
||||||
|
|
||||||
bobj.all_options = {'wrapper': 'dummy',
|
bobj.all_options = {'wrapper': 'dummy',
|
||||||
'wrapper_save_state': '1',
|
'wrapper_save_state': '1',
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class TestSaveState(TestCase):
|
|||||||
self.assertFalse(arch._validate_options())
|
self.assertFalse(arch._validate_options())
|
||||||
|
|
||||||
arch.all_options['wrapper'] = 'savestate'
|
arch.all_options['wrapper'] = 'savestate'
|
||||||
self.assertFalse(arch._validate_options())
|
self.assertTrue(arch._validate_options())
|
||||||
|
|
||||||
arch.all_options['wrapper_archiver'] = 'rar'
|
arch.all_options['wrapper_archiver'] = 'rar'
|
||||||
self.assertTrue(arch._validate_options())
|
self.assertTrue(arch._validate_options())
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ class TestCmdOptions(TestCase):
|
|||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@mock.patch('os.getenv')
|
@mock.patch('os.getenv')
|
||||||
@mock.patch('os.path.expandvars')
|
@mock.patch('os.path.expandvars')
|
||||||
@mock.patch('distutils.spawn.find_executable')
|
@mock.patch('shutil.which')
|
||||||
def test_interpolate_variables(self, find_exe, expandv, getenv, os_exists):
|
def test_interpolate_variables(self, which, expandv, getenv, os_exists):
|
||||||
|
|
||||||
os_exists.return_value = True
|
os_exists.return_value = True
|
||||||
itrpl = utils.interpolate_variables
|
itrpl = utils.interpolate_variables
|
||||||
@@ -252,7 +252,7 @@ class TestCmdOptions(TestCase):
|
|||||||
'/home/user')
|
'/home/user')
|
||||||
|
|
||||||
string = '$APP/$EXE'
|
string = '$APP/$EXE'
|
||||||
find_exe.return_value = '/usr/bin/fs-uae'
|
which.return_value = '/usr/bin/fs-uae'
|
||||||
self.assertEqual(itrpl(string, '/home/user/Config.fs-uae'),
|
self.assertEqual(itrpl(string, '/home/user/Config.fs-uae'),
|
||||||
'/usr/bin/fs-uae//usr/bin/fs-uae')
|
'/usr/bin/fs-uae//usr/bin/fs-uae')
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ class TestWrapper(TestCase):
|
|||||||
fobj.write('\n')
|
fobj.write('\n')
|
||||||
|
|
||||||
wrapper.run()
|
wrapper.run()
|
||||||
mock_plain_run.called_once_with('Config.fs-uae',
|
mock_plain_run.assert_called_once()
|
||||||
['--fullscreen',
|
|
||||||
'--fade_out_duration=0'],
|
|
||||||
[])
|
|
||||||
|
|
||||||
# This will obviously fail for nonexistent module
|
# This will obviously fail for nonexistent module
|
||||||
sys.argv.append('--wrapper=dummy_wrapper')
|
sys.argv.append('--wrapper=dummy_wrapper')
|
||||||
|
|||||||
Reference in New Issue
Block a user