From aea7614acfdb8b9e812d395208ba45a9967506e3 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 25 May 2026 16:51:03 +1000 Subject: [PATCH 1/8] Tweak imports and minor formatting fix --- fablib/annotate.py | 6 ++++-- fablib/installer.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fablib/annotate.py b/fablib/annotate.py index 74ec89e..93eb637 100644 --- a/fablib/annotate.py +++ b/fablib/annotate.py @@ -4,7 +4,7 @@ from re import Match from tempfile import TemporaryDirectory -from debian import deb822 +from debian import debfile def parse_plan(plan: str) -> set[str]: @@ -54,7 +54,9 @@ def plan_lint(plan_path: str, pool_path: str) -> str: plan = fob.read().strip() packages = parse_plan(plan) - packages_info: dict[str, str] = get_packages_info(list(packages), pool_path) + packages_info: dict[str, str] = get_packages_info( + list(packages), pool_path, + ) if not packages: column_len = 0 diff --git a/fablib/installer.py b/fablib/installer.py index e0041db..d1c3743 100644 --- a/fablib/installer.py +++ b/fablib/installer.py @@ -16,7 +16,7 @@ from typing import TextIO, cast from chroot import Chroot -from debian import deb822, debfile +from debian import debfile from fablib import common From 2e1f168f03fb895a7b57d4f491dd19fad7267fd1 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 25 May 2026 16:51:27 +1000 Subject: [PATCH 2/8] Make pool a hard depends (it's required by fab) --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index b4273a2..8082a3a 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,6 @@ Depends: python3-debian, xorriso, squashfs-tools, -Recommends: pool, Suggests: dd, From c40b69d7bd1bdf0e50d37d500c55007cfd6fae37 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Thu, 28 May 2026 15:26:03 +1000 Subject: [PATCH 3/8] Cleanup some docstrings, remove redundant use of 'os.path' prefix & extra debugging --- fablib/installer.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/fablib/installer.py b/fablib/installer.py index d1c3743..49e75d8 100644 --- a/fablib/installer.py +++ b/fablib/installer.py @@ -28,8 +28,10 @@ class Error(Exception): class RevertibleFile: - """File that automatically reverts to previous state on destruction - or if the revert method is invoked""" + """File that automatically reverts to previous state. + + Reverts on destruction or if the revert method is invoked. + """ @staticmethod def _get_orig_path(path: str) -> str: @@ -51,7 +53,7 @@ def __init__(self, path: str) -> None: self._inner = open(path, "w") def revert(self) -> None: - """revert file to original state""" + """Revert file to original state.""" if self.orig_path is not None: assert self.path is not None shutil.move(self.orig_path, self.path) @@ -73,7 +75,7 @@ def __del__(self) -> None: class RevertibleScript(RevertibleFile): - """RevertibleFile that ensures file is executable""" + """RevertibleFile that ensures file is executable.""" def __init__(self, path: str, lines: Iterable[str]) -> None: super().__init__(path) @@ -103,8 +105,10 @@ def __init__( def _get_packages_priority( packages: list[str], ) -> tuple[list[str], list[str]]: - """high priority packages must be installed before regular packages - APT should handle this, but in some circumstances it chokes... + """Sort list of packages into 2 lists of high & regular priority. + + High priority packages must be installed before regular packages, APT + should handle this, but in some circumstances it chokes... """ HIGH_PRIORITY = "linux-image" @@ -256,6 +260,9 @@ def install( class PoolInstaller(Installer): + + _class = "PoolInstaller" + def __init__( self, chroot_path: str, @@ -263,6 +270,12 @@ def __init__( arch: str, environ: dict[str, str] | None = None, ) -> None: + + logging.debug( + f"{self._class}(\n {chroot_path=},\n {pool_path=},\n {arch=}," + f" {environ=}\n)", + ) + super().__init__(chroot_path, environ) from pool_lib import Pool @@ -287,10 +300,10 @@ def sha256sum(path: str) -> str: index = [] for package in os.listdir(packagedir): - path = os.path.join(packagedir, package) + path = join(packagedir, package) # dl_path would best be calculated; but we don't # have access to chroot_path here... - dl_path = os.path.join("var/cache/apt/archives", package) + dl_path = join("var/cache/apt/archives", package) if path.endswith(".deb"): control = debfile.DebFile(path).debcontrol() for field in list(control.keys()): @@ -307,15 +320,16 @@ def sha256sum(path: str) -> str: def install( self, packages: list[str], ignore_errors: list[str] | None = None ) -> None: - """install packages into chroot via pool""" + """Install packages into chroot via pool.""" if ignore_errors is None: ignore_errors = [] + logging.debug(f"{self._class}.install({packages=}, {ignore_errors=})") + print("getting packages...") packagedir = join(self.chroot.path, "var/cache/apt/archives") logger.debug(f"{packagedir=}") - logger.debug(f"{packages=}") self.pool.get(packagedir, packages, strict=True) print("generating package index...") @@ -353,7 +367,7 @@ def __init__( def install( self, packages: list[str], ignore_errors: list[str] | None = None ) -> None: - """install packages into chroot via live apt""" + """Install packages into chroot via live apt.""" if ignore_errors is None: ignore_errors = [] From 829d9276ba6bcb7bf0dafbb8e6a5a6c2e8cc3264 Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Thu, 28 May 2026 15:43:09 +1000 Subject: [PATCH 4/8] Add SHA512 checksums to generated control file --- fablib/installer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fablib/installer.py b/fablib/installer.py index 49e75d8..245d4b2 100644 --- a/fablib/installer.py +++ b/fablib/installer.py @@ -298,6 +298,10 @@ def sha256sum(path: str) -> str: with open(path, "rb") as fob: return str(hashlib.sha256(fob.read()).hexdigest()) + def sha512sum(path: str) -> str: + with open(path, "rb") as fob: + return str(hashlib.sha512(fob.read()).hexdigest()) + index = [] for package in os.listdir(packagedir): path = join(packagedir, package) @@ -313,6 +317,7 @@ def sha256sum(path: str) -> str: index.append("Size: " + filesize(path)) index.append("MD5sum: " + md5sum(path)) index.append("SHA256: " + sha256sum(path)) + index.append("SHA512: " + sha512sum(path)) index.append("") return index From 29f52f0f996da1608160ebd27c005445ff02181e Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Thu, 28 May 2026 15:59:54 +1000 Subject: [PATCH 5/8] Packaging tweaks/updates --- debian/compat | 1 - debian/control | 12 ++++++++---- debian/copyright | 2 +- debian/{install => fab.install} | 0 4 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 debian/compat rename debian/{install => fab.install} (100%) diff --git a/debian/compat b/debian/compat deleted file mode 100644 index f599e28..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -10 diff --git a/debian/control b/debian/control index 8082a3a..695dbaf 100644 --- a/debian/control +++ b/debian/control @@ -3,11 +3,15 @@ Section: misc Priority: optional Maintainer: Stefan Davis Build-Depends: - debhelper (>= 10), - python3-all (>= 3.7~), + debhelper-compat (= 13), + python3 (>= 3.13), + pybuild-plugin-pyproject, + dh-python, python3-debian, - dh-python -Standards-Version: 4.0.0 +Standards-Version: 4.7.2 +Vcs-Git: https://github.com/turnkeylinux/fab.git +Vcs-Browser: https://github.com/turnkeylinux/fab +Rules-Requires-Root: no Package: fab Architecture: all diff --git a/debian/copyright b/debian/copyright index 3cdc320..5159429 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,5 +1,5 @@ Copyright (c) 2011-2014 TurnKey GNU/Linux - https://www.turnkeylinux.org -Copyright (c) 2020-2021 TurnKey GNU/Linux - https://www.turnkeylinux.org +Copyright (c) 2020-2026 TurnKey GNU/Linux - https://www.turnkeylinux.org Fab is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the diff --git a/debian/install b/debian/fab.install similarity index 100% rename from debian/install rename to debian/fab.install From 68be42f35148239531915b3e7125ad3b20673b1c Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 1 Jun 2026 16:24:08 +1000 Subject: [PATCH 6/8] product.mk: add some indents for readability and make sure that mounts are unmounted --- share/product.mk | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/share/product.mk b/share/product.mk index b760843..ee32bd5 100755 --- a/share/product.mk +++ b/share/product.mk @@ -34,10 +34,10 @@ FAB_INSTALL_ENV = $(FAB_CHROOT_ENV) FAB_SHARE_PATH ?= /usr/share/fab BOOTSTRAP ?= $(FAB_PATH)/bootstraps/$(CODENAME)-$(FAB_ARCH) ifneq ("$(wildcard $(FAB_PATH)/altstraps/$(CODENAME)-$(FAB_ARCH).core)", "") -BOOTSTRAP := $(FAB_PATH)/altstraps/$(CODENAME)-$(FAB_ARCH).core + BOOTSTRAP := $(FAB_PATH)/altstraps/$(CODENAME)-$(FAB_ARCH).core endif ifeq (,"$(wildcard $(BOOTSTRAP)")) -$(error bootstrap $(BOOTSTRAP) not found - download or build it first) + $(error bootstrap $(BOOTSTRAP) not found - download or build it first) endif CDROOTS_PATH ?= $(FAB_PATH)/cdroots @@ -49,9 +49,9 @@ MKSQUASHFS_OPTS ?= -no-sparse # we set _CDROOT with eval to improve the readability of $(value _CDROOT) # in help target ifeq ($(shell echo $(CDROOT) | grep ^/), ) -$(eval _CDROOT = $$(CDROOTS_PATH)/$(CDROOT)) + $(eval _CDROOT = $$(CDROOTS_PATH)/$(CDROOT)) else -$(eval _CDROOT = $(CDROOT)) + $(eval _CDROOT = $(CDROOT)) endif COMMON_OVERLAYS_PATH ?= $(FAB_PATH)/common/overlays @@ -80,7 +80,7 @@ CDROOT_OVERLAY ?= cdroot.overlay REMOVELIST ?= removelist # unset REMOVELIST if the file doesn't exist ifeq ($(wildcard $(REMOVELIST)),) -REMOVELIST = + REMOVELIST = endif UNIT_DIRS ?= unit.d @@ -103,19 +103,22 @@ define remove-deck exit 1; \ fi; \ fuser -k $1; \ + for m in run dev/pts dev proc sys; do \ + umount "$1/$m" || true ; \ + done ; \ echo deck -D $1; \ deck -D $1; \ fi endef ifdef CHROOT_ONLY -all: root.sandbox + all: root.sandbox else -ifeq ($(FAB_ARCH_FAMILY),arm) -all: root.sandbox -else -all: $O/product.iso -endif + ifeq ($(FAB_ARCH_FAMILY),arm) + all: root.sandbox + else + all: $O/product.iso + endif endif define mount-deck @@ -222,7 +225,7 @@ define help/body endef ifndef CHROOT_ONLY -help/body += ;\ + help/body += ;\ echo ' cdroot \# created by squashing root.patched into cdroot template + overlay'; \ echo ' product.iso \# product ISO created from the cdroot'; \ echo; \ From a314d8143264036aa53b465020cb1ba313f1f9ac Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 1 Jun 2026 16:35:44 +1000 Subject: [PATCH 7/8] Bugfix check for BOOTSTRAP - misplaced quotes caused check to always pass --- share/product.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/product.mk b/share/product.mk index ee32bd5..acd576e 100755 --- a/share/product.mk +++ b/share/product.mk @@ -36,7 +36,7 @@ BOOTSTRAP ?= $(FAB_PATH)/bootstraps/$(CODENAME)-$(FAB_ARCH) ifneq ("$(wildcard $(FAB_PATH)/altstraps/$(CODENAME)-$(FAB_ARCH).core)", "") BOOTSTRAP := $(FAB_PATH)/altstraps/$(CODENAME)-$(FAB_ARCH).core endif -ifeq (,"$(wildcard $(BOOTSTRAP)")) +ifeq (,$(wildcard $(BOOTSTRAP))) $(error bootstrap $(BOOTSTRAP) not found - download or build it first) endif From 46e65c4650b40e155d0fdf8a00f8d5d7b45a127d Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 1 Jun 2026 17:22:43 +1000 Subject: [PATCH 8/8] Check for root on overlayfs - fix unhelpful error message when running tkldev live --- share/product.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/share/product.mk b/share/product.mk index acd576e..555c0bc 100755 --- a/share/product.mk +++ b/share/product.mk @@ -13,6 +13,14 @@ $(shell /usr/share/fab/load_env) include /tmp/.build_env +# check if root is overlayfs and warn user +IS_OVERLAY := $(shell [ "$$(findmnt -n -o FSTYPE /)" = "overlay" ] && echo yes) +ifeq ($(IS_OVERLAY),yes) + FREE_RAM := $(shell free -mh | awk '/^Mem:/ {print $$4}') + $(info '/' is overlayfs. Build will fail unless "proper" filesystem is mounted) + $(info [free RAM: $(FREE_RAM)]) +endif + COMMON_PATCHES := turnkey.d $(COMMON_PATCHES) CONF_VARS_BUILTIN ?= FAB_ARCH HOST_ARCH FAB_HTTP_PROXY AMD64 ARM64 RELEASE DISTRO CODENAME DEBIAN UBUNTU KERNEL DEBUG CHROOT_ONLY DI_LIVE_DEBUG