aboutsummaryrefslogtreecommitdiff
path: root/svg-flatten/svg_flatten_wasi
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-09-26 15:45:09 +0200
committerjaseg <git@jaseg.de>2021-09-29 16:38:13 +0200
commit8a64621e8c8610a45884df82b46859bc3297d3e3 (patch)
tree4b6265bb01377e16e66dddeee8259f40ea86d562 /svg-flatten/svg_flatten_wasi
parent7eb0b9d7e42a20b85bd7afbfe3d33d9dd5fa5794 (diff)
downloadgerbolyze-8a64621e8c8610a45884df82b46859bc3297d3e3.tar.gz
gerbolyze-8a64621e8c8610a45884df82b46859bc3297d3e3.tar.bz2
gerbolyze-8a64621e8c8610a45884df82b46859bc3297d3e3.zip
CI/svg-flatten: add wasm builds
Diffstat (limited to 'svg-flatten/svg_flatten_wasi')
-rw-r--r--svg-flatten/svg_flatten_wasi/__init__.py82
1 files changed, 82 insertions, 0 deletions
diff --git a/svg-flatten/svg_flatten_wasi/__init__.py b/svg-flatten/svg_flatten_wasi/__init__.py
new file mode 100644
index 0000000..fe21b5b
--- /dev/null
+++ b/svg-flatten/svg_flatten_wasi/__init__.py
@@ -0,0 +1,82 @@
+import os
+import sys
+import tempfile
+import wasmtime
+import platform
+import click
+import pathlib
+import hashlib
+import appdirs
+import lzma
+from importlib import resources as importlib_resources
+try:
+ importlib_resources.files # py3.9+ stdlib
+except AttributeError:
+ import importlib_resources # py3.8- shim
+
+
+# ==============================
+# Note on wasmtime path handling
+# ==============================
+#
+# Hack: Right now, wasmtime's preopen_dir / --map functionality is completely borked. AFAICT only the first mapping is
+# even considered, and preopening both / and . simply does not work: Either all paths open'ed by the executable must be
+# absolute, or all paths must be relative. I spent some hours trying to track down where exactly this borkage originates
+# from, but I found the code confusing and did not succeed.
+#
+# FOR NOW we work around this issue the dumb way: We simply have click parse enough of the command line to transform any
+# paths given on the command line to absolute paths. The actual path resolution is done by click because of
+# resolve_path=True.
+#
+
+
+def _run_wasm_app(wasm_filename, argv, cachedir="svg-flatten-wasi"):
+
+ module_binary = importlib_resources.read_binary(__package__, wasm_filename)
+
+ module_path_digest = hashlib.sha256(__file__.encode()).hexdigest()
+ module_digest = hashlib.sha256(module_binary).hexdigest()
+ cache_path = pathlib.Path(os.getenv("SVG_FLATTEN_WASI_CACHE_DIR", appdirs.user_cache_dir(cachedir)))
+ cache_path.mkdir(parents=True, exist_ok=True)
+ cache_filename = (cache_path / f'{wasm_filename}-{module_path_digest[:8]}-{module_digest[:16]}')
+
+ wasi_cfg = wasmtime.WasiConfig()
+ wasi_cfg.argv = argv
+ wasi_cfg.preopen_dir('/', '/')
+ wasi_cfg.inherit_stdin()
+ wasi_cfg.inherit_stdout()
+ wasi_cfg.inherit_stderr()
+ engine = wasmtime.Engine()
+
+ import time
+ try:
+ with cache_filename.open("rb") as cache_file:
+ module = wasmtime.Module.deserialize(engine, lzma.decompress(cache_file.read()))
+ except:
+ print("Preparing to run {}. This might take a while...".format(argv[0]), file=sys.stderr)
+ module = wasmtime.Module(engine, module_binary)
+ with cache_filename.open("wb") as cache_file:
+ cache_file.write(lzma.compress(module.serialize(), preset=0))
+
+ linker = wasmtime.Linker(engine)
+ linker.define_wasi()
+ store = wasmtime.Store(engine)
+ store.set_wasi(wasi_cfg)
+ app = linker.instantiate(store, module)
+ linker.define_instance(store, "app", app)
+
+ try:
+ app.exports(store)["_start"](store)
+ return 0
+ except wasmtime.ExitTrap as trap:
+ return trap.code
+
+
+@click.command(context_settings={'ignore_unknown_options': True})
+@click.argument('other_args', nargs=-1, type=click.UNPROCESSED)
+@click.argument('input_file', type=click.Path(resolve_path=True, dir_okay=False))
+@click.argument('output_file', type=click.Path(resolve_path=True, dir_okay=False, writable=True))
+def run_usvg(input_file, output_file, other_args):
+
+ cmdline = ['svg-flatten', *other_args, input_file, output_file]
+ sys.exit(_run_wasm_app("svg-flatten.wasm", cmdline))