Skip to content

docker: split host deps into per-group apt layers in generated Dockerfile#9999

Open
rpardini wants to merge 11 commits into
armbian:mainfrom
rpardini:pr/docker-split-host-deps-into-per-group-apt-layers-in-generated-Dockerfile
Open

docker: split host deps into per-group apt layers in generated Dockerfile#9999
rpardini wants to merge 11 commits into
armbian:mainfrom
rpardini:pr/docker-split-host-deps-into-per-group-apt-layers-in-generated-Dockerfile

Conversation

@rpardini

@rpardini rpardini commented Jun 19, 2026

Copy link
Copy Markdown
Member

docker: split host deps into per-group apt layers in generated Dockerfile

  • 🌵 host: convert EXTRA_BUILD_DEPS to a proper bash array The add_host_dependencies hook filled a space-separated string that was word-split into host_dependencies[]. Make EXTRA_BUILD_DEPS a real array and merge it with a quoted expansion instead, dropping the SC2206 hack. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌿 cli: append to EXTRA_BUILD_DEPS array in docker/patch ssh hooks Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🐸 extensions: append to EXTRA_BUILD_DEPS array in add_host_dependencies hooks Convert all in-tree add_host_dependencies__* hooks from space-separated string appends to proper bash array appends, matching the new EXTRA_BUILD_DEPS array contract. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌴 host: reword second host_dependencies hook doc for EXTRA_BUILD_DEPS array Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🍃 host: strip optional group:: prefix in install_host_side_packages Introduces HOSTDEP_GROUP_DELIMITER/HOSTDEP_DEFAULT_GROUP and strips the optional "group::package" prefix before dpkg matching / apt install. Prep for Docker layer grouping. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌳 host: assign group:: prefixes to built-in host_dependencies Restructure the built-in dependency list into per-group blocks (native-toolchain, build-tools, imaging, fs-tools, compression, emulation, python, cross-arm, cross-other, clang, core) so the Docker image can be split into multiple layers. Unprefixed entries fall into 'core'. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌱 docker: split host deps into per-group apt layers in generated Dockerfile Instead of a single huge 'apt-get install' RUN (one giant image layer), group host_dependencies by their 'group::' prefix and emit one RUN per group, ordered heaviest/most-stable first. Produces multiple layers that Docker can pull and cache in parallel. apt update is its own layer. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🍀 extensions: tag EXTRA_BUILD_DEPS with Docker-layer group:: prefixes Assign each extension's host deps to a logical group (fs-tools, emulation, clang, cross-arm/-other, build-tools, native-toolchain) so they land in the matching Docker layer. Unprefixed deps (e.g. openssh-client) stay in 'core'. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌵 docker: rebalance host-dep layer groups + dedupe packages Real 'docker history' showed lopsided layers: cross-other 562MB, cross-arm 422MB, emulation 496MB, while compression was 5.5MB. Rebalance:
    • split cross compilers per family: cross-amd64 / cross-arm64 / cross-armhf / cross-other (riscv/loong/or1k) -> even ~200-280MB band
    • split the heavy 'qemu' (qemu-user-static) out of 'emulation'; move tiny binfmt-support/arch-test and the compression tools into 'core'
    • dedupe packages in the generator (qemu-utils was listed 4x, etc.) clang (libclang-dev, 633MB) and qemu (~490MB) are single packages and remain unavoidable floors. Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🌿 extensions: move deps to rebalanced groups (qemu, cross-arm64/armhf) Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
  • 🐸 docker: split rust into own layer to flatten distribution Real 'docker history' showed native-toolchain=334MB poles.
    • rustc/cargo pull libstd-rust-dev; move them to a new 'rust' group ordered after native-toolchain (so shared gcc/build-essential stay there). Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Summary by CodeRabbit

  • Refactor
    • Reorganized build dependencies into logical groups to improve Docker layer efficiency and caching during image construction across multiple extensions.

rpardini and others added 11 commits June 19, 2026 15:43
The add_host_dependencies hook filled a space-separated string that was
word-split into host_dependencies[]. Make EXTRA_BUILD_DEPS a real array
and merge it with a quoted expansion instead, dropping the SC2206 hack.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… hooks

Convert all in-tree add_host_dependencies__* hooks from space-separated
string appends to proper bash array appends, matching the new
EXTRA_BUILD_DEPS array contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rray

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduces HOSTDEP_GROUP_DELIMITER/HOSTDEP_DEFAULT_GROUP and strips the
optional "group::package" prefix before dpkg matching / apt install.
Prep for Docker layer grouping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructure the built-in dependency list into per-group blocks (native-toolchain,
build-tools, imaging, fs-tools, compression, emulation, python, cross-arm,
cross-other, clang, core) so the Docker image can be split into multiple layers.
Unprefixed entries fall into 'core'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…file

Instead of a single huge 'apt-get install' RUN (one giant image layer),
group host_dependencies by their 'group::' prefix and emit one RUN per
group, ordered heaviest/most-stable first. Produces multiple layers that
Docker can pull and cache in parallel. apt update is its own layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Assign each extension's host deps to a logical group (fs-tools, emulation,
clang, cross-arm/-other, build-tools, native-toolchain) so they land in the
matching Docker layer. Unprefixed deps (e.g. openssh-client) stay in 'core'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real 'docker history' showed lopsided layers: cross-other 562MB, cross-arm
422MB, emulation 496MB, while compression was 5.5MB. Rebalance:
- split cross compilers per family: cross-amd64 / cross-arm64 / cross-armhf /
  cross-other (riscv/loong/or1k) -> even ~200-280MB band
- split the heavy 'qemu' (qemu-user-static) out of 'emulation'; move tiny
  binfmt-support/arch-test and the compression tools into 'core'
- dedupe packages in the generator (qemu-utils was listed 4x, etc.)
clang (libclang-dev, 633MB) and qemu (~490MB) are single packages and remain
unavoidable floors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real 'docker history' showed native-toolchain=334MB poles.
- rustc/cargo pull libstd-rust-dev; move them to a new 'rust' group ordered
  *after* native-toolchain (so shared gcc/build-essential stay there).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces a group::package naming scheme for host build dependencies. HOSTDEP_GROUP_DELIMITER and HOSTDEP_DEFAULT_GROUP constants are added to host-utils.sh with prefix-stripping at install time. prepare-host.sh rewrites the host_dependencies array using grouped entries and converts EXTRA_BUILD_DEPS from a string to an array. docker.sh gains docker_create_dockerfile_apt_install_runs to split apt installs into per-group Dockerfile RUN layers. All extension hooks are updated to append group::package entries using array syntax.

Changes

Grouped host dependency system and EXTRA_BUILD_DEPS array migration

Layer / File(s) Summary
group::package delimiter constants and install-time prefix stripping
lib/functions/host/host-utils.sh
Adds HOSTDEP_GROUP_DELIMITER (::) and HOSTDEP_DEFAULT_GROUP (core) globals, and strips the group:: prefix from each entry before package presence checks during installation.
prepare-host.sh: grouped host_dependencies array and EXTRA_BUILD_DEPS contract
lib/functions/host/prepare-host.sh, lib/functions/general/python-tools.sh
Rewrites host_dependencies initialization with group::package-prefixed entries across core, python, build-tools, qemu, cross-*, clang, and llvm groups; converts EXTRA_BUILD_DEPS from a string to an array; updates all conditional additions (QEMU, cross-toolchains, clang/lld) and the extension hook contract.
Docker Dockerfile per-group apt-get install layers
lib/functions/host/docker.sh
Adds docker_create_dockerfile_apt_install_runs to group host_dependencies by prefix, deduplicate packages, order groups via a preferred sequence, and emit DOCKERFILE_APT_INSTALL_RUNS as separate RUN apt-get install blocks; updates docker_cli_prepare_dockerfile to invoke it.
Extension EXTRA_BUILD_DEPS array migration
extensions/arm64-compat-vdso.sh, extensions/c-plus-plus-compiler.sh, extensions/cleanup-space-final-image.sh, extensions/fs-*.sh, extensions/image-output-*.sh, extensions/kernel-rust.sh, extensions/lvm.sh, extensions/mtkflash.sh, extensions/rkdevflash.sh, extensions/sunxi-tools.sh, lib/functions/cli/cli-docker.sh, lib/functions/cli/cli-patch.sh
Converts every extension add_host_dependencies hook from string concatenation to EXTRA_BUILD_DEPS+=(\"group::package\") array appends, adding group prefixes (fs-tools::, qemu::, clang::, cross-armhf::, cross-arm64::, rust::, build-tools::, native-toolchain::, etc.).

Sequence Diagram(s)

sequenceDiagram
  participant Extension
  participant adaptative_prepare_host_dependencies
  participant docker_create_dockerfile_apt_install_runs
  participant install_host_side_packages

  Extension->>adaptative_prepare_host_dependencies: EXTRA_BUILD_DEPS+=(group::package)
  adaptative_prepare_host_dependencies->>adaptative_prepare_host_dependencies: append EXTRA_BUILD_DEPS array to host_dependencies
  adaptative_prepare_host_dependencies->>docker_create_dockerfile_apt_install_runs: host_dependencies[] with group::package entries
  docker_create_dockerfile_apt_install_runs->>docker_create_dockerfile_apt_install_runs: split on ::, deduplicate, order groups
  docker_create_dockerfile_apt_install_runs-->>adaptative_prepare_host_dependencies: DOCKERFILE_APT_INSTALL_RUNS (per-group RUN blocks)
  adaptative_prepare_host_dependencies->>install_host_side_packages: host_dependencies[]
  install_host_side_packages->>install_host_side_packages: strip group:: prefix → bare package
  install_host_side_packages-->>adaptative_prepare_host_dependencies: packages installed
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

05, size/medium

Suggested reviewers

  • igorpecovnik
  • schwar3kat
  • ColorfulRhino

Poem

🐇 Hop, hop, hooray for tidy arrays!
No more strings with spaces all astray,
Each package tagged with group::name so neat,
Docker layers split — a layered feat!
The rabbit checks deps with a prefix strip,
Sorted, grouped, and ready for the trip! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: splitting host dependencies into per-group apt layers in Docker generated files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size/large PR with 250 lines or more 08 Milestone: Third quarter release Needs review Seeking for review Framework Framework components labels Jun 19, 2026
@rpardini

rpardini commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

Those TODO's were there since forever. I wanted to split the build image layers for years now. Claude to the rescue.
Result: https://asciinema.org/a/9RTLLLhXhotosaZY (tl,dr: ~2x faster pull)

(Having pigz installed (on the Docker host) helps Docker/containerd decompress faster too.)

@rpardini rpardini marked this pull request as ready for review June 19, 2026 13:55
@rpardini rpardini requested review from a team and igorpecovnik as code owners June 19, 2026 13:55
@rpardini rpardini requested review from sgjava and removed request for a team June 19, 2026 13:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/functions/host/prepare-host.sh (1)

216-220: 💤 Low value

Missing group prefix for python3-setuptools.

This conditional addition lacks the python:: group prefix used for other Python packages (lines 211, 239). It will default to the core group instead of being grouped with other Python dependencies.

For consistency with the rest of the Python packages in this file:

Suggested fix
 	if [[ 'tag:v2022.04' == "${BOOTBRANCH:-}" || 'tag:v2022.07' == "${BOOTBRANCH:-}" ]]; then
 		display_alert "Adding package to 'host_dependencies'" "python3-setuptools" "info"
-		host_dependencies+=("python3-setuptools")
+		host_dependencies+=("python::python3-setuptools")
 	fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/functions/host/prepare-host.sh` around lines 216 - 220, The
python3-setuptools package being added to host_dependencies in the conditional
block (when BOOTBRANCH matches tag:v2022.04 or tag:v2022.07) is missing the
python:: group prefix that other Python packages use elsewhere in this file
(like on lines 211 and 239). Add the python:: prefix to the python3-setuptools
string in the host_dependencies array assignment so it is properly grouped with
other Python dependencies instead of defaulting to the core group.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/functions/host/docker.sh`:
- Around line 260-287: The deduplication check at line 268 using pkg_seen locks
each package to the first group that encounters it, but the preferred_order
ranking applied later (lines 280-287) only affects layer order, not package
group assignment. To fix this, implement a two-pass approach: first collect all
unique packages and track all groups they appear in without immediate
deduplication, then in a second pass reassign package ownership based on
preferred_order ranking before building the final_order array. This ensures
shared heavy dependencies like llvm-dev land in their intended earlier layers
according to the notes on lines 276-279.

---

Nitpick comments:
In `@lib/functions/host/prepare-host.sh`:
- Around line 216-220: The python3-setuptools package being added to
host_dependencies in the conditional block (when BOOTBRANCH matches tag:v2022.04
or tag:v2022.07) is missing the python:: group prefix that other Python packages
use elsewhere in this file (like on lines 211 and 239). Add the python:: prefix
to the python3-setuptools string in the host_dependencies array assignment so it
is properly grouped with other Python dependencies instead of defaulting to the
core group.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7cf8f6a5-8f59-4a15-abaf-05078cb09b90

📥 Commits

Reviewing files that changed from the base of the PR and between 2195f35 and 229a48c.

📒 Files selected for processing (24)
  • extensions/arm64-compat-vdso.sh
  • extensions/c-plus-plus-compiler.sh
  • extensions/cleanup-space-final-image.sh
  • extensions/fs-btrfs-support.sh
  • extensions/fs-cryptroot-support.sh
  • extensions/fs-f2fs-support.sh
  • extensions/fs-nilfs2-support.sh
  • extensions/fs-xfs-support.sh
  • extensions/image-output-abl.sh
  • extensions/image-output-ovf.sh
  • extensions/image-output-qcow2.sh
  • extensions/image-output-vhd-azure.sh
  • extensions/image-output-vhdx.sh
  • extensions/kernel-rust.sh
  • extensions/lvm.sh
  • extensions/mtkflash.sh
  • extensions/rkdevflash.sh
  • extensions/sunxi-tools.sh
  • lib/functions/cli/cli-docker.sh
  • lib/functions/cli/cli-patch.sh
  • lib/functions/general/python-tools.sh
  • lib/functions/host/docker.sh
  • lib/functions/host/host-utils.sh
  • lib/functions/host/prepare-host.sh

Comment thread lib/functions/host/docker.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

08 Milestone: Third quarter release Framework Framework components Needs review Seeking for review size/large PR with 250 lines or more

Development

Successfully merging this pull request may close these issues.

1 participant