diff --git a/tool/src/aurora_iconset_builder/__init__.py b/tool/src/aurora_iconset_builder/__init__.py index b727131..3f6ac32 100644 --- a/tool/src/aurora_iconset_builder/__init__.py +++ b/tool/src/aurora_iconset_builder/__init__.py @@ -10,18 +10,20 @@ from . import std_icons, nostd_icons def main() -> None: opts = parse() + def tempdir_initializer(p: Path) -> None: + # create our special temporary subdirectory + comp = p / "component" + comp.mkdir(parents=True, exist_ok=True) + repository_root = Path(__file__).resolve().parent.parent.parent.parent iconset_input = repository_root / "src" iconset_output = repository_root / "artifact" - prologue = AuroraPrologue(iconset_input, iconset_output, opts.svg_render) + prologue = AuroraPrologue( + iconset_input, iconset_output, opts.svg_render, tempdir_initializer + ) env = Environment(prologue) ctx = Context(env) - # TODO: use explicit temporary directory initializer in prologue to do this. - - # create our special temporary subdirectory - env.__temporary_artifact("component").mkdir(parents=True, exist_ok=True) - try: register(ctx) ctx.run(opts.selection) diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/context.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/context.py index a5bc3e6..a1e03aa 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/context.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/context.py @@ -184,7 +184,8 @@ class Context(Generic[P]): for item in ios: if not isinstance(item, (Source, Sink)): raise TypeError( - "passes source or sink instance must be the subclass of Source or Sink" + f"All items in the ios of job {name!r} must be instances " + f"of Source or Sink, but got {type(item)}." ) self.__jobs[name] = Job(name, cast(tuple[Source | Sink, ...], ios), executor) diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/fdart_sink.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/fdart_sink.py index 6c2441e..0306f7e 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/fdart_sink.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/fdart_sink.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from .common import Sink from ..address import Address, AddressDomain from ..environment import Environment -from ..utils import Artifact, FdContext, FD_THUMBNAIL_HWS +from ..utils import Artifact, FdContext, FD_THUMBNAIL_HWS, check_vart from ...lowlevel import artio, artrdr from ...logger import HIGHLEVEL_LOGGER as LOGGER @@ -31,6 +31,7 @@ class FdArtSink(Sink): self.__kind, self.__name, ) + check_vart(art) for hw, thumbnail in zip( FD_THUMBNAIL_HWS, artrdr.render_thumbnail(art, FD_THUMBNAIL_HWS) ): diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/macart_sink.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/macart_sink.py index 189dfb1..68950d1 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/macart_sink.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/macart_sink.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from .common import Sink from ..address import Address, AddressDomain from ..environment import Environment -from ..utils import Artifact, MacCategory +from ..utils import Artifact, MacCategory, check_vart from ...lowlevel import artrdr from ...logger import HIGHLEVEL_LOGGER as LOGGER @@ -31,7 +31,8 @@ class MacArtSink(Sink): self.__kind, self.__name, ) - artrdr.render_ico(art, env.mac_output_artifact(self.__kind, self.__name)) + check_vart(art) + artrdr.render_icns(art, env.mac_output_artifact(self.__kind, self.__name)) def push_hint(self) -> MacArtSinkHint: return MacArtSinkHint(self.__kind, self.__name) diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/winart_sink.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/winart_sink.py index 3b093be..4e879c4 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/winart_sink.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/sink/winart_sink.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from .common import Sink from ..address import Address, AddressDomain from ..environment import Environment -from ..utils import Artifact, WinCategory +from ..utils import Artifact, WinCategory, check_vart from ...lowlevel import artrdr from ...logger import HIGHLEVEL_LOGGER as LOGGER @@ -31,6 +31,7 @@ class WinArtSink(Sink): self.__kind, self.__name, ) + check_vart(art) artrdr.render_ico(art, env.win_output_artifact(self.__kind, self.__name)) def push_hint(self) -> WinArtSinkHint: diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/fdart_source.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/fdart_source.py index 49bc72c..8f1d8a4 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/fdart_source.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/fdart_source.py @@ -19,7 +19,7 @@ class FdArtSource(Source): def address(self) -> Address: return Address(AddressDomain.FdOutput, str(self.__kind), self.__name) - def pull_to_fd(self, env: Environment, fd_sink: FdArtSink) -> None: + def link_to(self, env: Environment, fd_sink: FdArtSink) -> None: sink_hint = fd_sink.push_hint() LOGGER.info( 'Duplicating FreeDesktop artifact from kind "%s" name "%s" to kind "%s" name "%s".', diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/macart_source.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/macart_source.py index eb68d5b..5c46879 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/macart_source.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/macart_source.py @@ -19,10 +19,10 @@ class MacArtSource(Source): def address(self) -> Address: return Address(AddressDomain.MacOutput, str(self.__kind), self.__name) - def pull_to_fd(self, env: Environment, mac_sink: MacArtSink) -> None: + def link_to(self, env: Environment, mac_sink: MacArtSink) -> None: sink_hint = mac_sink.push_hint() LOGGER.info( - 'Duplicating Macdows-only artifact from kind "%s" name "%s" to kind "%s" name "%s".', + 'Duplicating macOS-only artifact from kind "%s" name "%s" to kind "%s" name "%s".', sink_hint.kind, sink_hint.name, self.__kind, diff --git a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/winart_source.py b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/winart_source.py index 73e317e..fc25a74 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/winart_source.py +++ b/tool/src/aurora_iconset_builder/assemblicon/highlevel/source/winart_source.py @@ -19,7 +19,7 @@ class WinArtSource(Source): def address(self) -> Address: return Address(AddressDomain.WinOutput, str(self.__kind), self.__name) - def pull_to_fd(self, env: Environment, win_sink: WinArtSink) -> None: + def link_to(self, env: Environment, win_sink: WinArtSink) -> None: sink_hint = win_sink.push_hint() LOGGER.info( 'Duplicating Windows-only artifact from kind "%s" name "%s" to kind "%s" name "%s".', diff --git a/tool/src/aurora_iconset_builder/assemblicon/lowlevel/artio.py b/tool/src/aurora_iconset_builder/assemblicon/lowlevel/artio.py index d2c485a..6151960 100644 --- a/tool/src/aurora_iconset_builder/assemblicon/lowlevel/artio.py +++ b/tool/src/aurora_iconset_builder/assemblicon/lowlevel/artio.py @@ -124,8 +124,18 @@ def link_artifact(src: Path, dst: Path) -> None: f'No common directory between "{src}" and "{dst}", ' f"can not create relative symlink." ) + # SAFETY: the symlink target must always be stored with POSIX + # separators ("/"). On Windows, "relative_to" yields a + # backslash-separated path, and "symlink_to" stores the target string + # verbatim into the NTFS reparse point, so a backslash form would + # also leak verbatim into tar archives. Whether an unpacker accepts + # backslash targets is not guaranteed, and we deliberately do not + # rely on the packer normalizing them. Converting to POSIX form here + # is the single point guaranteeing that archived symlinks stay + # portable, regardless of the platform the build ran on or the + # packer used. try: - dst.symlink_to(link_target) + dst.symlink_to(link_target.as_posix()) except OSError as e: LOGGER.warning( "Fail to create symlink for artifact %s: %s. Falling back to copy.",