Refactor multi-distro Dockerfile and Makefile:

- Add dynamic BASE_IMAGE selection via ARG for Arch, Debian, Ubuntu, Fedora, CentOS
- Introduce conditional package installation and unified Nix installer logic
- Implement single-user Nix install without build-users-group for Debian/Ubuntu/Fedora/CentOS
- Add Nix environment preparation and PATH fixes
- Restore Arch-only makepkg build stage
- Extend Makefile with multi-distro build/test workflow
- Add base image mappings (arch/debian/ubuntu/fedora/centos)
- Add test runner logic for each distro, including Nix devShell fallback scanning
- Improve structure with clear section headers and comments

https://chatgpt.com/share/69360c94-ef04-800f-afd2-75bc6cd33d4d
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-08 00:24:22 +01:00
parent 87b806d1b9
commit 0286cb44e0
2 changed files with 297 additions and 53 deletions

View File

@@ -1,31 +1,166 @@
FROM archlinux:latest # ------------------------------------------------------------
# Base image selector — overridden by Makefile
# ------------------------------------------------------------
ARG BASE_IMAGE=archlinux:latest
FROM ${BASE_IMAGE}
# 1) System basis + Nix # ------------------------------------------------------------
RUN pacman -Syu --noconfirm \ # System base + conditional package installation
&& pacman -S --noconfirm --needed \ # ------------------------------------------------------------
base-devel \ RUN set -e; \
git \ if [ -f /etc/os-release ]; then . /etc/os-release; else echo "No /etc/os-release found" && exit 1; fi; \
nix \ echo "Detected base image: ${ID:-unknown} (like: ${ID_LIKE:-})"; \
rsync \ \
&& pacman -Scc --noconfirm # --------------------------------------------------------
# Archlinux: Nix via pacman
# --------------------------------------------------------
if [ "$ID" = "arch" ]; then \
pacman -Syu --noconfirm && \
pacman -S --noconfirm --needed \
base-devel \
git \
nix \
rsync && \
pacman -Scc --noconfirm; \
\
# --------------------------------------------------------
# Debian: Nix installer (single-user, root, no build-users-group)
# --------------------------------------------------------
elif [ "$ID" = "debian" ]; then \
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
python3 \
python3-venv \
rsync \
bash \
xz-utils && \
rm -rf /var/lib/apt/lists/* && \
echo "Preparing /nix + /etc/nix/nix.conf on Debian..." && \
mkdir -p /nix && chmod 0755 /nix && chown root:root /nix && \
mkdir -p /etc/nix && printf 'build-users-group =\n' > /etc/nix/nix.conf && \
echo "Downloading Nix installer on Debian..." && \
curl -L https://nixos.org/nix/install -o /tmp/nix-install && \
echo "Installing Nix on Debian (single-user, as root, no build-users-group)..." && \
HOME=/root NIX_INSTALLER_NO_MODIFY_PROFILE=1 sh /tmp/nix-install --no-daemon && \
rm -f /tmp/nix-install; \
\
# --------------------------------------------------------
# Ubuntu: Nix installer (single-user, root, no build-users-group)
# --------------------------------------------------------
elif [ "$ID" = "ubuntu" ]; then \
apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
tzdata \
lsb-release \
python3 \
python3-venv \
rsync \
bash \
xz-utils && \
rm -rf /var/lib/apt/lists/* && \
echo "Preparing /nix + /etc/nix/nix.conf on Ubuntu..." && \
mkdir -p /nix && chmod 0755 /nix && chown root:root /nix && \
mkdir -p /etc/nix && printf 'build-users-group =\n' > /etc/nix/nix.conf && \
echo "Downloading Nix installer on Ubuntu..." && \
curl -L https://nixos.org/nix/install -o /tmp/nix-install && \
echo "Installing Nix on Ubuntu (single-user, as root, no build-users-group)..." && \
HOME=/root NIX_INSTALLER_NO_MODIFY_PROFILE=1 sh /tmp/nix-install --no-daemon && \
rm -f /tmp/nix-install; \
\
# --------------------------------------------------------
# Fedora: Nix installer (single-user, root, no build-users-group)
# --------------------------------------------------------
elif [ "$ID" = "fedora" ]; then \
dnf -y update && \
dnf -y install \
ca-certificates \
curl \
git \
python3 \
rsync \
bash \
xz && \
dnf clean all && \
echo "Preparing /nix + /etc/nix/nix.conf on Fedora..." && \
mkdir -p /nix && chmod 0755 /nix && chown root:root /nix && \
mkdir -p /etc/nix && printf 'build-users-group =\n' > /etc/nix/nix.conf && \
echo "Downloading Nix installer on Fedora..." && \
curl -L https://nixos.org/nix/install -o /tmp/nix-install && \
echo "Installing Nix on Fedora (single-user, as root, no build-users-group)..." && \
HOME=/root NIX_INSTALLER_NO_MODIFY_PROFILE=1 sh /tmp/nix-install --no-daemon && \
rm -f /tmp/nix-install; \
\
# --------------------------------------------------------
# CentOS Stream: Nix installer (single-user, root, no build-users-group)
# --------------------------------------------------------
elif [ "$ID" = "centos" ]; then \
dnf -y update && \
dnf -y install \
ca-certificates \
curl-minimal \
git \
python3 \
rsync \
bash \
xz && \
dnf clean all && \
echo "Preparing /nix + /etc/nix/nix.conf on CentOS..." && \
mkdir -p /nix && chmod 0755 /nix && chown root:root /nix && \
mkdir -p /etc/nix && printf 'build-users-group =\n' > /etc/nix/nix.conf && \
echo "Downloading Nix installer on CentOS..." && \
curl -L https://nixos.org/nix/install -o /tmp/nix-install && \
echo "Installing Nix on CentOS (single-user, as root, no build-users-group)..." && \
HOME=/root NIX_INSTALLER_NO_MODIFY_PROFILE=1 sh /tmp/nix-install --no-daemon && \
rm -f /tmp/nix-install; \
\
# --------------------------------------------------------
# Unknown distro
# --------------------------------------------------------
else \
echo "Unsupported base image: ${ID}" && exit 1; \
fi
# Nix CLI behavior (used later in tests)
ENV NIX_CONFIG="experimental-features = nix-command flakes" ENV NIX_CONFIG="experimental-features = nix-command flakes"
ENV PATH="/root/.nix-profile/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# 2) Unprivileged user for building Arch packages # ------------------------------------------------------------
# Create unprivileged build user (used on Arch for makepkg)
# ------------------------------------------------------------
RUN useradd -m builder RUN useradd -m builder
# 3) Build-Stage (optional): einmal aus /build bauen, wenn du magst # ------------------------------------------------------------
# Build stage — only active on Arch
# ------------------------------------------------------------
WORKDIR /build WORKDIR /build
COPY . . COPY . .
RUN chown -R builder:builder /build \
&& su builder -c "cd /build && rm -f package-manager-*.pkg.tar.* && makepkg -sf --noconfirm --clean" \
&& pacman -U --noconfirm package-manager-*.pkg.tar.* \
&& rm -rf /build
# 4) Runtime-Workingdir für das gemountete Repo RUN set -e; \
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
if [ "$ID" = "arch" ]; then \
echo "Running Arch build stage (makepkg)..."; \
chown -R builder:builder /build && \
su builder -c "cd /build && rm -f package-manager-*.pkg.tar.* && makepkg -sf --noconfirm --clean"; \
pacman -U --noconfirm package-manager-*.pkg.tar.*; \
else \
echo "Non-Arch base detected — skipping Arch package build."; \
fi; \
rm -rf /build
# ------------------------------------------------------------
# Runtime working directory for the mounted repository
# ------------------------------------------------------------
WORKDIR /src WORKDIR /src
# 5) Entry-Script für „always build from /src“ # ------------------------------------------------------------
# Development entry script
# ------------------------------------------------------------
COPY scripts/docker-entry-dev.sh /usr/local/bin/docker-entry-dev.sh COPY scripts/docker-entry-dev.sh /usr/local/bin/docker-entry-dev.sh
RUN chmod +x /usr/local/bin/docker-entry-dev.sh RUN chmod +x /usr/local/bin/docker-entry-dev.sh

181
Makefile
View File

@@ -1,9 +1,31 @@
.PHONY: install setup uninstall aur_builder_setup test .PHONY: install setup uninstall aur_builder_setup \
test build build-no-cache
# ------------------------------------------------------------
# Local Nix cache directories in the repo # Local Nix cache directories in the repo
# ------------------------------------------------------------
NIX_STORE_VOLUME := pkgmgr_nix_store NIX_STORE_VOLUME := pkgmgr_nix_store
NIX_CACHE_VOLUME := pkgmgr_nix_cache NIX_CACHE_VOLUME := pkgmgr_nix_cache
# ------------------------------------------------------------
# Distro list and base images
# ------------------------------------------------------------
DISTROS := arch #debian ubuntu fedora centos
BASE_IMAGE_arch := archlinux:latest
BASE_IMAGE_debian := debian:stable-slim
BASE_IMAGE_ubuntu := ubuntu:latest
BASE_IMAGE_fedora := fedora:latest
BASE_IMAGE_centos := quay.io/centos/centos:stream9
# Helper to echo which image is used for which distro (purely informational)
define echo_build_info
@echo "Building image for distro '$(1)' with base image '$(2)'..."
endef
# ------------------------------------------------------------
# PKGMGR setup (wrapper)
# ------------------------------------------------------------
setup: install setup: install
@echo "Running pkgmgr setup via main.py..." @echo "Running pkgmgr setup via main.py..."
@if [ -x "$$HOME/.venvs/pkgmgr/bin/python" ]; then \ @if [ -x "$$HOME/.venvs/pkgmgr/bin/python" ]; then \
@@ -14,44 +36,129 @@ setup: install
python3 main.py install; \ python3 main.py install; \
fi fi
# ------------------------------------------------------------
# Docker build targets: build all images
# ------------------------------------------------------------
build-no-cache: build-no-cache:
@echo "Building test image 'package-manager-test' with no cache..." @for distro in $(DISTROS); do \
docker build --no-cache -t package-manager-test . case "$$distro" in \
arch) base_image="$(BASE_IMAGE_arch)" ;; \
debian) base_image="$(BASE_IMAGE_debian)" ;; \
ubuntu) base_image="$(BASE_IMAGE_ubuntu)" ;; \
fedora) base_image="$(BASE_IMAGE_fedora)" ;; \
centos) base_image="$(BASE_IMAGE_centos)" ;; \
*) echo "Unknown distro '$$distro'" >&2; exit 1 ;; \
esac; \
echo "Building test image 'package-manager-test-$$distro' with no cache (BASE_IMAGE=$$base_image)..."; \
docker build --no-cache \
--build-arg BASE_IMAGE="$$base_image" \
-t "package-manager-test-$$distro" . || exit $$?; \
done
build: build:
@echo "Building test image 'package-manager-test'..." @for distro in $(DISTROS); do \
docker build -t package-manager-test . case "$$distro" in \
arch) base_image="$(BASE_IMAGE_arch)" ;; \
debian) base_image="$(BASE_IMAGE_debian)" ;; \
ubuntu) base_image="$(BASE_IMAGE_ubuntu)" ;; \
fedora) base_image="$(BASE_IMAGE_fedora)" ;; \
centos) base_image="$(BASE_IMAGE_centos)" ;; \
*) echo "Unknown distro '$$distro'" >&2; exit 1 ;; \
esac; \
echo "Building test image 'package-manager-test-$$distro' (BASE_IMAGE=$$base_image)..."; \
docker build \
--build-arg BASE_IMAGE="$$base_image" \
-t "package-manager-test-$$distro" . || exit $$?; \
done
# ------------------------------------------------------------
# Test target: run tests in all three images
# ------------------------------------------------------------
test: build test: build
@echo "Ensuring Docker Nix volumes exist (auto-created if missing)..." @echo "Ensuring Docker Nix volumes exist (auto-created if missing)..."
@echo "Running tests inside Nix devShell with cached store..." @echo "Running tests inside Nix devShell with cached store for all distros: $(DISTROS)"
docker run --rm \
-v "$$(pwd):/src" \
-v "$(NIX_STORE_VOLUME):/nix" \
-v "$(NIX_CACHE_VOLUME):/root/.cache/nix" \
--workdir /src \
--entrypoint bash \
package-manager-test \
-c '\
set -e; \
echo "Remove existing Arch package-manager (if any)..."; \
pacman -Rns --noconfirm package-manager || true; \
echo "Rebuild Arch package from /src..."; \
rm -f /src/package-manager-*.pkg.tar.* || true; \
chown -R builder:builder /src; \
su builder -c "cd /src && makepkg -sf --noconfirm --clean"; \
pacman -U --noconfirm /src/package-manager-*.pkg.tar.*; \
echo "Run tests inside Nix devShell..."; \
git config --global --add safe.directory /src && \
cd /src && \
nix develop .#default --no-write-lock-file -c \
python3 -m unittest discover \
-s /src/tests \
-p "test_*.py" \
'
@for distro in $(DISTROS); do \
echo "============================================================"; \
echo ">>> Running tests in container for distro: $$distro"; \
echo "============================================================"; \
docker run --rm \
-v "$$(pwd):/src" \
-v "$(NIX_STORE_VOLUME):/nix" \
-v "$(NIX_CACHE_VOLUME):/root/.cache/nix" \
--workdir /src \
--entrypoint bash \
"package-manager-test-$$distro" \
-c '\
set -e; \
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
echo "Detected container distro: $${ID:-unknown} (like: $${ID_LIKE:-})"; \
\
# Arch-only: rebuild Arch package inside the container \
if [ "$${ID}" = "arch" ]; then \
echo "Remove existing Arch package-manager (if any)..."; \
pacman -Rns --noconfirm package-manager || true; \
echo "Rebuild Arch package from /src..."; \
rm -f /src/package-manager-*.pkg.tar.* || true; \
chown -R builder:builder /src; \
su builder -c "cd /src && makepkg -sf --noconfirm --clean"; \
pacman -U --noconfirm /src/package-manager-*.pkg.tar.*; \
else \
echo "Non-Arch distro skipping Arch package rebuild."; \
fi; \
\
echo "Preparing Nix environment..."; \
# Try to source typical Nix profile scripts (if they exist) \
if [ -f "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ]; then \
. "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"; \
fi; \
if [ -f "$$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then \
. "$$HOME/.nix-profile/etc/profile.d/nix.sh"; \
fi; \
# Hard-extend PATH for common Nix locations \
PATH="/nix/var/nix/profiles/default/bin:$$HOME/.nix-profile/bin:$$PATH"; \
export PATH; \
echo "PATH is now:"; \
echo "$$PATH"; \
\
# Determine which Nix binary to use \
NIX_CMD=""; \
if command -v nix >/dev/null 2>&1; then \
echo "Found nix on PATH:"; \
command -v nix; \
NIX_CMD="nix"; \
else \
echo "nix not found on PATH, scanning /nix/store for a nix binary..."; \
for path in /nix/store/*-nix-*/bin/nix; do \
if [ -x "$$path" ]; then \
echo "Found nix binary at $$path"; \
NIX_CMD="$$path"; \
break; \
fi; \
done; \
fi; \
\
if [ -z "$$NIX_CMD" ]; then \
echo "ERROR: nix binary not found anywhere cannot run devShell"; \
exit 1; \
fi; \
\
echo "Using Nix command: $$NIX_CMD"; \
echo "Run tests inside Nix devShell..."; \
git config --global --add safe.directory /src; \
cd /src; \
"$$NIX_CMD" develop .#default --no-write-lock-file -c \
python3 -m unittest discover \
-s /src/tests \
-p "test_*.py"; \
' || exit $$?; \
done
# ------------------------------------------------------------
# Installer for host systems (your original logic)
# ------------------------------------------------------------
install: install:
@if [ -n "$$IN_NIX_SHELL" ]; then \ @if [ -n "$$IN_NIX_SHELL" ]; then \
echo "Nix shell detected (IN_NIX_SHELL=1). Skipping venv/pip install handled by Nix flake."; \ echo "Nix shell detected (IN_NIX_SHELL=1). Skipping venv/pip install handled by Nix flake."; \
@@ -93,18 +200,17 @@ install:
echo "Installation complete. Please restart your shell (or 'exec bash' or 'exec zsh') for the changes to take effect."; \ echo "Installation complete. Please restart your shell (or 'exec bash' or 'exec zsh') for the changes to take effect."; \
fi fi
# Only runs on Arch/Manjaro # ------------------------------------------------------------
# AUR builder setup — only on Arch/Manjaro
# ------------------------------------------------------------
aur_builder_setup: aur_builder_setup:
@echo "Setting up aur_builder and yay (Arch/Manjaro)..." @echo "Setting up aur_builder and yay (Arch/Manjaro)..."
@sudo pacman -Syu --noconfirm @sudo pacman -Syu --noconfirm
@sudo pacman -S --needed --noconfirm base-devel git sudo @sudo pacman -S --needed --noconfirm base-devel git sudo
@# group & user
@if ! getent group aur_builder >/dev/null; then sudo groupadd -r aur_builder; fi @if ! getent group aur_builder >/dev/null; then sudo groupadd -r aur_builder; fi
@if ! id -u aur_builder >/dev/null 2>&1; then sudo useradd -m -r -g aur_builder -s /bin/bash aur_builder; fi @if ! id -u aur_builder >/dev/null 2>&1; then sudo useradd -m -r -g aur_builder -s /bin/bash aur_builder; fi
@# sudoers rule for pacman
@echo '%aur_builder ALL=(ALL) NOPASSWD: /usr/bin/pacman' | sudo tee /etc/sudoers.d/aur_builder >/dev/null @echo '%aur_builder ALL=(ALL) NOPASSWD: /usr/bin/pacman' | sudo tee /etc/sudoers.d/aur_builder >/dev/null
@sudo chmod 0440 /etc/sudoers.d/aur_builder @sudo chmod 0440 /etc/sudoers.d/aur_builder
@# yay install (if missing)
@if ! sudo -u aur_builder bash -lc 'command -v yay >/dev/null'; then \ @if ! sudo -u aur_builder bash -lc 'command -v yay >/dev/null'; then \
sudo -u aur_builder bash -lc 'cd ~ && rm -rf yay && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si --noconfirm'; \ sudo -u aur_builder bash -lc 'cd ~ && rm -rf yay && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si --noconfirm'; \
else \ else \
@@ -112,6 +218,9 @@ aur_builder_setup:
fi fi
@echo "aur_builder/yay setup complete." @echo "aur_builder/yay setup complete."
# ------------------------------------------------------------
# Uninstall target
# ------------------------------------------------------------
uninstall: uninstall:
@echo "Removing global user virtual environment if it exists..." @echo "Removing global user virtual environment if it exists..."
@rm -rf "$$HOME/.venvs/pkgmgr" @rm -rf "$$HOME/.venvs/pkgmgr"