import os import requests import tempfile import importlib.util from blender.version import BlenderVersion # "Wayland Protocols" has no "Library" in its name but is still a # build-critical dependency, so it's matched by name too. _EXTRA_PACKAGE_NAMES = {'wayland protocols'} class BlenderDependency: def __init__(self, blender: BlenderVersion): self._blender_version = blender self._url = rf'https://projects.blender.org/api/v1/repos/blender/blender/raw/build_files/build_environment/install_linux_packages.py?ref=v{self._blender_version.tag_name()}' self.module = self._get_source_file() self.packages = list() self._get_list() self.packages_complete = list() self._get_complete_list() def _get_source_file(self): """Download the Blender dependency script and import it at runtime.""" r = requests.get(self._url) r.raise_for_status() with tempfile.NamedTemporaryFile(mode='wb', suffix='.py', delete=False) as t: t.write(r.content) path = t.name try: spec = importlib.util.spec_from_file_location('install_linux_packages', path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module finally: os.remove(path) def _get_list(self): """Keep the mandatory 'library' packages (and Wayland Protocols) as Debian/Ubuntu apt names.""" sources = self.module.BUILD_MANDATORY_SUBPACKAGES if hasattr(self.module, 'DEPS_CRITICAL_SUBPACKAGES'): sources += self.module.DEPS_CRITICAL_SUBPACKAGES for package in self._flatten(sources): if 'library' not in package.name.lower() and package.name.lower() not in _EXTRA_PACKAGE_NAMES: continue name = package.distro_package_names.get(self.module.DISTRO_ID_DEBIAN) if isinstance(name, str): self.packages.append(name) def _get_complete_list(self): """All packages required to build Blender (PACKAGES_BASICS_BUILD) as Debian/Ubuntu apt names.""" if hasattr(self.module, 'PACKAGES_BASICS_BUILD'): for package in self._flatten(self.module.PACKAGES_BASICS_BUILD): name = package.distro_package_names.get(self.module.DISTRO_ID_DEBIAN) if isinstance(name, str): self.packages_complete.append(name) def _flatten(self, packages): """Yield every leaf Package, descending into is_group sub_packages.""" for package in packages: if package.is_group: yield from self._flatten(package.sub_packages) else: yield package def __str__(self): return ' '.join(self.packages) def complete_str(self): return ' '.join(self.packages_complete) if __name__ == "__main__": bld = BlenderVersion(version='5.0.0') dep = BlenderDependency(blender=bld) print('Show All packages:') print(dep.__str__())