Files
euri-mklive/euri_mklive/iso.py
T
c-ludenberg 3c5a357cb4 euri-mklive: universal CLI ISO builder
- any distro from any distro (debian, ubuntu, arch, artix, void, alpine, fedora)
- YAML config for distro, arch, init, packages, users, services, bootloader
- each distro backend knows how to bootstrap itself
- squashfs + xorriso for ISO generation
- sexy CLI with banner and colored output
- examples for Artix+Euri and Project Horizon
2026-08-26 19:01:19 +02:00

84 lines
2.6 KiB
Python

"""ISO generator — squashes rootfs and creates bootable ISO."""
from __future__ import annotations
import subprocess
import tempfile
from pathlib import Path
def generate(rootfs: Path, config: dict, output: Path) -> Path:
"""Generate a bootable ISO from a rootfs."""
iso_cfg = config.get("iso", {})
label = iso_cfg.get("label", "EURI")
name = iso_cfg.get("name", "Euri Linux")
version = iso_cfg.get("version", "1.0")
print(f"\n\033[1;36m==>\033[0m \033[1mGenerating ISO: {name} {version}\033[0m")
workdir = Path(tempfile.mkdtemp(prefix="mklive-iso-"))
iso_dir = workdir / "iso"
iso_dir.mkdir()
# copy rootfs into ISO staging
_run(["cp", "-a", str(rootfs) + "/.", str(iso_dir)])
# squashfs
squash = workdir / "filesystem.squashfs"
print(f"\033[1;36m==>\033[0m \033[1mCreating squashfs image...\033[0m")
_run(["mksquashfs", str(iso_dir), str(squash), "-comp", "xz", "-b", "1M"])
# create ISO layout
live_dir = iso_dir / "boot" / "x86_64"
live_dir.mkdir(parents=True, exist_ok=True)
_run(["cp", str(squash), str(live_dir / "filesystem.squashfs")])
# EFI boot
efi_dir = iso_dir / "EFI" / "BOOT"
efi_dir.mkdir(parents=True, exist_ok=True)
_run(["cp", "/usr/lib/grub/x86_64-efi/monolithic/grubx64.efi", str(efi_dir / "BOOTX64.EFI")])
# GRUB config
grub_cfg = iso_dir / "boot" / "grub" / "grub.cfg"
grub_cfg.parent.mkdir(parents=True, exist_ok=True)
grub_cfg.write_text(f"""
set timeout=10
set default=0
menuentry "{name}" {{
linux /boot/x86_64/vmlinuz boot=live components
initrd /boot/x86_64/initrd
}}
menuentry "{name} (copy to RAM)" {{
linux /boot/x86_64/vmlinuz boot=live components toram
initrd /boot/x86_64/initrd
}}
""")
# xorriso to create ISO
iso_path = output / f"{name.lower().replace(' ', '-')}-{version}-x86_64.iso"
print(f"\033[1;36m==>\033[0m \033[1mCreating ISO: {iso_path.name}\033[0m")
_run([
"xorriso", "-as", "mkisofs",
"-V", label,
"-o", str(iso_path),
"-J", "-joliet-long",
"-b", "boot/x86_64/filesystem.squashfs",
"-no-emul-boot", "-boot-load-size", "4",
"-boot-info-table",
"-eltorito-alt-boot",
"-e", "boot/x86_64/filesystem.squashfs",
"-no-emul-boot",
str(iso_dir),
])
size_mb = iso_path.stat().st_size / (1024 * 1024)
print(f"\n\033[1;32m==>\033[0m \033[1mISO ready: {iso_path} ({size_mb:.1f} MB)\033[0m")
return iso_path
def _run(cmd: list[str], **kw) -> subprocess.CompletedProcess:
print(f" \033[90m$\033[0m \033[1m{' '.join(cmd)}\033[0m")
return subprocess.run(cmd, check=True, **kw)