diff --git a/skoolkit/skool2html.py b/skoolkit/skool2html.py
index 492294af..15f4630e 100644
--- a/skoolkit/skool2html.py
+++ b/skoolkit/skool2html.py
@@ -1,4 +1,4 @@
-# Copyright 2008-2022 Richard Dymond (rjdymond@gmail.com)
+# Copyright 2008-2022, 2024 Richard Dymond (rjdymond@gmail.com)
#
# This file is part of SkoolKit.
#
@@ -250,12 +250,13 @@ def write_disassembly(html_writer, files, search_dir, extra_search_dirs, pages,
# Copy resources named in the [Resources] section
resources = html_writer.ref_parser.get_dictionary('Resources')
search_dirs = _get_search_dirs(extra_search_dirs, search_dir)
- for f, dest_dir in resources.items():
+ for f, dest in resources.items():
fnames = []
for d in search_dirs:
fnames.extend(glob.glob(os.path.join(d, f), recursive=True))
if not fnames:
raise SkoolKitError('Cannot copy resource "{}": file not found'.format(normpath(f)))
+ dest_dir = html_writer.format_path(dest)
for fname in fnames:
if os.path.isfile(fname):
copy_resource(fname, odir, dest_dir)
diff --git a/skoolkit/skoolhtml.py b/skoolkit/skoolhtml.py
index 698bcd8f..c6d82248 100644
--- a/skoolkit/skoolhtml.py
+++ b/skoolkit/skoolhtml.py
@@ -194,7 +194,7 @@ def __init__(self, skool_parser, ref_parser, file_info=None, code_id=MAIN_CODE_I
self.titles.setdefault(map_name, map_name)
self._expand_values(self.paths)
- self.image_paths = {k: v for k, v in self.paths.items() if k.endswith('ImagePath')}
+ self.all_paths = {k: v for k, v in self.paths.items() if k.endswith('Path')}
self.asm_fname_template = self.paths['CodeFiles']
self.udg_fname_template = self.paths['UDGFilename']
@@ -1006,18 +1006,18 @@ def _image_path(self, fname, path_id):
"""
if fname:
fname = self.image_writer.image_fname(fname)
- expanded = self._expand_image_path(fname)
+ expanded = self.format_path(fname)
if expanded != fname or fname.startswith('/'):
return expanded.lstrip('/')
if path_id in self.paths:
- return join(self._expand_image_path(self.paths[path_id]), fname)
+ return join(self.format_path(self.paths[path_id]), fname)
raise SkoolKitError("Unknown path ID '{0}' for image file '{1}'".format(path_id, fname))
- def _expand_image_path(self, path):
+ def format_path(self, path):
orig_path = prev_path = path
while True:
try:
- path = path.format(**self.image_paths)
+ path = path.format(**self.all_paths)
except KeyError:
break
if path in (prev_path, orig_path):
diff --git a/sphinx/source/changelog.rst b/sphinx/source/changelog.rst
index 01182895..bb59688b 100644
--- a/sphinx/source/changelog.rst
+++ b/sphinx/source/changelog.rst
@@ -12,6 +12,8 @@ Changelog
* Added the ``Opcodes`` configuration parameter to
:ref:`sna2skool.py ` (for specifying additional opcode
sequences to disassemble)
+* Added support for path ID replacement fields in the ``destDir`` parameter of
+ items in the :ref:`resources` section
* Fixed the bug that prevents the ``--reg`` option of :ref:`trace.py` from
accepting hexadecimal values prefixed by '0x'
diff --git a/sphinx/source/ref-files.rst b/sphinx/source/ref-files.rst
index 4aae8aba..a06ceb0a 100644
--- a/sphinx/source/ref-files.rst
+++ b/sphinx/source/ref-files.rst
@@ -909,6 +909,10 @@ which are expanded as follows:
sequence of characters (e.g. ``abcde``) or a range (e.g. ``a-e``)
* ``[!seq]`` - matches any character not in ``seq``
+If ``destDir`` contains a path ID replacement field (e.g. ``{AudioPath}``), the
+corresponding parameter value from the :ref:`Paths` section will be
+substituted.
+
If your disassembly requires pre-built images or other resources that SkoolKit
does not build, listing them in this section ensures that they will be copied
into place whenever the disassembly is built.
@@ -916,6 +920,9 @@ into place whenever the disassembly is built.
+---------+-------------------------------------------------------------------+
| Version | Changes |
+=========+===================================================================+
+| 9.3 | Added support for path ID replacement fields in the ``destDir`` |
+| | parameter |
++---------+-------------------------------------------------------------------+
| 8.0 | Added support for the ``**`` pattern |
+---------+-------------------------------------------------------------------+
| 6.3 | Added support for pathname pattern expansion using wildcard |
diff --git a/tests/test_skool2html.py b/tests/test_skool2html.py
index 7b6b80fe..5488a720 100644
--- a/tests/test_skool2html.py
+++ b/tests/test_skool2html.py
@@ -800,6 +800,57 @@ def test_resources_are_copied(self):
self.assertTrue(os.path.isfile(os.path.join(game_dir, dest_dir, resource2)))
self.assertTrue(os.path.isfile(os.path.join(game_dir, dest_dir, resource3)))
+ @patch.object(skool2html, 'get_object', Mock(return_value=TestHtmlWriter))
+ @patch.object(skool2html, 'SkoolParser', MockSkoolParser)
+ def test_resources_using_path_id_replacement_fields(self):
+ resource_dir = self.make_directory()
+ self.write_bin_file(path=f'{resource_dir}/sound.wav')
+ self.write_bin_file(path=f'{resource_dir}/asm.html')
+ self.write_bin_file(path=f'{resource_dir}/font.png')
+ self.write_bin_file(path=f'{resource_dir}/font.ttf')
+ self.write_bin_file(path=f'{resource_dir}/logo.png')
+ self.write_bin_file(path=f'{resource_dir}/game.js')
+ self.write_bin_file(path=f'{resource_dir}/scr.png')
+ self.write_bin_file(path=f'{resource_dir}/style.css')
+ self.write_bin_file(path=f'{resource_dir}/udg.png')
+ ref = """
+ [Paths]
+ AudioPath=a
+ CodePath=b
+ FontImagePath=c
+ FontPath=d
+ ImagePath=e
+ JavaScriptPath=f
+ ScreenshotImagePath=g
+ StyleSheetPath=h
+ UDGImagePath=i
+
+ [Resources]
+ sound.wav={AudioPath}/1
+ asm.html={CodePath}/2
+ font.png={FontImagePath}/3
+ font.ttf={FontPath}/4
+ logo.png={ImagePath}/5
+ game.js={JavaScriptPath}/6
+ scr.png={ScreenshotImagePath}/7
+ style.css={StyleSheetPath}/8
+ udg.png={UDGImagePath}/9
+ """
+ reffile = self._write_ref_file(ref)
+ skoolfile = self.write_text_file(path='{}.skool'.format(reffile[:-4]))
+ output, error = self.run_skool2html('-d {} -S {} {}'.format(self.odir, resource_dir, skoolfile))
+ self.assertEqual(error, '')
+ game_dir = os.path.join(self.odir, reffile[:-4])
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'a', '1', 'sound.wav')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'b', '2', 'asm.html')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'c', '3', 'font.png')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'd', '4', 'font.ttf')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'e', '5', 'logo.png')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'f', '6', 'game.js')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'g', '7', 'scr.png')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'h', '8', 'style.css')))
+ self.assertTrue(os.path.isfile(os.path.join(game_dir, 'i', '9', 'udg.png')))
+
@patch.object(skool2html, 'get_object', Mock(return_value=TestHtmlWriter))
@patch.object(skool2html, 'SkoolParser', MockSkoolParser)
def test_resources_using_pathname_expansion(self):