init new os-image-builder tool

This commit is contained in:
Alexander Stefanov 2024-11-13 11:48:35 +00:00
commit 723ed5ce4c
7 changed files with 221 additions and 0 deletions

0
bootstrap/README.md Normal file
View file

7
bootstrap/rosa13 Normal file
View file

@ -0,0 +1,7 @@
RELEASE="rosa13"
ABF_DOWNLOADS="https://abf-downloads.rosalinux.ru"
PKGS="basesystem-minimal locales-en dbus coreutils findutils util-linux xz e2fsprogs passwd openssh-server"
WEAK_DEPS="false"
DEFAULT_USER="rosa"
DEFAULT_USER_PASSWORD="rosa"
PASSWD_ROOT="root"

87
build.py Executable file
View file

@ -0,0 +1,87 @@
#!/usr/bin/env python
import os
import sys
import subprocess
import multiprocessing
from utils.bootstrap_setup import setup_bootstrap, load_config
BASE_DIR = os.getcwd()
TMP_DIR = os.path.join(BASE_DIR, "tmp")
NUM_CORES = str(multiprocessing.cpu_count())
def clone_repo(repo_url, branch, dest_dir, name):
if os.path.exists(dest_dir):
print(f"Warning: {name} directory '{dest_dir}' already exists. Skipping clone.")
else:
os.makedirs(dest_dir, exist_ok=True)
subprocess.run(["git", "clone", "--depth", "1", repo_url, "-b", branch, dest_dir], check=True)
def build_kernel(config, vendor, device):
kernel_dir = os.path.join(TMP_DIR, vendor, device, "kernel")
clone_repo(config["KERNEL"].split("#")[0], config["KERNEL"].split("#")[1], kernel_dir, "Kernel")
os.chdir(kernel_dir)
subprocess.run(["make", config["KERNEL_CONFIG"]], check=True)
subprocess.run(["make", config.get("KERNELTARGET", "Image"), "-j" + NUM_CORES], check=True)
os.chdir(BASE_DIR)
def build_uboot(config, vendor, device):
if "UBOOT" not in config or "UBOOT_VERSION" not in config:
print("U-Boot configuration not found. Skipping U-Boot build.")
return
uboot_dir = os.path.join(TMP_DIR, vendor, device, "u-boot")
clone_repo(config["UBOOT"], config["UBOOT_VERSION"], uboot_dir, "U-Boot")
os.chdir(uboot_dir)
subprocess.run(["make", config["UBOOT_CONFIG"]], check=True)
subprocess.run(["make", "-j" + NUM_CORES], check=True)
os.chdir(BASE_DIR)
def main():
if len(sys.argv) < 3 or "--distro" not in sys.argv:
print("Usage: python build.py --distro <distro_name> <vendor/device> [--skip-kernel] [--skip-uboot]")
sys.exit(1)
distro_idx = sys.argv.index("--distro") + 1
distro = sys.argv[distro_idx]
vendor_device = sys.argv[distro_idx + 1]
vendor, device = vendor_device.split("/")
config_path = os.path.join("device", vendor, device, "config")
skip_kernel = "--skip-kernel" in sys.argv
skip_uboot = "--skip-uboot" in sys.argv
if not os.path.exists(config_path):
print(f"Configuration file for {vendor}/{device} not found.")
sys.exit(1)
config = load_config(config_path)
if config["ARCH"] != "aarch64":
print("Unsupported architecture.")
sys.exit(1)
print(f"Building for {vendor}/{device} with distro {distro}...")
if not skip_kernel:
build_kernel(config, vendor, device)
else:
print("Skipping kernel build.")
if not skip_uboot:
build_uboot(config, vendor, device)
else:
print("Skipping U-Boot build.")
setup_bootstrap("bootstrap", TMP_DIR, vendor, device, distro)
print(f"Build completed for {vendor}/{device} with distro {distro}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,7 @@
ARCH="aarch64"
KERNEL="https://github.com/raspberrypi/linux.git#rpi-6.6.y"
KERNEL_CONFIG="bcm2711_defconfig"
KERNEL_EXTRACONFIG="--module NTFS3_FS --enable NTFS3_LZX_XPRESS --enable NTFS3_FS_POSIX_ACL --disable NTFS3_64BIT_CLUSTER"
DTB="broadcom/bcm2711-rpi-4-b"
CMDLINE="dwc_otg.lpm_enable=0 console=ttyS0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait"
NEED_INITRD=no

View file

@ -0,0 +1,25 @@
# See
# https://www.raspberrypi.org/documentation/configuration/config-txt
arm_64bit=1
kernel=kernel8.img
dtoverlay=vc4-kms-v3d-pi4
# Force the monitor to HDMI mode so that sound will be sent over HDMI cable
hdmi_drive=2
# Force monitor mode to DMT
hdmi_group=2
# Force monitor resolution (e.g. 16 = 1920x1080)
#hdmi_mode=16
# Some displays might have issues with text/pixels spilling off the screen.
# If this affects you, uncomment the overscan_* settings and adjust the values
#overscan_left=20
#overscan_right=12
#overscan_top=10
#overscan_bottom=10
# For i2c & spi
dtparam=i2c_arm=on
dtparam=spi=on
# Memory reserved for the GPU (in MB)
mem_gpu=256
# Enable audio (loads snd_bcm2835)
dtparam=audio=on

Binary file not shown.

95
utils/bootstrap_setup.py Normal file
View file

@ -0,0 +1,95 @@
import os
import sys
import subprocess
def load_config(config_path):
config = {}
with open(config_path, "r") as f:
for line in f:
if "=" in line and not line.strip().startswith("#"):
key, value = line.strip().split("=", 1)
config[key] = value.strip('"')
return config
def load_bootstrap_config(bootstrap_path):
"""Load the bootstrap configuration from the specified file."""
config = {}
with open(bootstrap_path, "r") as f:
for line in f:
if "=" in line and not line.strip().startswith("#"):
key, value = line.strip().split("=", 1)
config[key] = value.strip('"')
return config
def generate_dnf_conf(dnf_conf_path, abf_downloads, release):
"""Generate dnf.conf based on the bootstrap configuration."""
dnf_conf_content = f"""
[main]
keepcache=1
debuglevel=2
reposdir=/dev/null
retries=20
obsoletes=1
gpgcheck=0
assumeyes=1
syslog_ident=mock
syslog_device=
install_weak_deps=0
metadata_expire=60s
best=1
[{release}_main_release]
name={release}_main_release
baseurl={abf_downloads}/{release}/repository/aarch64/main/release
gpgcheck=0
enabled=1
[{release}_main_updates]
name={release}_main_updates
baseurl={abf_downloads}/{release}/repository/aarch64/main/updates
gpgcheck=0
enabled=1
"""
os.makedirs(os.path.dirname(dnf_conf_path), exist_ok=True)
with open(dnf_conf_path, "w") as f:
f.write(dnf_conf_content)
def run_dnf_install(config, dnf_conf_path, rootfs_dir):
"""Run dnf command to install packages based on the bootstrap configuration."""
pkgs = config["PKGS"]
weak_deps = config["WEAK_DEPS"].lower()
dnf_command = [
"sudo",
"dnf",
"--setopt=install_weak_deps=" + str(weak_deps),
"--config", dnf_conf_path,
"--installroot", rootfs_dir,
"install"
] + pkgs.split()
subprocess.run(dnf_command, check=True)
def setup_bootstrap(bootstrap_dir, tmp_dir, vendor, device, distro):
# load distro config
# bootstrap/DISTRO_NAME
distro_config_path = os.path.join(bootstrap_dir, distro)
if not os.path.exists(distro_config_path):
print(f"Bootstrap configuration for distro '{distro}' not found.")
sys.exit(1)
config = load_config(distro_config_path)
dnf_conf_path = os.path.join(tmp_dir, vendor, device, "dnf.conf")
rootfs_dir = os.path.join(tmp_dir, vendor, device, "rootfs")
generate_dnf_conf(dnf_conf_path, config["ABF_DOWNLOADS"], config["RELEASE"])
run_dnf_install(config, dnf_conf_path, rootfs_dir)
#setup_user(rootfs_dir, config["DEFAULT_USER"], config["DEFAULT_USER_PASSWORD"], config["PASSWD_ROOT"])