diff --git a/Dockerfile b/Dockerfile index bdf752e..ae3f8a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 \ - && pacman -S --noconfirm --needed \ - base-devel \ - git \ - nix \ - rsync \ - && pacman -Scc --noconfirm +# ------------------------------------------------------------ +# System base + conditional package installation +# ------------------------------------------------------------ +RUN set -e; \ + if [ -f /etc/os-release ]; then . /etc/os-release; else echo "No /etc/os-release found" && exit 1; fi; \ + echo "Detected base image: ${ID:-unknown} (like: ${ID_LIKE:-})"; \ + \ + # -------------------------------------------------------- + # 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 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 -# 3) Build-Stage (optional): einmal aus /build bauen, wenn du magst +# ------------------------------------------------------------ +# Build stage — only active on Arch +# ------------------------------------------------------------ WORKDIR /build 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 -# 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 RUN chmod +x /usr/local/bin/docker-entry-dev.sh diff --git a/Makefile b/Makefile index bcbf3d5..fe4fc1c 100644 --- a/Makefile +++ b/Makefile @@ -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 +# ------------------------------------------------------------ NIX_STORE_VOLUME := pkgmgr_nix_store 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 @echo "Running pkgmgr setup via main.py..." @if [ -x "$$HOME/.venvs/pkgmgr/bin/python" ]; then \ @@ -14,44 +36,129 @@ setup: install python3 main.py install; \ fi - +# ------------------------------------------------------------ +# Docker build targets: build all images +# ------------------------------------------------------------ build-no-cache: - @echo "Building test image 'package-manager-test' with no cache..." - docker build --no-cache -t package-manager-test . + @for distro in $(DISTROS); do \ + 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: - @echo "Building test image 'package-manager-test'..." - docker build -t package-manager-test . - + @for distro in $(DISTROS); do \ + 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 @echo "Ensuring Docker Nix volumes exist (auto-created if missing)..." - @echo "Running tests inside Nix devShell with cached store..." - 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" \ - ' + @echo "Running tests inside Nix devShell with cached store for all distros: $(DISTROS)" + @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: @if [ -n "$$IN_NIX_SHELL" ]; then \ 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."; \ fi -# Only runs on Arch/Manjaro +# ------------------------------------------------------------ +# AUR builder setup — only on Arch/Manjaro +# ------------------------------------------------------------ aur_builder_setup: @echo "Setting up aur_builder and yay (Arch/Manjaro)..." @sudo pacman -Syu --noconfirm @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 ! 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 @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 \ sudo -u aur_builder bash -lc 'cd ~ && rm -rf yay && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si --noconfirm'; \ else \ @@ -112,6 +218,9 @@ aur_builder_setup: fi @echo "aur_builder/yay setup complete." +# ------------------------------------------------------------ +# Uninstall target +# ------------------------------------------------------------ uninstall: @echo "Removing global user virtual environment if it exists..." @rm -rf "$$HOME/.venvs/pkgmgr"