Skip to content

Commit 5d1f840

Browse files
rootfs: add local-debs flow; kernel deb optional
Context - The script previously required --kernel-package, which blocked valid flows where kernels are provided by apt sources or installed later via overlay manifests. - Local .deb injection relied on direct package install assumptions and did not provide a first-class dependency-resolving ingestion path. Implementation - Relax the required CLI contract: - keep --product-conf and --seed mandatory, - make --kernel-package optional with conditional validation, copy, and install behavior. - Introduce a repeatable --local-debs <path> input: - accepts file or directory paths, - validates each path preflight, - stages all discovered debs into /opt/local-debs in the rootfs. - Inside the chroot, create a temporary local apt repository from the staged debs: - dpkg-scanpackages index generation, - file:///opt/local-debs source registration, - package-name extraction from deb metadata, - apt-driven installation to resolve inter-package dependencies. Why an apt-backed local repo - `dpkg -i` alone is non-closure-preserving for dependency graphs. - A local apt repository allows the resolver to satisfy dependency chains across the provided package set in deterministic order. Operational behavior - If no --local-debs are provided, local-repo stages are true no-ops. - If directories are provided but empty, execution remains stable (no hard failure). Scope - Packaging ingress expansion and input-contract modernization; the bootloader sequencing change lands in a subsequent commit. Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
1 parent 992bb78 commit 5d1f840

1 file changed

Lines changed: 88 additions & 10 deletions

File tree

rootfs/scripts/build-rootfs.sh

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
# - Supports JSON package manifest for additional package installation
1818
# (via apt or local .deb) inside the rootfs.
1919
# - Supports injecting custom apt sources from the package manifest.
20-
# - Injects custom kernel and firmware .deb packages.
20+
# - Optionally injects custom kernel and firmware .deb packages.
21+
# - Supports installing local .deb packages (--local-debs) with full dependency resolution
22+
# via a temporary local APT repository built inside the rootfs.
2123
# - Installs user-specified packages from seed and/or overlay manifest.
2224
# - Dynamically deduces and generates base and custom package manifests.
2325
# - Configures GRUB bootloader, hostname, DNS, and other system settings.
@@ -27,18 +29,28 @@
2729
# ./build-rootfs.sh \
2830
# --product-conf qcom-product.conf \
2931
# --seed seed_file \
30-
# --kernel-package kernel.deb \
32+
# [--kernel-package kernel.deb] \
3133
# [--firmware firmware.deb] \
3234
# [--overlay package-manifest.json] \
33-
# [--variant desktop]
35+
# [--variant desktop] \
36+
# [--local-debs pkg-a.deb] \
37+
# [--local-debs debs/]
3438
#
3539
# ARGUMENTS:
3640
# --product-conf <qcom-product.conf> Required. Product configuration file.
3741
# --seed <seed_file> Required. Seed file: one package per line (# comments allowed).
38-
# --kernel-package <kernel.deb> Required. Custom kernel package.
42+
# --kernel-package <kernel.deb> Optional. Custom kernel package.
3943
# --firmware <firmware.deb> Optional. Custom firmware package.
4044
# --overlay <package-manifest.json> Optional. JSON manifest specifying extra packages/apt sources.
4145
# --variant <variant_name> Optional. System variant (default: desktop).
46+
# --local-debs <path> Optional. A .deb file OR a directory of .deb files to install
47+
# via a local APT repo (repeatable). May be specified multiple
48+
# times. Inter-package dependencies are resolved automatically
49+
# via a temporary local APT repository built inside the rootfs.
50+
# Installed after manifest packages (--overlay).
51+
# Examples:
52+
# --local-debs mypkg.deb
53+
# --local-debs debs/
4254
#
4355
# OUTPUT:
4456
# rootfs.img Flashable ext4 rootfs image.
@@ -69,21 +81,26 @@ MANIFEST="" # internal name retained (overlay JSON)
6981
KERNEL_DEB=""
7082
FIRMWARE_DEB=""
7183
VARIANT_INPUT="" # New variable to hold the variant argument
84+
LOCAL_DEBS=() # Array of local .deb file paths (--local-debs, repeatable)
7285
USE_CONF=0
7386
USE_MANIFEST=0
7487
TARGET=""
7588

7689
print_usage() {
7790
echo "Usage:"
78-
echo " $0 --product-conf <qcom-product.conf> --seed <seed_file> --kernel-package <kernel.deb> [--firmware <firmware.deb>] [--overlay <package-manifest.json>] [--variant <variant>]"
91+
echo " $0 --product-conf <qcom-product.conf> --seed <seed_file> [--kernel-package <kernel.deb>] [--firmware <firmware.deb>] [--overlay <package-manifest.json>] [--variant <variant>] [--local-debs <pkg.deb>] ..."
7992
echo
8093
echo "Arguments:"
8194
echo " --product-conf Required. qcom-product.conf"
8295
echo " --seed Required. Seed file (one package per line; supports # comments)"
83-
echo " --kernel-package Required. Kernel .deb"
96+
echo " --kernel-package Optional. Kernel .deb"
8497
echo " --firmware Optional. Firmware .deb"
8598
echo " --overlay Optional. package-manifest.json (same schema as current manifest)"
8699
echo " --variant Optional. System variant (default: desktop)"
100+
echo " --local-debs Optional. A .deb file OR a directory of .deb files to install via a"
101+
echo " local APT repo (repeatable). Specify once per path. Dependencies"
102+
echo " between packages are resolved automatically. Installed after manifest."
103+
echo " Examples: --local-debs mypkg.deb --local-debs debs/"
87104
}
88105

89106
# Parse named options
@@ -102,6 +119,8 @@ while [[ $# -gt 0 ]]; do
102119
MANIFEST="${2-}"; shift 2 ;;
103120
--variant)
104121
VARIANT_INPUT="${2-}"; shift 2 ;;
122+
--local-debs)
123+
if [[ -n "${2-}" ]]; then LOCAL_DEBS+=("${2-}"); fi; shift 2 ;;
105124
-h|--help)
106125
print_usage
107126
exit 0
@@ -115,7 +134,7 @@ while [[ $# -gt 0 ]]; do
115134
done
116135

117136
# Validate required args
118-
if [[ -z "${CONF}" || -z "${SEED}" || -z "${KERNEL_DEB}" ]]; then
137+
if [[ -z "${CONF}" || -z "${SEED}" ]]; then
119138
echo "[ERROR] Missing required argument(s)."
120139
print_usage
121140
exit 1
@@ -129,13 +148,25 @@ fi
129148

130149
[[ -f "$CONF" ]] || { echo "[ERROR] Config file not found: $CONF"; exit 1; }
131150
[[ -f "$SEED" ]] || { echo "[ERROR] Seed file not found: $SEED"; exit 1; }
132-
[[ -f "$KERNEL_DEB" ]] || { echo "[ERROR] Kernel package not found: $KERNEL_DEB"; exit 1; }
151+
if [[ -n "$KERNEL_DEB" ]]; then
152+
[[ -f "$KERNEL_DEB" ]] || { echo "[ERROR] Kernel package not found: $KERNEL_DEB"; exit 1; }
153+
fi
133154
if [[ -n "$FIRMWARE_DEB" ]]; then
134155
[[ -f "$FIRMWARE_DEB" ]] || { echo "[ERROR] Firmware package not found: $FIRMWARE_DEB"; exit 1; }
135156
fi
136157
if [[ "$USE_MANIFEST" -eq 1 && -n "$MANIFEST" ]]; then
137158
[[ -f "$MANIFEST" ]] || { echo "[ERROR] Manifest/overlay file not found: $MANIFEST"; exit 1; }
138159
fi
160+
for _deb in "${LOCAL_DEBS[@]}"; do
161+
if [[ -d "$_deb" ]]; then
162+
: # directory — may contain zero or more .deb files; handled gracefully at copy time
163+
elif [[ -f "$_deb" ]]; then
164+
: # valid .deb file path
165+
else
166+
echo "[ERROR] --local-debs path not found (not a file or directory): $_deb"
167+
exit 1
168+
fi
169+
done
139170

140171
WORKDIR=$(pwd)
141172
MNT_DIR="$WORKDIR/mnt"
@@ -391,7 +422,9 @@ fi
391422
# Step 4: Inject Kernel, Firmware, and Working resolv.conf
392423
# ==============================================================================
393424
echo "[INFO] Copying kernel and firmware packages into rootfs..."
394-
cp "$KERNEL_DEB" "$ROOTFS_DIR/"
425+
if [[ -n "$KERNEL_DEB" ]]; then
426+
cp "$KERNEL_DEB" "$ROOTFS_DIR/"
427+
fi
395428
if [[ -n "$FIRMWARE_DEB" ]]; then
396429
cp "$FIRMWARE_DEB" "$ROOTFS_DIR/"
397430
fi
@@ -463,6 +496,27 @@ apt install -y ${APT_INSTALL_LIST[@]}
463496
EOF
464497
chmod +x "$ROOTFS_DIR/install_manifest_pkgs.sh"
465498

499+
# ==============================================================================
500+
# Step 6.5: Copy local .deb packages into rootfs (if provided)
501+
# ==============================================================================
502+
if [[ ${#LOCAL_DEBS[@]} -gt 0 ]]; then
503+
echo "[INFO] Copying local .deb packages into rootfs for local APT repository..."
504+
mkdir -p "$ROOTFS_DIR/opt/local-debs"
505+
for _deb in "${LOCAL_DEBS[@]}"; do
506+
if [[ -d "$_deb" ]]; then
507+
echo "[INFO] -> directory: $_deb"
508+
for _f in "$_deb"/*.deb; do
509+
[[ -f "$_f" ]] || continue # skip if glob matched nothing (empty dir)
510+
echo "[INFO] $(basename "$_f")"
511+
cp "$_f" "$ROOTFS_DIR/opt/local-debs/"
512+
done
513+
else
514+
echo "[INFO] -> $(basename "$_deb")"
515+
cp "$_deb" "$ROOTFS_DIR/opt/local-debs/"
516+
fi
517+
done
518+
fi
519+
466520
# ==============================================================================
467521
# Step 7: Bind Mount System Directories for chroot
468522
# ==============================================================================
@@ -516,6 +570,13 @@ else
516570
CMD_FW_INSTALL="echo '[CHROOT] Skipping firmware installation.'"
517571
fi
518572

573+
CMD_KERNEL_INSTALL=""
574+
if [[ -n "$KERNEL_DEB" ]]; then
575+
CMD_KERNEL_INSTALL="yes \"\" | dpkg -i /$(basename "$KERNEL_DEB")"
576+
else
577+
CMD_KERNEL_INSTALL="echo '[CHROOT] Skipping kernel installation (no kernel package provided).'"
578+
fi
579+
519580
echo "[INFO] Entering chroot to install packages and configure GRUB..."
520581
env DISTRO="$DISTRO" CODENAME="$CODENAME" VARIANT="$VARIANT" \
521582
chroot "$ROOTFS_DIR" /bin/bash -c "
@@ -562,7 +623,7 @@ dpkg-query -W -f='\${Package} \${Version}\n' > /tmp/\${CODENAME}_base.manifest
562623
563624
echo '[CHROOT] Installing custom firmware and kernel...'
564625
$CMD_FW_INSTALL
565-
yes \"\" | dpkg -i /$(basename "$KERNEL_DEB")
626+
$CMD_KERNEL_INSTALL
566627
567628
# Run update-grub explicitly: the zz-update-grub hook skips it in a chroot
568629
# because systemd is not running (/run/systemd/system absent).
@@ -575,6 +636,23 @@ usermod -aG sudo qcom
575636
echo '[CHROOT] Installing manifest packages (if any)...'
576637
/install_manifest_pkgs.sh || true
577638
639+
echo '[CHROOT] Installing local .deb packages via local APT repository (if any)...'
640+
if ls /opt/local-debs/*.deb >/dev/null 2>&1; then
641+
echo '[CHROOT] Setting up local .deb APT repository...'
642+
apt-get install -y --no-install-recommends dpkg-dev
643+
cd /opt/local-debs
644+
dpkg-scanpackages . /dev/null > Packages
645+
cd /
646+
echo 'deb [trusted=yes] file:///opt/local-debs ./' > /etc/apt/sources.list.d/local-debs.list
647+
apt-get update
648+
LOCAL_PKG_NAMES=\$(for deb in /opt/local-debs/*.deb; do dpkg-deb --field \"\$deb\" Package; done | tr '\n' ' ')
649+
echo \"[CHROOT] Installing local packages: \$LOCAL_PKG_NAMES\"
650+
apt-get install -y \$LOCAL_PKG_NAMES
651+
echo '[CHROOT] Local .deb packages installed successfully.'
652+
else
653+
echo '[CHROOT] No local .deb packages found; skipping.'
654+
fi
655+
578656
echo '[CHROOT] Capturing post-install package list...'
579657
dpkg-query -W -f='\${Package} \${Version}\n' > /tmp/\${CODENAME}_post.manifest
580658

0 commit comments

Comments
 (0)