1
0
mirror of https://github.com/gryf/fs-uae-wrapper.git synced 2025-12-18 20:10:26 +01:00

Fix some lint errors and warnings

This commit is contained in:
2024-09-14 10:53:58 +02:00
parent 7b40974779
commit 3b597e34ee
6 changed files with 166 additions and 43 deletions

View File

@@ -137,6 +137,7 @@ Currently, couple of wrapper modules are available:
- cd32 - cd32
- archive - archive
- savestate - savestate
- whdload
plain plain
----- -----
@@ -323,6 +324,10 @@ Options used:
* ``wrapper_whdload_base`` (required) path to the whdload base system. Usually * ``wrapper_whdload_base`` (required) path to the whdload base system. Usually
it's minimal system containing at least whdload executables in C, and config it's minimal system containing at least whdload executables in C, and config
in S. Read on below for further details. in S. Read on below for further details.
* ``wrapper_whdload_options`` (optional) this option will replace the line in
``s:whdload-startup`` with specific ``whdload`` options for certain slave.
For reference look at WHDLoad documentation and/or on ``s:WHDLoad.prefs``.
Note, that ``Slave=`` option must not be used.
* ``wrapper_archive`` (optional) path to the whdload archive, defaults to same * ``wrapper_archive`` (optional) path to the whdload archive, defaults to same
name as configuration file with some detected archive extension. Note, that name as configuration file with some detected archive extension. Note, that
name is case sensitive name is case sensitive
@@ -336,19 +341,69 @@ internet).
Base image Base image
~~~~~~~~~~ ~~~~~~~~~~
To make it work, first the minimal system archive need to be prepared. There To make it work, first the absolute minimal image need to contain following
are few dependences to be included in such small system: structure:
.. code::
.
├── C
│   ├── DIC
│   ├── Execute
│   ├── Patcher
│   ├── RawDIC
│   ├── SetPatch
│   ├── WHDLoad
│   └── WHDLoadCD32
└── S
├── startup-sequence
└── WHDLoad.prefs
where the minimum dependences are:
- ``Excecute`` from your copy of Workbench
- `WHDLoad`_ 18.9 - `WHDLoad`_ 18.9
- `uaequit`_
- `SetPatch`_ 43.6 - `SetPatch`_ 43.6
- ``Excecute``, ``Assign`` and whatever commands you'll be use in scripts from
your copy of Workbench and the ``S/startup-sequence`` should at east contain:
.. code::
setpatch QUIET
IF EXISTS S:whdload-startup
Execute S:whdload-startup
EndIF
To leverage more pleasant UX, additionally those bits should be installed (or -
copied into base image filesystem):
- ``Assign`` and whatever commands you'll be use in scripts from your copy of
- `uaequit`_ - this will allow to quit emulator, after quiting game
Workbench
- `kgiconload`_ - tool for reading icon and executing *default tool* with - `kgiconload`_ - tool for reading icon and executing *default tool* with
optionally defined tool types as parameters (in this case: WHDLoad) optionally defined tool types as parameters (in this case: WHDLoad)
- `SKick`_ optionally - for kickstart relocations. Also images of corresponding - `SKick`_ optionally - for kickstart relocations. Also images of corresponding
kickstart ROM images will be needed. kickstart ROM images will be needed.
and then ``s/startup-sequence`` might looks a follows:
.. code::
Assign >NIL: ENV: RAM:
Assign >NIL: T: RAM:
setpatch QUIET
IF EXISTS S:whdload-startup
Execute S:whdload-startup
EndIF
C:UAEquit
Creating base image archive
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now, the tree for the minimal image could look like that: Now, the tree for the minimal image could look like that:
.. code:: .. code::
@@ -369,7 +424,9 @@ Now, the tree for the minimal image could look like that:
└── WHDLoad.prefs └── WHDLoad.prefs
to use relocation tables you'll need to place ``Kickstarts`` drawer into Devs to use relocation tables you'll need to place ``Kickstarts`` drawer into Devs
drawer, so it'll looks like this: drawer. Also keep in mind, that corresponding kickstart rom images need to be
placed there as well, otherwise it may or may not work. Structure looks like
this:
.. code:: .. code::
. .
@@ -421,7 +478,7 @@ tar with different compressions: ``tar Jcf /tmp/base.tar.xz .``, ``tar zcf
/tmp/base.tgz .``, ``tar jcf /tmp/base.tar.bz2 .``. It should work with all /tmp/base.tgz .``, ``tar jcf /tmp/base.tar.bz2 .``. It should work with all
mentioned at the beginning of this document archivers. mentioned at the beginning of this document archivers.
Starting point is in ``S/startup-sequence`` file, where eventually Starting point is in ``S/startup-sequence`` file, where eventually
``S/whdload-startup`` is executed, which will be created by fs-uae-warpper ``S/whdload-startup`` is executed, which will be created by fs-uae-warpper
before execution by fs-uae. before execution by fs-uae.

View File

@@ -82,7 +82,7 @@ class Base(object):
"""execute fs-uae""" """execute fs-uae"""
curdir = os.path.abspath('.') curdir = os.path.abspath('.')
os.chdir(self.dir) os.chdir(self.dir)
utils.run_command(['fs-uae'] + self.fsuae_options.list()) utils.run_command(['fs-uae', *self.fsuae_options.list()])
os.chdir(curdir) os.chdir(curdir)
return True return True

View File

@@ -11,8 +11,8 @@ from fs_uae_wrapper import path
class Archive(object): class Archive(object):
"""Base class for archive support""" """Base class for archive support"""
ADD = ['a'] ADD = ('a',)
EXTRACT = ['x'] EXTRACT = ('x',)
ARCH = 'false' ARCH = 'false'
def __init__(self): def __init__(self):
@@ -27,8 +27,8 @@ class Archive(object):
files = files if files else ['.'] files = files if files else ['.']
logging.debug("Calling `%s %s %s %s'.", self._compress, logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files)) " ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name] result = subprocess.call([self._compress, *self.ADD, arch_name,
+ files) *files])
if result != 0: if result != 0:
logging.error("Unable to create archive `%s'.", arch_name) logging.error("Unable to create archive `%s'.", arch_name)
return False return False
@@ -44,8 +44,7 @@ class Archive(object):
logging.debug("Calling `%s %s %s'.", self._compress, logging.debug("Calling `%s %s %s'.", self._compress,
" ".join(self.ADD), arch_name) " ".join(self.ADD), arch_name)
result = subprocess.call([self._decompress] + self.EXTRACT + result = subprocess.call([self._decompress, *self.EXTRACT, arch_name])
[arch_name])
if result != 0: if result != 0:
logging.error("Unable to extract archive `%s'.", arch_name) logging.error("Unable to extract archive `%s'.", arch_name)
return False return False
@@ -53,16 +52,16 @@ class Archive(object):
class TarArchive(Archive): class TarArchive(Archive):
ADD = ['cf'] ADD = ('cf',)
EXTRACT = ['xf'] EXTRACT = ('xf',)
ARCH = 'tar' ARCH = 'tar'
def create(self, arch_name, files=None): def create(self, arch_name, files=None):
files = files if files else sorted(os.listdir('.')) files = files if files else sorted(os.listdir('.'))
logging.debug("Calling `%s %s %s %s'.", self._compress, logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files)) " ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name] + result = subprocess.call([self._compress, *self.ADD, arch_name,
files) *files])
if result != 0: if result != 0:
logging.error("Unable to create archive `%s'.", arch_name) logging.error("Unable to create archive `%s'.", arch_name)
return False return False
@@ -70,15 +69,15 @@ class TarArchive(Archive):
class TarGzipArchive(TarArchive): class TarGzipArchive(TarArchive):
ADD = ['zcf'] ADD = ('zcf',)
class TarBzip2Archive(TarArchive): class TarBzip2Archive(TarArchive):
ADD = ['jcf'] ADD = ('jcf',)
class TarXzArchive(TarArchive): class TarXzArchive(TarArchive):
ADD = ['Jcf'] ADD = ('Jcf',)
class LhaArchive(Archive): class LhaArchive(Archive):
@@ -86,8 +85,8 @@ class LhaArchive(Archive):
class ZipArchive(Archive): class ZipArchive(Archive):
ADD = ['a', '-tzip'] ADD = ('a', '-tzip')
ARCH = ['7z', 'zip'] ARCH = ('7z', 'zip')
def __init__(self): def __init__(self):
super(ZipArchive, self).__init__() super(ZipArchive, self).__init__()
@@ -102,7 +101,7 @@ class SevenZArchive(Archive):
class LzxArchive(Archive): class LzxArchive(Archive):
EXTRACT = ['-x'] EXTRACT = ('-x',)
ARCH = 'unlzx' ARCH = 'unlzx'
@classmethod @classmethod
@@ -113,7 +112,7 @@ class LzxArchive(Archive):
class RarArchive(Archive): class RarArchive(Archive):
ARCH = ['rar', 'unrar'] ARCH = ('rar', 'unrar')
def create(self, arch_name, files=None): def create(self, arch_name, files=None):
files = files if files else sorted(os.listdir('.')) files = files if files else sorted(os.listdir('.'))
@@ -124,8 +123,8 @@ class RarArchive(Archive):
logging.debug("Calling `%s %s %s %s'.", self._compress, logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files)) " ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name] + result = subprocess.call([self._compress, *self.ADD, arch_name,
files) *files])
if result != 0: if result != 0:
logging.error("Unable to create archive `%s'.", arch_name) logging.error("Unable to create archive `%s'.", arch_name)
return False return False
@@ -134,7 +133,7 @@ class RarArchive(Archive):
class Archivers(object): class Archivers(object):
"""Archivers class""" """Archivers class"""
archivers = [{'arch': TarArchive, 'name': 'tar', 'ext': ['tar']}, archivers = ({'arch': TarArchive, 'name': 'tar', 'ext': ['tar']},
{'arch': TarGzipArchive, 'name': 'tgz', {'arch': TarGzipArchive, 'name': 'tgz',
'ext': ['tar.gz', 'tgz']}, 'ext': ['tar.gz', 'tgz']},
{'arch': TarBzip2Archive, 'name': 'tar.bz2', {'arch': TarBzip2Archive, 'name': 'tar.bz2',
@@ -144,7 +143,7 @@ class Archivers(object):
{'arch': SevenZArchive, 'name': '7z', 'ext': ['7z']}, {'arch': SevenZArchive, 'name': '7z', 'ext': ['7z']},
{'arch': ZipArchive, 'name': 'zip', 'ext': ['zip']}, {'arch': ZipArchive, 'name': 'zip', 'ext': ['zip']},
{'arch': LhaArchive, 'name': 'lha', 'ext': ['lha', 'lzh']}, {'arch': LhaArchive, 'name': 'lha', 'ext': ['lha', 'lzh']},
{'arch': LzxArchive, 'name': 'lzx', 'ext': ['lzx']}] {'arch': LzxArchive, 'name': 'lzx', 'ext': ['lzx']})
@classmethod @classmethod
def get(cls, extension): def get(cls, extension):

View File

@@ -16,8 +16,8 @@ class Wrapper(base.Base):
def _run_emulator(self): def _run_emulator(self):
"""execute fs-uae""" """execute fs-uae"""
utils.run_command(['fs-uae'] + [self.conf_file] + utils.run_command(['fs-uae', self.conf_file,
self.fsuae_options.list()) *self.fsuae_options.list()])
def clean(self): def clean(self):
"""Do the cleanup. Here - just do nothing""" """Do the cleanup. Here - just do nothing"""

View File

@@ -80,12 +80,20 @@ class Wrapper(base.ArchiveBase):
# find slave name # find slave name
slave_fname = None slave_fname = None
slave_path = None slave_path = None
case_insensitvie_map = {}
# build case insensitive map of paths and find the slave file
for root, dirnames, fnames in os.walk('.'):
for dirname in dirnames:
full_path = os.path.normpath(os.path.join(root, dirname))
case_insensitvie_map[full_path.lower()] = full_path
for root, dirs, fnames in os.walk('.'):
for fname in fnames: for fname in fnames:
if fname.lower().endswith('.slave'): full_path = os.path.normpath(os.path.join(root, fname))
case_insensitvie_map[full_path.lower()] = full_path
if not slave_fname and fname.lower().endswith('.slave'):
slave_path, slave_fname = os.path.normpath(root), fname slave_path, slave_fname = os.path.normpath(root), fname
break
if slave_fname is None: if slave_fname is None:
logging.error("Cannot find .slave file in archive.") logging.error("Cannot find .slave file in archive.")
return False return False
@@ -103,10 +111,26 @@ class Wrapper(base.ArchiveBase):
"archive.", slave_fname) "archive.", slave_fname)
return False return False
# Write startup file # find proper way to handle slave
with open("S/whdload-startup", "w") as fobj: # 1. check if there are user provided params
fobj.write(f"cd {slave_path}\n") contents = f"cd {slave_path}\n"
fobj.write(f"C:kgiconload {icon_fname}\n") if self.fsuae_options.get('wrapper_whdload_options'):
contents = (f"{contents}"
f"C:whdload "
f"{self.fsuae_options['wrapper_whdload_options']} "
f"Slave={slave_fname}\n")
else:
# no params, find if kgiconload is available
if case_insensitvie_map.get('c/kgiconload'):
contents = f"{contents}C:kgiconload {icon_fname}\n"
else:
# if not, just add common defaults
contents = (f"{contents}C:whdload Preload "
f"Slave={slave_fname}\n")
fname = os.path.join(case_insensitvie_map.get('s'), 'whdload-startup')
with open(fname, "w") as fobj:
fobj.write(contents)
os.chdir(curdir) os.chdir(curdir)
return True return True

View File

@@ -176,15 +176,58 @@ class TestWHDLoad(TestCase):
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {}) wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
self.assertFalse(wrapper._find_slave()) self.assertFalse(wrapper._find_slave())
@mock.patch('builtins.open')
@mock.patch('os.listdir') @mock.patch('os.listdir')
@mock.patch('os.walk') @mock.patch('os.walk')
@mock.patch('os.chdir') @mock.patch('os.chdir')
def test_find_slave_success(self, chdir, walk, listdir, bopen): def test_find_slave_success(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info') contents = ('foo', 'bar', 'baz.slave', 'baz.info')
walk.return_value = [(".", ('game'), ()), _open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'kgiconload')),
('./S', (), ()),
('./game', (), contents)] ('./game', (), contents)]
listdir.return_value = contents listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {}) wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
self.assertTrue(wrapper._find_slave()) with mock.patch('builtins.open', _open):
bopen.assert_called_once() self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with('cd game\n'
'C:kgiconload baz.info\n')
@mock.patch('os.listdir')
@mock.patch('os.walk')
@mock.patch('os.chdir')
def test_find_slave_minial(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info')
_open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'WHDLoad')),
('./S', (), ()),
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
with mock.patch('builtins.open', _open):
self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with('cd game\nC:whdload Preload '
'Slave=baz.slave\n')
@mock.patch('os.listdir')
@mock.patch('os.walk')
@mock.patch('os.chdir')
def test_find_custom_options(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info')
_open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'WHDLoad')),
('./S', (), ()),
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
whdl_opts = 'Preload SplashDelay=0 MMU PAL'
wrapper.fsuae_options['wrapper_whdload_options'] = whdl_opts
with mock.patch('builtins.open', _open):
self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with(f'cd game\nC:whdload {whdl_opts} '
'Slave=baz.slave\n')