from dataclasses import dataclass
from pathlib import Path
from typing import Optional, Any
from wasmer import Instance, Module, Store, wasi # type: ignore
@dataclass
class ExitStatus:
"""The status code returned when the executable finished."""
code: int
@property
def success(self):
return self.code == 0
class Commands:
"""
Run the various WASI executables in this package.
"""
def __init__(self, store: Store):
self._store = store
self._cache: dict[str, Module] = {}
def _get_module(self, filename: str) -> Module:
if filename in self._cache:
return self._cache[filename]
wasm = Path(__file__).parent.joinpath(filename).read_bytes()
module = Module(self._store, wasm)
self._cache[filename] = module
return module
{% for cmd in commands %}
def {{cmd.ident}}(
self,
env: wasi.Environment,
imports: Optional[dict[str, Any]] = None,
module: Optional[Module] = None,
) -> ExitStatus:
"""
Run the "{{cmd.ident}}" command.
:param wasi: A pre-initialized WASI environment. If not specified, a
default value will be used.
:param imports: Additional imports to be provided to the WebAssembly
module.
:param module: A user-specified WebAssembly module to use instead of the
one bundled with this package.
"""
if not module:
module = self._get_module("{{cmd.module_filename}}")
version = wasi.get_version(module, strict=True)
assert version is not None, 'The WebAssembly module is not a valid WASI executable'
if not imports:
imports = {}
wasi_imports = env.generate_import_object(self._store, version)
imports.update(wasi_imports.to_dict())
instance = Instance(module, imports)
code = instance.exports._start()
return ExitStatus(code=code or 0)
{% endfor %}