Source code for autofmu.utils

"""General utilities."""

import re
import shutil
import subprocess
import unicodedata
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Any, Mapping, Optional
from zipfile import ZipFile


[docs]def slugify(value: Any, allow_unicode: bool = False) -> str: """Convert a string to a URL slug. Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated dashes to single dashes. Remove characters that aren't alphanumerics, underscores, or hyphens. Convert to lowercase. Also strip leading and trailing whitespace, dashes, and underscores. See: https://docs.djangoproject.com/en/3.1/ref/utils/#django.utils.text.slugify """ value = str(value) if allow_unicode: value = unicodedata.normalize("NFKC", value) else: value = ( unicodedata.normalize("NFKD", value) .encode("ascii", "ignore") .decode("ascii") ) value = re.sub(r"[^\w\s-]", "", value.lower()) return re.sub(r"[-\s]+", "-", value).strip("-_")
[docs]def run_cmake( source_dir: Path, build_dir: Path, variables: Optional[Mapping[str, str]] = None, ) -> None: """Run cmake command and build the targets. Roughly equivalent to running the following two commands: .. code-block:: shell cmake -S source_dir -B build_dir cmake --build build_dir Arguments: source_dir: path to source directory build_dir: path to build directory variables: a mapping between variable names and their values, e.g, ``{"CMAKE_PROJECT_NAME": "Unicorn"}`` would be passed as ``DCMAKE_PROJECT_NAME=Unicorn`` in the command line """ cmake = shutil.which("cmake") or "cmake" if variables: args = [f"-D{name}={value}" for name, value in variables.items()] else: args = [] subprocess.run( [cmake, *args, "-S", source_dir, "-B", build_dir], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) subprocess.run( [cmake, "--build", build_dir], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, )
[docs]def compile_fmu(model_identifier: str, fmu_path: Path) -> None: """Compile the C sources files of an FMU. Extracts the FMU into a temporary directory, calling cmake to build the FMU, copying the generated library back into the FMU file. If `MinGW <http://www.mingw.org/>`_ is installed, it also cross compiles the FMU for Linux and Windows. Arguments: model_identifier: short class name according to C syntax, for example, "A_B_C" fmu_path: path to the FMU file """ with ZipFile(fmu_path, "a") as fmu, TemporaryDirectory() as tmpdir: fmu.extractall(tmpdir) # Use CMake to compile the FMU for the current platform shutil.copy(Path(__file__).parent / "cmake" / "CMakeLists.txt", tmpdir) build_dir = Path(tmpdir) / "build" run_cmake(Path(tmpdir), build_dir, {"CMAKE_PROJECT_NAME": model_identifier}) # Cross compile compilers = ( ("i686-linux-gnu-gcc", "Linux"), ("x86_64-linux-gnu-gcc", "Linux"), ("i686-w64-mingw32-gcc", "Windows"), ("x86_64-w64-mingw32-gcc", "Windows"), ) for compiler, system in compilers: run_cmake( Path(tmpdir), build_dir / compiler, { "CMAKE_PROJECT_NAME": model_identifier, "CMAKE_SYSTEM_NAME": system, "CMAKE_C_COMPILER": compiler, }, ) for lib in Path(tmpdir).glob("binaries/**/*"): fmu.write(lib, lib.relative_to(tmpdir))