Refactor container build and installation pipeline to use configurable Makefile parameters (e.g. DISTROS, base images) and propagate them through all build, install, and test scripts
This commit is contained in:
25
.github/workflows/test-container.yml
vendored
Normal file
25
.github/workflows/test-container.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: Test Distribution Containers
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- "*"
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-unit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Show Docker version
|
||||||
|
run: docker version
|
||||||
|
|
||||||
|
- name: Run container tests
|
||||||
|
run: make test-container
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -15,7 +15,7 @@ venv/
|
|||||||
|
|
||||||
# Build artifacts
|
# Build artifacts
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/*
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
|
|
||||||
# Editor files
|
# Editor files
|
||||||
@@ -31,4 +31,11 @@ Thumbs.db
|
|||||||
|
|
||||||
# Ignore logs
|
# Ignore logs
|
||||||
*.log
|
*.log
|
||||||
package-manager-*
|
package-manager-*
|
||||||
|
|
||||||
|
# debian
|
||||||
|
debian/package-manager/
|
||||||
|
debian/debhelper-build-stamp
|
||||||
|
debian/files
|
||||||
|
debian/.debhelper/
|
||||||
|
debian/package-manager.substvars
|
||||||
194
Dockerfile
194
Dockerfile
@@ -4,87 +4,6 @@
|
|||||||
ARG BASE_IMAGE=archlinux:latest
|
ARG BASE_IMAGE=archlinux:latest
|
||||||
FROM ${BASE_IMAGE}
|
FROM ${BASE_IMAGE}
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# System base + conditional package tool installation
|
|
||||||
#
|
|
||||||
# Important:
|
|
||||||
# - We do NOT install Nix directly here via curl.
|
|
||||||
# - Nix is installed/initialized by init-nix.sh, which is invoked
|
|
||||||
# from the system packaging hooks (Arch .install, Debian postinst,
|
|
||||||
# RPM %post).
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
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:-})"; \
|
|
||||||
\
|
|
||||||
if [ "$ID" = "arch" ]; then \
|
|
||||||
pacman -Syu --noconfirm && \
|
|
||||||
pacman -S --noconfirm --needed \
|
|
||||||
base-devel \
|
|
||||||
git \
|
|
||||||
rsync \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
xz && \
|
|
||||||
pacman -Scc --noconfirm; \
|
|
||||||
elif [ "$ID" = "debian" ]; then \
|
|
||||||
apt-get update && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
build-essential \
|
|
||||||
debhelper \
|
|
||||||
dpkg-dev \
|
|
||||||
git \
|
|
||||||
rsync \
|
|
||||||
bash \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
xz-utils && \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
elif [ "$ID" = "ubuntu" ]; then \
|
|
||||||
apt-get update && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
build-essential \
|
|
||||||
debhelper \
|
|
||||||
dpkg-dev \
|
|
||||||
git \
|
|
||||||
tzdata \
|
|
||||||
lsb-release \
|
|
||||||
rsync \
|
|
||||||
bash \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
xz-utils && \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
elif [ "$ID" = "fedora" ]; then \
|
|
||||||
dnf -y update && \
|
|
||||||
dnf -y install \
|
|
||||||
git \
|
|
||||||
rsync \
|
|
||||||
rpm-build \
|
|
||||||
make \
|
|
||||||
gcc \
|
|
||||||
bash \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
xz && \
|
|
||||||
dnf clean all; \
|
|
||||||
elif [ "$ID" = "centos" ]; then \
|
|
||||||
dnf -y update && \
|
|
||||||
dnf -y install \
|
|
||||||
git \
|
|
||||||
rsync \
|
|
||||||
rpm-build \
|
|
||||||
make \
|
|
||||||
gcc \
|
|
||||||
bash \
|
|
||||||
curl-minimal \
|
|
||||||
ca-certificates \
|
|
||||||
xz && \
|
|
||||||
dnf clean all; \
|
|
||||||
else \
|
|
||||||
echo "Unsupported base image: ${ID}" && exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Nix environment defaults
|
# Nix environment defaults
|
||||||
#
|
#
|
||||||
@@ -96,94 +15,38 @@ ENV NIX_CONFIG="experimental-features = nix-command flakes"
|
|||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Unprivileged user for Arch package build (makepkg)
|
# Unprivileged user for Arch package build (makepkg)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
RUN useradd -m builder || true
|
RUN useradd -m aur_builder || true
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Copy scripts and install distro dependencies
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy only scripts first so dependency installation can run early
|
||||||
|
COPY scripts/ scripts/
|
||||||
|
RUN find scripts -type f -name '*.sh' -exec chmod +x {} \;
|
||||||
|
|
||||||
|
# Install distro-specific build dependencies (and AUR builder on Arch)
|
||||||
|
RUN scripts/installation/run-dependencies.sh
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Select distro-specific Docker entrypoint
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Docker entrypoint (distro-agnostic, nutzt run-package.sh)
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
COPY scripts/docker/entry.sh /usr/local/bin/docker-entry.sh
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entry.sh
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Build and install distro-native package-manager package
|
# Build and install distro-native package-manager package
|
||||||
#
|
# via Makefile `install` target (calls scripts/installation/run-package.sh)
|
||||||
# - Arch: PKGBUILD -> pacman -U
|
|
||||||
# - Debian: debhelper -> dpkg-buildpackage -> apt install ./package-manager_*.deb
|
|
||||||
# - Ubuntu: same as Debian
|
|
||||||
# - Fedora: rpmbuild -> dnf/dnf5/yum install package-manager-*.rpm
|
|
||||||
# - CentOS: rpmbuild -> dnf/yum install package-manager-*.rpm
|
|
||||||
#
|
|
||||||
# Nix is NOT manually installed here; it is handled by init-nix.sh.
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
WORKDIR /build
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN find scripts -type f -name '*.sh' -exec chmod +x {} \;
|
||||||
|
|
||||||
RUN set -e; \
|
RUN set -e; \
|
||||||
. /etc/os-release; \
|
echo "Building and installing package-manager via make install..."; \
|
||||||
if [ "$ID" = "arch" ]; then \
|
make install; \
|
||||||
echo 'Building Arch package (makepkg --nodeps)...'; \
|
|
||||||
chown -R builder:builder /build; \
|
|
||||||
su builder -c "cd /build && rm -f package-manager-*.pkg.tar.* && makepkg --noconfirm --clean --nodeps"; \
|
|
||||||
\
|
|
||||||
echo 'Installing generated Arch package...'; \
|
|
||||||
pacman -U --noconfirm package-manager-*.pkg.tar.*; \
|
|
||||||
elif [ "$ID" = "debian" ] || [ "$ID" = "ubuntu" ]; then \
|
|
||||||
echo 'Building Debian/Ubuntu package...'; \
|
|
||||||
dpkg-buildpackage -us -uc -b; \
|
|
||||||
\
|
|
||||||
echo 'Installing generated DEB package...'; \
|
|
||||||
apt-get update && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y ./../package-manager_*.deb && \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
elif [ "$ID" = "fedora" ] || [ "$ID" = "centos" ]; then \
|
|
||||||
echo 'Setting up rpmbuild dirs...'; \
|
|
||||||
mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}; \
|
|
||||||
\
|
|
||||||
echo "Extracting version from package-manager.spec..."; \
|
|
||||||
version=$(grep -E '^Version:' /build/package-manager.spec | awk '{print $2}'); \
|
|
||||||
if [ -z "$version" ]; then echo 'ERROR: Version missing!' && exit 1; fi; \
|
|
||||||
srcdir="package-manager-${version}"; \
|
|
||||||
\
|
|
||||||
echo "Preparing source tree for RPM: $srcdir"; \
|
|
||||||
rm -rf "/tmp/$srcdir"; \
|
|
||||||
mkdir -p "/tmp/$srcdir"; \
|
|
||||||
cp -a /build/. "/tmp/$srcdir/"; \
|
|
||||||
\
|
|
||||||
echo "Creating source tarball: /root/rpmbuild/SOURCES/$srcdir.tar.gz"; \
|
|
||||||
tar czf "/root/rpmbuild/SOURCES/$srcdir.tar.gz" -C /tmp "$srcdir"; \
|
|
||||||
\
|
|
||||||
echo 'Copying SPEC...'; \
|
|
||||||
cp /build/package-manager.spec /root/rpmbuild/SPECS/; \
|
|
||||||
\
|
|
||||||
echo 'Running rpmbuild...'; \
|
|
||||||
cd /root/rpmbuild/SPECS && rpmbuild -bb package-manager.spec; \
|
|
||||||
\
|
|
||||||
echo 'Installing generated RPM (local, offline)...'; \
|
|
||||||
rpm_path=$(find /root/rpmbuild/RPMS -name "package-manager-*.rpm" | head -n1); \
|
|
||||||
if [ -z "$rpm_path" ]; then echo 'ERROR: RPM not found!' && exit 1; fi; \
|
|
||||||
\
|
|
||||||
if command -v dnf5 >/dev/null 2>&1; then \
|
|
||||||
echo 'Using dnf5 to install local RPM (no remote repos)...'; \
|
|
||||||
if ! dnf5 install -y --disablerepo='*' "$rpm_path"; then \
|
|
||||||
echo 'dnf5 failed, falling back to rpm -i --nodeps'; \
|
|
||||||
rpm -i --nodeps "$rpm_path"; \
|
|
||||||
fi; \
|
|
||||||
elif command -v dnf >/dev/null 2>&1; then \
|
|
||||||
echo 'Using dnf to install local RPM (no remote repos)...'; \
|
|
||||||
if ! dnf install -y --disablerepo='*' "$rpm_path"; then \
|
|
||||||
echo 'dnf failed, falling back to rpm -i --nodeps'; \
|
|
||||||
rpm -i --nodeps "$rpm_path"; \
|
|
||||||
fi; \
|
|
||||||
elif command -v yum >/dev/null 2>&1; then \
|
|
||||||
echo 'Using yum to install local RPM (no remote repos)...'; \
|
|
||||||
if ! yum localinstall -y --disablerepo='*' "$rpm_path"; then \
|
|
||||||
echo 'yum failed, falling back to rpm -i --nodeps'; \
|
|
||||||
rpm -i --nodeps "$rpm_path"; \
|
|
||||||
fi; \
|
|
||||||
else \
|
|
||||||
echo 'No dnf/dnf5/yum found, falling back to rpm -i --nodeps...'; \
|
|
||||||
rpm -i --nodeps "$rpm_path"; \
|
|
||||||
fi; \
|
|
||||||
\
|
|
||||||
rm -rf "/tmp/$srcdir"; \
|
|
||||||
else \
|
|
||||||
echo "Unsupported distro: ${ID}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
rm -rf /build
|
rm -rf /build
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
@@ -191,8 +54,5 @@ RUN set -e; \
|
|||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
COPY scripts/docker-entry-dev.sh /usr/local/bin/docker-entry-dev.sh
|
ENTRYPOINT ["/usr/local/bin/docker-entry.sh"]
|
||||||
RUN chmod +x /usr/local/bin/docker-entry-dev.sh
|
CMD ["pkgmgr", "--help"]
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/docker-entry-dev.sh"]
|
|
||||||
CMD ["--help"]
|
|
||||||
|
|||||||
278
Makefile
278
Makefile
@@ -1,5 +1,6 @@
|
|||||||
.PHONY: install setup uninstall aur_builder_setup \
|
.PHONY: install setup uninstall \
|
||||||
test build build-no-cache test-unit test-e2e test-integration
|
test build build-no-cache test-unit test-e2e test-integration \
|
||||||
|
test-container
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Local Nix cache directories in the repo
|
# Local Nix cache directories in the repo
|
||||||
@@ -9,267 +10,72 @@ NIX_CACHE_VOLUME := pkgmgr_nix_cache
|
|||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Distro list and base images
|
# Distro list and base images
|
||||||
|
# (kept for documentation/reference; actual build logic is in scripts/build)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
DISTROS := arch debian ubuntu fedora centos
|
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
|
||||||
|
|
||||||
BASE_IMAGE_arch := archlinux:latest
|
# Make them available in scripts
|
||||||
BASE_IMAGE_debian := debian:stable-slim
|
export DISTROS
|
||||||
BASE_IMAGE_ubuntu := ubuntu:latest
|
export BASE_IMAGE_ARCH
|
||||||
BASE_IMAGE_fedora := fedora:latest
|
export BASE_IMAGE_DEBIAN
|
||||||
BASE_IMAGE_centos := quay.io/centos/centos:stream9
|
export BASE_IMAGE_UBUNTU
|
||||||
|
export BASE_IMAGE_FEDORA
|
||||||
# Helper to echo which image is used for which distro (purely informational)
|
export BASE_IMAGE_CENTOS
|
||||||
define echo_build_info
|
|
||||||
@echo "Building image for distro '$(1)' with base image '$(2)'..."
|
|
||||||
endef
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# PKGMGR setup (wrapper)
|
# PKGMGR setup (developer wrapper -> scripts/installation/main.sh)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
setup: install
|
setup:
|
||||||
@echo "Running pkgmgr setup via main.py..."
|
@bash scripts/installation/main.sh
|
||||||
@if [ -x "$$HOME/.venvs/pkgmgr/bin/python" ]; then \
|
|
||||||
echo "Using virtualenv Python at $$HOME/.venvs/pkgmgr/bin/python"; \
|
|
||||||
"$$HOME/.venvs/pkgmgr/bin/python" main.py install; \
|
|
||||||
else \
|
|
||||||
echo "Virtualenv not found, falling back to system python3"; \
|
|
||||||
python3 main.py install; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Docker build targets: build all images
|
# Docker build targets (delegated to scripts/build)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
build-no-cache:
|
build-no-cache:
|
||||||
@for distro in $(DISTROS); do \
|
@bash scripts/build/build-image-no-cache.sh
|
||||||
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:
|
||||||
@for distro in $(DISTROS); do \
|
@bash scripts/build/build-image.sh
|
||||||
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
|
|
||||||
|
|
||||||
build-arch:
|
|
||||||
@base_image="$(BASE_IMAGE_arch)"; \
|
|
||||||
echo "Building test image 'package-manager-test-arch' (BASE_IMAGE=$$base_image)..."; \
|
|
||||||
docker build \
|
|
||||||
--build-arg BASE_IMAGE="$$base_image" \
|
|
||||||
-t "package-manager-test-arch" . || exit $$?;
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Test targets
|
# Test targets (delegated to scripts/test)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
# Unit tests: only in Arch container (fastest feedback), via Nix devShell
|
test-unit:
|
||||||
test-unit: build-arch
|
@bash scripts/test/test-unit.sh
|
||||||
@echo "============================================================"
|
|
||||||
@echo ">>> Running UNIT tests in Arch container (via Nix devShell)"
|
|
||||||
@echo "============================================================"
|
|
||||||
docker run --rm \
|
|
||||||
-v "$$(pwd):/src" \
|
|
||||||
--workdir /src \
|
|
||||||
--entrypoint bash \
|
|
||||||
"package-manager-test-arch" \
|
|
||||||
-c '\
|
|
||||||
set -e; \
|
|
||||||
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
|
|
||||||
echo "Detected container distro: $${ID:-unknown} (like: $${ID_LIKE:-})"; \
|
|
||||||
echo "Running Python unit tests (tests/unit) via nix develop..."; \
|
|
||||||
git config --global --add safe.directory /src || true; \
|
|
||||||
cd /src; \
|
|
||||||
nix develop .#default --no-write-lock-file -c \
|
|
||||||
python -m unittest discover \
|
|
||||||
-s tests/unit \
|
|
||||||
-t /src \
|
|
||||||
-p "test_*.py"; \
|
|
||||||
'
|
|
||||||
|
|
||||||
# Integration tests: also in Arch container, via Nix devShell
|
test-integration:
|
||||||
test-integration: build-arch
|
@bash scripts/test/test-integration.sh
|
||||||
@echo "============================================================"
|
|
||||||
@echo ">>> Running INTEGRATION tests in Arch container (via Nix devShell)"
|
|
||||||
@echo "============================================================"
|
|
||||||
docker run --rm \
|
|
||||||
-v "$$(pwd):/src" \
|
|
||||||
--workdir /src \
|
|
||||||
--entrypoint bash \
|
|
||||||
"package-manager-test-arch" \
|
|
||||||
-c '\
|
|
||||||
set -e; \
|
|
||||||
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
|
|
||||||
echo "Detected container distro: $${ID:-unknown} (like: $${ID_LIKE:-})"; \
|
|
||||||
echo "Running Python integration tests (tests/integration) via nix develop..."; \
|
|
||||||
git config --global --add safe.directory /src || true; \
|
|
||||||
cd /src; \
|
|
||||||
nix develop .#default --no-write-lock-file -c \
|
|
||||||
python -m unittest discover \
|
|
||||||
-s tests/integration \
|
|
||||||
-t /src \
|
|
||||||
-p "test_*.py"; \
|
|
||||||
'
|
|
||||||
|
|
||||||
# End-to-end tests: run in all distros via Nix devShell (tests/e2e)
|
test-e2e:
|
||||||
test-e2e: build
|
@bash scripts/test/test-e2e.sh
|
||||||
@echo "Ensuring Docker Nix volumes exist (auto-created if missing)..."
|
|
||||||
@echo "Running E2E tests inside Nix devShell with cached store for all distros: $(DISTROS)"
|
|
||||||
|
|
||||||
@for distro in $(DISTROS); do \
|
test-container:
|
||||||
echo "============================================================"; \
|
@bash scripts/test/test-container.sh
|
||||||
echo ">>> Running E2E tests in container for distro: $$distro"; \
|
|
||||||
echo "============================================================"; \
|
# ------------------------------------------------------------
|
||||||
# Only for Arch: mount /nix as volume, for others use image-installed Nix \
|
# Build only missing container images
|
||||||
if [ "$$distro" = "arch" ]; then \
|
# ------------------------------------------------------------
|
||||||
NIX_STORE_MOUNT="-v $(NIX_STORE_VOLUME):/nix"; \
|
build-missing:
|
||||||
else \
|
@bash scripts/build/build-image-missing.sh
|
||||||
NIX_STORE_MOUNT=""; \
|
|
||||||
fi; \
|
|
||||||
docker run --rm \
|
|
||||||
-v "$$(pwd):/src" \
|
|
||||||
$$NIX_STORE_MOUNT \
|
|
||||||
-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:-})"; \
|
|
||||||
echo "Preparing Nix environment..."; \
|
|
||||||
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; \
|
|
||||||
PATH="/nix/var/nix/profiles/default/bin:$$HOME/.nix-profile/bin:$$PATH"; \
|
|
||||||
export PATH; \
|
|
||||||
echo "PATH is now:"; \
|
|
||||||
echo "$$PATH"; \
|
|
||||||
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 E2E tests inside Nix devShell (tests/e2e)..."; \
|
|
||||||
git config --global --add safe.directory /src || true; \
|
|
||||||
cd /src; \
|
|
||||||
"$$NIX_CMD" develop .#default --no-write-lock-file -c \
|
|
||||||
python3 -m unittest discover \
|
|
||||||
-s /src/tests/e2e \
|
|
||||||
-p "test_*.py"; \
|
|
||||||
' || exit $$?; \
|
|
||||||
done
|
|
||||||
|
|
||||||
# Combined test target for local + CI (unit + e2e + integration)
|
# Combined test target for local + CI (unit + e2e + integration)
|
||||||
test: build test-unit test-e2e test-integration
|
test: build-missing test-container test-unit test-e2e test-integration
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Installer for host systems (original logic)
|
# System install (native packages, calls scripts/installation/run-package.sh)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
install:
|
install:
|
||||||
@if [ -n "$$IN_NIX_SHELL" ]; then \
|
@echo "Building and installing distro-native package-manager for this system..."
|
||||||
echo "Nix shell detected (IN_NIX_SHELL=1). Skipping venv/pip install – handled by Nix flake."; \
|
@bash scripts/installation/run-package.sh
|
||||||
else \
|
|
||||||
echo "Making 'main.py' executable..."; \
|
|
||||||
chmod +x main.py; \
|
|
||||||
echo "Checking if global user virtual environment exists..."; \
|
|
||||||
mkdir -p "$$HOME/.venvs"; \
|
|
||||||
if [ ! -d "$$HOME/.venvs/pkgmgr" ]; then \
|
|
||||||
echo "Creating global venv at $$HOME/.venvs/pkgmgr..."; \
|
|
||||||
python3 -m venv "$$HOME/.venvs/pkgmgr"; \
|
|
||||||
fi; \
|
|
||||||
echo "Installing required Python packages into $$HOME/.venvs/pkgmgr..."; \
|
|
||||||
"$$HOME/.venvs/pkgmgr/bin/python" -m ensurepip --upgrade; \
|
|
||||||
"$$HOME/.venvs/pkgmgr/bin/pip" install --upgrade pip setuptools wheel; \
|
|
||||||
echo "Looking for requirements.txt / _requirements.txt..."; \
|
|
||||||
if [ -f requirements.txt ]; then \
|
|
||||||
echo "Installing Python packages from requirements.txt..."; \
|
|
||||||
"$$HOME/.venvs/pkgmgr/bin/pip" install -r requirements.txt; \
|
|
||||||
elif [ -f _requirements.txt ]; then \
|
|
||||||
echo "Installing Python packages from _requirements.txt..."; \
|
|
||||||
"$$HOME/.venvs/pkgmgr/bin/pip" install -r _requirements.txt; \
|
|
||||||
else \
|
|
||||||
echo "No requirements.txt or _requirements.txt found, skipping dependency installation."; \
|
|
||||||
fi; \
|
|
||||||
echo "Ensuring $$HOME/.bashrc and $$HOME/.zshrc exist..."; \
|
|
||||||
touch "$$HOME/.bashrc" "$$HOME/.zshrc"; \
|
|
||||||
echo "Ensuring automatic activation of $$HOME/.venvs/pkgmgr for this user..."; \
|
|
||||||
for rc in "$$HOME/.bashrc" "$$HOME/.zshrc"; do \
|
|
||||||
rc_line='if [ -d "$${HOME}/.venvs/pkgmgr" ]; then . "$${HOME}/.venvs/pkgmgr/bin/activate"; if [ -n "$${PS1:-}" ]; then echo "Global Python virtual environment '\''~/.venvs/pkgmgr'\'' activated."; fi; fi'; \
|
|
||||||
grep -qxF "$${rc_line}" "$$rc" || echo "$${rc_line}" >> "$$rc"; \
|
|
||||||
done; \
|
|
||||||
echo "Arch/Manjaro detection and optional AUR setup..."; \
|
|
||||||
if command -v pacman >/dev/null 2>&1; then \
|
|
||||||
$(MAKE) aur_builder_setup; \
|
|
||||||
else \
|
|
||||||
echo "Not Arch-based (no pacman). Skipping aur_builder/yay setup."; \
|
|
||||||
fi; \
|
|
||||||
echo "Installation complete. Please restart your shell (or 'exec bash' or 'exec zsh') for the changes to take effect."; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# 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
|
|
||||||
@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
|
|
||||||
@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
|
|
||||||
@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 \
|
|
||||||
echo "yay already installed."; \
|
|
||||||
fi
|
|
||||||
@echo "aur_builder/yay setup complete."
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Uninstall target
|
# Uninstall target
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
uninstall:
|
uninstall:
|
||||||
@echo "Removing global user virtual environment if it exists..."
|
@bash scripts/uninstall.sh
|
||||||
@rm -rf "$$HOME/.venvs/pkgmgr"
|
|
||||||
@echo "Cleaning up $$HOME/.bashrc and $$HOME/.zshrc entries..."
|
|
||||||
@for rc in "$$HOME/.bashrc" "$$HOME/.zshrc"; do \
|
|
||||||
sed -i '/\.venvs\/pkgmgr\/bin\/activate"; if \[ -n "\$${PS1:-}" \]; then echo "Global Python virtual environment '\''~\/\.venvs\/pkgmgr'\'' activated."; fi; fi/d' "$$rc"; \
|
|
||||||
done
|
|
||||||
@echo "Uninstallation complete. Please restart your shell (or 'exec bash' or 'exec zsh') for the changes to fully apply."
|
|
||||||
|
|||||||
35
scripts/build/build-image-missing.sh
Executable file
35
scripts/build/build-image-missing.sh
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
source "${SCRIPT_DIR}/resolve-base-image.sh"
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> Building ONLY missing container images"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
for distro in $DISTROS; do
|
||||||
|
IMAGE="package-manager-test-$distro"
|
||||||
|
BASE_IMAGE="$(resolve_base_image "$distro")"
|
||||||
|
|
||||||
|
if docker image inspect "$IMAGE" >/dev/null 2>&1; then
|
||||||
|
echo "[build-missing] Image already exists: $IMAGE (skipping)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
echo "[build-missing] Building missing image: $IMAGE"
|
||||||
|
echo "BASE_IMAGE = $BASE_IMAGE"
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--build-arg BASE_IMAGE="$BASE_IMAGE" \
|
||||||
|
-t "$IMAGE" \
|
||||||
|
.
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> build-missing: Done"
|
||||||
|
echo "============================================================"
|
||||||
17
scripts/build/build-image-no-cache.sh
Executable file
17
scripts/build/build-image-no-cache.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
source "${SCRIPT_DIR}/resolve-base-image.sh"
|
||||||
|
|
||||||
|
for distro in $DISTROS; do
|
||||||
|
base_image="$(resolve_base_image "$distro")"
|
||||||
|
|
||||||
|
echo ">>> Building test image for distro '$distro' with NO CACHE (BASE_IMAGE=$base_image)..."
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--no-cache \
|
||||||
|
--build-arg BASE_IMAGE="$base_image" \
|
||||||
|
-t "package-manager-test-$distro" \
|
||||||
|
.
|
||||||
|
done
|
||||||
16
scripts/build/build-image.sh
Executable file
16
scripts/build/build-image.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
source "${SCRIPT_DIR}/resolve-base-image.sh"
|
||||||
|
|
||||||
|
for distro in $DISTROS; do
|
||||||
|
base_image="$(resolve_base_image "$distro")"
|
||||||
|
|
||||||
|
echo ">>> Building test image for distro '$distro' (BASE_IMAGE=$base_image)..."
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--build-arg BASE_IMAGE="$base_image" \
|
||||||
|
-t "package-manager-test-$distro" \
|
||||||
|
.
|
||||||
|
done
|
||||||
18
scripts/build/resolve-base-image.sh
Executable file
18
scripts/build/resolve-base-image.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
resolve_base_image() {
|
||||||
|
local distro="$1"
|
||||||
|
|
||||||
|
case "$distro" in
|
||||||
|
arch) echo "$BASE_IMAGE_ARCH" ;;
|
||||||
|
debian) echo "$BASE_IMAGE_DEBIAN" ;;
|
||||||
|
ubuntu) echo "$BASE_IMAGE_UBUNTU" ;;
|
||||||
|
fedora) echo "$BASE_IMAGE_FEDORA" ;;
|
||||||
|
centos) echo "$BASE_IMAGE_CENTOS" ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: Unknown distro '$distro'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
echo "[entry] Using /src as working tree for package-manager..."
|
|
||||||
cd /src
|
|
||||||
|
|
||||||
# Optional: altes Paket entfernen
|
|
||||||
echo "[entry] Removing existing 'package-manager' Arch package (if installed)..."
|
|
||||||
pacman -Rns --noconfirm package-manager || true
|
|
||||||
|
|
||||||
# Build-Owner richtig setzen (falls /src vom Host kommt)
|
|
||||||
echo "[entry] Fixing ownership of /src for user 'builder'..."
|
|
||||||
chown -R builder:builder /src
|
|
||||||
|
|
||||||
echo "[entry] Rebuilding Arch package from /src as user 'builder'..."
|
|
||||||
su builder -c "cd /src && makepkg -s --noconfirm --clean"
|
|
||||||
|
|
||||||
echo "[entry] Installing freshly built package-manager-*.pkg.tar.*..."
|
|
||||||
pacman -U --noconfirm /src/package-manager-*.pkg.tar.*
|
|
||||||
|
|
||||||
echo "[entry] Handing off to pkgmgr with args: $*"
|
|
||||||
exec pkgmgr "$@"
|
|
||||||
43
scripts/docker/entry.sh
Executable file
43
scripts/docker/entry.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
echo "[docker] Starting package-manager container"
|
||||||
|
|
||||||
|
# Distro-Info nur für Logging
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/os-release
|
||||||
|
echo "[docker] Detected distro: ${ID:-unknown} (like: ${ID_LIKE:-})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wir arbeiten immer aus /src (vom Host gemountet)
|
||||||
|
echo "[docker] Using /src as working directory"
|
||||||
|
cd /src
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# DEV-Mode: aus dem aktuellen /src heraus Paket bauen/installieren
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
if [[ "${PKGMGR_DEV:-0}" == "1" ]]; then
|
||||||
|
echo "[docker] DEV mode enabled (PKGMGR_DEV=1)"
|
||||||
|
echo "[docker] Rebuilding package-manager from /src via scripts/installation/run-package.sh..."
|
||||||
|
|
||||||
|
if [[ -x scripts/installation/run-package.sh ]]; then
|
||||||
|
bash scripts/installation/run-package.sh
|
||||||
|
else
|
||||||
|
echo "[docker] ERROR: scripts/installation/run-package.sh not found or not executable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Hand-off zu pkgmgr / beliebigem Kommando
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
echo "[docker] No arguments provided. Showing pkgmgr help..."
|
||||||
|
exec pkgmgr --help
|
||||||
|
else
|
||||||
|
echo "[docker] Executing command: $*"
|
||||||
|
exec "$@"
|
||||||
|
fi
|
||||||
222
scripts/init-nix.sh
Normal file → Executable file
222
scripts/init-nix.sh
Normal file → Executable file
@@ -1,44 +1,208 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
echo ">>> Initializing Nix environment for package-manager..."
|
echo "[init-nix] Starting Nix initialization..."
|
||||||
|
|
||||||
# 1. /nix store
|
# ---------------------------------------------------------------------------
|
||||||
if [ ! -d /nix ]; then
|
# Helper: detect whether we are inside a container (Docker/Podman/etc.)
|
||||||
echo ">>> Creating /nix store directory"
|
# ---------------------------------------------------------------------------
|
||||||
mkdir -m 0755 /nix
|
is_container() {
|
||||||
chown root:root /nix
|
# Docker / Podman markers
|
||||||
|
if [[ -f /.dockerenv ]] || [[ -f /run/.containerenv ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# cgroup hints
|
||||||
|
if grep -qiE 'docker|container|podman|lxc' /proc/1/cgroup 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Environment variable used by some runtimes
|
||||||
|
if [[ -n "${container:-}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Helper: ensure Nix binaries are on PATH (multi-user or single-user)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
ensure_nix_on_path() {
|
||||||
|
# Multi-user profile (daemon install)
|
||||||
|
if [[ -x /nix/var/nix/profiles/default/bin/nix ]]; then
|
||||||
|
export PATH="/nix/var/nix/profiles/default/bin:${PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Single-user profile (current user)
|
||||||
|
if [[ -x "${HOME}/.nix-profile/bin/nix" ]]; then
|
||||||
|
export PATH="${HOME}/.nix-profile/bin:${PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Single-user profile for dedicated "nix" user (container case)
|
||||||
|
if [[ -x /home/nix/.nix-profile/bin/nix ]]; then
|
||||||
|
export PATH="/home/nix/.nix-profile/bin:${PATH}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Fast path: Nix already available
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if command -v nix >/dev/null 2>&1; then
|
||||||
|
echo "[init-nix] Nix already available on PATH: $(command -v nix)"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 2. Enable nix-daemon if available
|
ensure_nix_on_path
|
||||||
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files | grep -q nix-daemon.service; then
|
|
||||||
echo ">>> Enabling nix-daemon.service"
|
if command -v nix >/dev/null 2>&1; then
|
||||||
systemctl enable --now nix-daemon.service 2>/dev/null || true
|
echo "[init-nix] Nix found after adjusting PATH: $(command -v nix)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[init-nix] Nix not found, starting installation logic..."
|
||||||
|
|
||||||
|
IN_CONTAINER=0
|
||||||
|
if is_container; then
|
||||||
|
IN_CONTAINER=1
|
||||||
|
echo "[init-nix] Detected container environment."
|
||||||
else
|
else
|
||||||
echo ">>> Warning: nix-daemon.service not found or systemctl not available."
|
echo "[init-nix] No container detected."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. Ensure nix-users group
|
# ---------------------------------------------------------------------------
|
||||||
if ! getent group nix-users >/dev/null 2>&1; then
|
# Container + root: install Nix as dedicated "nix" user (single-user)
|
||||||
echo ">>> Creating nix-users group"
|
# ---------------------------------------------------------------------------
|
||||||
groupadd -r nix-users 2>/dev/null || true
|
if [[ "${IN_CONTAINER}" -eq 1 && "${EUID:-0}" -eq 0 ]]; then
|
||||||
fi
|
echo "[init-nix] Running as root inside a container – using dedicated 'nix' user."
|
||||||
|
|
||||||
# 4. Add users to nix-users (best-effort)
|
# Ensure nixbld group (required by Nix)
|
||||||
if command -v loginctl >/dev/null 2>&1; then
|
if ! getent group nixbld >/dev/null 2>&1; then
|
||||||
for user in $(loginctl list-users | awk 'NR>1 {print $2}'); do
|
echo "[init-nix] Creating group 'nixbld'..."
|
||||||
if id "$user" >/dev/null 2>&1; then
|
groupadd -r nixbld
|
||||||
echo ">>> Adding user '$user' to nix-users"
|
fi
|
||||||
usermod -aG nix-users "$user" 2>/dev/null || true
|
|
||||||
|
# Ensure Nix build users (nixbld1..nixbld10) as members of nixbld
|
||||||
|
for i in $(seq 1 10); do
|
||||||
|
if ! id "nixbld$i" >/dev/null 2>&1; then
|
||||||
|
echo "[init-nix] Creating build user nixbld$i..."
|
||||||
|
# -r: system account, -g: primary group, -G: supplementary (ensures membership is listed)
|
||||||
|
useradd -r -g nixbld -G nixbld -s /usr/sbin/nologin "nixbld$i"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
elif command -v logname >/dev/null 2>&1; then
|
|
||||||
USERNAME="$(logname 2>/dev/null || true)"
|
# Ensure "nix" user (home at /home/nix)
|
||||||
if [ -n "$USERNAME" ] && id "$USERNAME" >/dev/null 2>&1; then
|
if ! id nix >/dev/null 2>&1; then
|
||||||
echo ">>> Adding user '$USERNAME' to nix-users"
|
echo "[init-nix] Creating user 'nix'..."
|
||||||
usermod -aG nix-users "$USERNAME" 2>/dev/null || true
|
useradd -m -r -g nixbld -s /usr/bin/bash nix
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create /nix directory and hand it to nix user (prevents installer sudo prompt)
|
||||||
|
if [[ ! -d /nix ]]; then
|
||||||
|
echo "[init-nix] Creating /nix with owner nix:nixbld..."
|
||||||
|
mkdir -m 0755 /nix
|
||||||
|
chown nix:nixbld /nix
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run Nix single-user installer as "nix"
|
||||||
|
echo "[init-nix] Installing Nix as user 'nix' (single-user, --no-daemon)..."
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
sudo -u nix bash -lc 'sh <(curl -L https://nixos.org/nix/install) --no-daemon'
|
||||||
|
else
|
||||||
|
su - nix -c 'sh <(curl -L https://nixos.org/nix/install) --no-daemon'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# After installation, expose nix to root via PATH and symlink
|
||||||
|
ensure_nix_on_path
|
||||||
|
|
||||||
|
if [[ -x /home/nix/.nix-profile/bin/nix ]]; then
|
||||||
|
if [[ ! -e /usr/local/bin/nix ]]; then
|
||||||
|
echo "[init-nix] Creating /usr/local/bin/nix symlink -> /home/nix/.nix-profile/bin/nix"
|
||||||
|
ln -s /home/nix/.nix-profile/bin/nix /usr/local/bin/nix
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_nix_on_path
|
||||||
|
|
||||||
|
if command -v nix >/dev/null 2>&1; then
|
||||||
|
echo "[init-nix] Nix successfully installed (container mode) at: $(command -v nix)"
|
||||||
|
else
|
||||||
|
echo "[init-nix] WARNING: Nix installation finished in container, but 'nix' is still not on PATH."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally add PATH hints to /etc/profile (best effort)
|
||||||
|
if [[ -w /etc/profile ]]; then
|
||||||
|
if ! grep -q 'Nix profiles' /etc/profile 2>/dev/null; then
|
||||||
|
cat <<'EOF' >> /etc/profile
|
||||||
|
|
||||||
|
# Nix profiles (added by package-manager init-nix.sh)
|
||||||
|
if [ -d /nix/var/nix/profiles/default/bin ]; then
|
||||||
|
PATH="/nix/var/nix/profiles/default/bin:$PATH"
|
||||||
|
fi
|
||||||
|
if [ -d "$HOME/.nix-profile/bin" ]; then
|
||||||
|
PATH="$HOME/.nix-profile/bin:$PATH"
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
echo "[init-nix] Appended Nix PATH setup to /etc/profile (container mode)."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[init-nix] Nix initialization complete (container root mode)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Non-container or non-root container: normal installer paths
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if [[ "${IN_CONTAINER}" -eq 0 ]]; then
|
||||||
|
# Real host
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "[init-nix] Host with systemd – using multi-user install (--daemon)."
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --daemon
|
||||||
|
else
|
||||||
|
if [[ "${EUID:-0}" -eq 0 ]]; then
|
||||||
|
echo "[init-nix] WARNING: Running as root without systemd on host."
|
||||||
|
echo "[init-nix] Falling back to single-user install (--no-daemon), but this is not recommended."
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --no-daemon
|
||||||
|
else
|
||||||
|
echo "[init-nix] Non-root host without systemd – using single-user install (--no-daemon)."
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --no-daemon
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Container, but not root (rare)
|
||||||
|
echo "[init-nix] Container as non-root user – using single-user install (--no-daemon)."
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --no-daemon
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# After installation: fix PATH (runtime + shell profiles)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
ensure_nix_on_path
|
||||||
|
|
||||||
|
if ! command -v nix >/dev/null 2>&1; then
|
||||||
|
echo "[init-nix] WARNING: Nix installation finished, but 'nix' is still not on PATH."
|
||||||
|
echo "[init-nix] You may need to source your shell profile manually."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[init-nix] Nix successfully installed at: $(command -v nix)"
|
||||||
|
|
||||||
|
# Update global /etc/profile if writable (helps especially on minimal systems)
|
||||||
|
if [[ -w /etc/profile ]]; then
|
||||||
|
if ! grep -q 'Nix profiles' /etc/profile 2>/dev/null; then
|
||||||
|
cat <<'EOF' >> /etc/profile
|
||||||
|
|
||||||
|
# Nix profiles (added by package-manager init-nix.sh)
|
||||||
|
if [ -d /nix/var/nix/profiles/default/bin ]; then
|
||||||
|
PATH="/nix/var/nix/profiles/default/bin:$PATH"
|
||||||
|
fi
|
||||||
|
if [ -d "$HOME/.nix-profile/bin" ]; then
|
||||||
|
PATH="$HOME/.nix-profile/bin:$PATH"
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
echo "[init-nix] Appended Nix PATH setup to /etc/profile"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ">>> Nix initialization complete."
|
echo "[init-nix] Nix initialization complete."
|
||||||
echo ">>> You may need to log out and log back in to activate group membership."
|
|
||||||
|
|||||||
54
scripts/installation/arch/aur-builder-setup.sh
Executable file
54
scripts/installation/arch/aur-builder-setup.sh
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# aur-builder-setup.sh
|
||||||
|
#
|
||||||
|
# Setup helper for an 'aur_builder' user and yay on Arch-based
|
||||||
|
# systems. Intended for host usage and can also be used in
|
||||||
|
# containers if desired.
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Checking for pacman..."
|
||||||
|
if ! command -v pacman >/dev/null 2>&1; then
|
||||||
|
echo "[aur-builder-setup] pacman not found – this is not an Arch-based system. Skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${EUID:-0}" -ne 0 ]]; then
|
||||||
|
ROOT_CMD="sudo"
|
||||||
|
else
|
||||||
|
ROOT_CMD=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Installing base-devel, git, sudo..."
|
||||||
|
${ROOT_CMD} pacman -Syu --noconfirm
|
||||||
|
${ROOT_CMD} pacman -S --needed --noconfirm base-devel git sudo
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Ensuring aur_builder group/user..."
|
||||||
|
if ! getent group aur_builder >/dev/null 2>&1; then
|
||||||
|
${ROOT_CMD} groupadd -r aur_builder
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! id -u aur_builder >/dev/null 2>&1; then
|
||||||
|
${ROOT_CMD} useradd -m -r -g aur_builder -s /bin/bash aur_builder
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Configuring sudoers for aur_builder..."
|
||||||
|
${ROOT_CMD} bash -c "echo '%aur_builder ALL=(ALL) NOPASSWD: /usr/bin/pacman' > /etc/sudoers.d/aur_builder"
|
||||||
|
${ROOT_CMD} chmod 0440 /etc/sudoers.d/aur_builder
|
||||||
|
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
RUN_AS_AUR=(sudo -u aur_builder bash -lc)
|
||||||
|
else
|
||||||
|
RUN_AS_AUR=(su - aur_builder -c)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Ensuring yay is installed for aur_builder..."
|
||||||
|
if ! "${RUN_AS_AUR[@]}" 'command -v yay >/dev/null 2>&1'; then
|
||||||
|
"${RUN_AS_AUR[@]}" 'cd ~ && rm -rf yay && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si --noconfirm'
|
||||||
|
else
|
||||||
|
echo "[aur-builder-setup] yay already installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[aur-builder-setup] Done."
|
||||||
30
scripts/installation/arch/dependencies.sh
Executable file
30
scripts/installation/arch/dependencies.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
echo "[arch/dependencies] Installing Arch build dependencies..."
|
||||||
|
|
||||||
|
pacman -Syu --noconfirm
|
||||||
|
pacman -S --noconfirm --needed \
|
||||||
|
base-devel \
|
||||||
|
git \
|
||||||
|
rsync \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
xz
|
||||||
|
|
||||||
|
pacman -Scc --noconfirm
|
||||||
|
|
||||||
|
# Always run AUR builder setup for Arch
|
||||||
|
AUR_SETUP="${SCRIPT_DIR}/aur-builder-setup.sh"
|
||||||
|
|
||||||
|
if [[ ! -x "${AUR_SETUP}" ]]; then
|
||||||
|
echo "[arch/dependencies] ERROR: AUR builder setup script not found or not executable: ${AUR_SETUP}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[arch/dependencies] Running AUR builder setup..."
|
||||||
|
bash "${AUR_SETUP}"
|
||||||
|
|
||||||
|
echo "[arch/dependencies] Done."
|
||||||
19
scripts/installation/arch/package.sh
Executable file
19
scripts/installation/arch/package.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[arch/package] Building Arch package (makepkg --nodeps)..."
|
||||||
|
|
||||||
|
if id aur_builder >/dev/null 2>&1; then
|
||||||
|
echo "[arch/package] Using 'aur_builder' user for makepkg..."
|
||||||
|
chown -R aur_builder:aur_builder "$(pwd)"
|
||||||
|
su aur_builder -c "cd '$(pwd)' && rm -f package-manager-*.pkg.tar.* && makepkg --noconfirm --clean --nodeps"
|
||||||
|
else
|
||||||
|
echo "[arch/package] WARNING: user 'aur_builder' not found, running makepkg as current user..."
|
||||||
|
rm -f package-manager-*.pkg.tar.*
|
||||||
|
makepkg --noconfirm --clean --nodeps
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[arch/package] Installing generated Arch package..."
|
||||||
|
pacman -U --noconfirm package-manager-*.pkg.tar.*
|
||||||
|
|
||||||
|
echo "[arch/package] Done."
|
||||||
20
scripts/installation/centos/dependencies.sh
Executable file
20
scripts/installation/centos/dependencies.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[centos/dependencies] Installing CentOS build dependencies..."
|
||||||
|
|
||||||
|
dnf -y update
|
||||||
|
dnf -y install \
|
||||||
|
git \
|
||||||
|
rsync \
|
||||||
|
rpm-build \
|
||||||
|
make \
|
||||||
|
gcc \
|
||||||
|
bash \
|
||||||
|
curl-minimal \
|
||||||
|
ca-certificates \
|
||||||
|
xz
|
||||||
|
|
||||||
|
dnf clean all
|
||||||
|
|
||||||
|
echo "[centos/dependencies] Done."
|
||||||
46
scripts/installation/centos/package.sh
Executable file
46
scripts/installation/centos/package.sh
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[centos/package] Setting up rpmbuild directories..."
|
||||||
|
mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
|
||||||
|
echo "[centos/package] Extracting version from package-manager.spec..."
|
||||||
|
version="$(grep -E '^Version:' package-manager.spec | awk '{print $2}')"
|
||||||
|
if [[ -z "${version}" ]]; then
|
||||||
|
echo "ERROR: Version missing!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
srcdir="package-manager-${version}"
|
||||||
|
echo "[centos/package] Preparing source tree: ${srcdir}"
|
||||||
|
rm -rf "/tmp/${srcdir}"
|
||||||
|
mkdir -p "/tmp/${srcdir}"
|
||||||
|
cp -a . "/tmp/${srcdir}/"
|
||||||
|
|
||||||
|
echo "[centos/package] Creating source tarball..."
|
||||||
|
tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}"
|
||||||
|
|
||||||
|
echo "[centos/package] Copying SPEC..."
|
||||||
|
cp package-manager.spec /root/rpmbuild/SPECS/
|
||||||
|
|
||||||
|
echo "[centos/package] Running rpmbuild..."
|
||||||
|
cd /root/rpmbuild/SPECS
|
||||||
|
rpmbuild -bb package-manager.spec
|
||||||
|
|
||||||
|
echo "[centos/package] Installing generated RPM (local, offline, forced reinstall)..."
|
||||||
|
rpm_path="$(find /root/rpmbuild/RPMS -name 'package-manager-*.rpm' | head -n1)"
|
||||||
|
if [[ -z "${rpm_path}" ]]; then
|
||||||
|
echo "ERROR: RPM not found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Forced reinstall, always overwrite old version
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
echo "[centos/package] Forcing reinstall via rpm -Uvh --replacepkgs --force"
|
||||||
|
rpm -Uvh --replacepkgs --force "${rpm_path}"
|
||||||
|
|
||||||
|
# Keep structure: remove temp directory afterwards
|
||||||
|
rm -rf "/tmp/${srcdir}"
|
||||||
|
|
||||||
|
echo "[centos/package] Done."
|
||||||
20
scripts/installation/debian/dependencies.sh
Executable file
20
scripts/installation/debian/dependencies.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[debian/dependencies] Installing Debian build dependencies..."
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
debhelper \
|
||||||
|
dpkg-dev \
|
||||||
|
git \
|
||||||
|
rsync \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
xz-utils
|
||||||
|
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
echo "[debian/dependencies] Done."
|
||||||
13
scripts/installation/debian/package.sh
Executable file
13
scripts/installation/debian/package.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[debian/package] Building Debian package..."
|
||||||
|
|
||||||
|
dpkg-buildpackage -us -uc -b
|
||||||
|
|
||||||
|
echo "[debian/package] Installing generated DEB package..."
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y ./../package-manager_*.deb
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
echo "[debian/package] Done."
|
||||||
21
scripts/installation/fedora/dependencies.sh
Executable file
21
scripts/installation/fedora/dependencies.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[fedora/dependencies] Installing Fedora build dependencies..."
|
||||||
|
|
||||||
|
dnf -y update
|
||||||
|
dnf -y install \
|
||||||
|
git \
|
||||||
|
rsync \
|
||||||
|
rpm-build \
|
||||||
|
make \
|
||||||
|
gcc \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
python3 \
|
||||||
|
xz
|
||||||
|
|
||||||
|
dnf clean all
|
||||||
|
|
||||||
|
echo "[fedora/dependencies] Done."
|
||||||
43
scripts/installation/fedora/package.sh
Executable file
43
scripts/installation/fedora/package.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[fedora/package] Setting up rpmbuild directories..."
|
||||||
|
mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
|
||||||
|
echo "[fedora/package] Extracting version from package-manager.spec..."
|
||||||
|
version="$(grep -E '^Version:' package-manager.spec | awk '{print $2}')"
|
||||||
|
if [[ -z "${version}" ]]; then
|
||||||
|
echo "ERROR: Version missing!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
srcdir="package-manager-${version}"
|
||||||
|
echo "[fedora/package] Preparing source tree: ${srcdir}"
|
||||||
|
rm -rf "/tmp/${srcdir}"
|
||||||
|
mkdir -p "/tmp/${srcdir}"
|
||||||
|
cp -a . "/tmp/${srcdir}/"
|
||||||
|
|
||||||
|
echo "[fedora/package] Creating source tarball..."
|
||||||
|
tar czf "/root/rpmbuild/SOURCES/${srcdir}.tar.gz" -C /tmp "${srcdir}"
|
||||||
|
|
||||||
|
echo "[fedora/package] Copying SPEC..."
|
||||||
|
cp package-manager.spec /root/rpmbuild/SPECS/
|
||||||
|
|
||||||
|
echo "[fedora/package] Running rpmbuild..."
|
||||||
|
cd /root/rpmbuild/SPECS
|
||||||
|
rpmbuild -bb package-manager.spec
|
||||||
|
|
||||||
|
echo "[fedora/package] Installing generated RPM (local, offline, forced reinstall)..."
|
||||||
|
rpm_path="$(find /root/rpmbuild/RPMS -name 'package-manager-*.rpm' | head -n1)"
|
||||||
|
if [[ -z "${rpm_path}" ]]; then
|
||||||
|
echo "ERROR: RPM not found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always force (re)install the freshly built RPM, even if the same
|
||||||
|
# version is already installed. This is what we want in dev/test containers.
|
||||||
|
rpm -Uvh --replacepkgs --force "${rpm_path}"
|
||||||
|
|
||||||
|
rm -rf "/tmp/${srcdir}"
|
||||||
|
|
||||||
|
echo "[fedora/package] Done."
|
||||||
12
scripts/installation/lib.sh
Executable file
12
scripts/installation/lib.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
detect_os_id() {
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/os-release
|
||||||
|
echo "${ID:-unknown}"
|
||||||
|
else
|
||||||
|
echo "unknown"
|
||||||
|
fi
|
||||||
|
}
|
||||||
89
scripts/installation/main.sh
Executable file
89
scripts/installation/main.sh
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# main.sh
|
||||||
|
#
|
||||||
|
# Developer setup entrypoint.
|
||||||
|
#
|
||||||
|
# Responsibilities:
|
||||||
|
# - If inside a Nix shell (IN_NIX_SHELL=1):
|
||||||
|
# * Skip venv creation and dependency installation
|
||||||
|
# * Run `python3 main.py install`
|
||||||
|
# - Otherwise:
|
||||||
|
# * Create ~/.venvs/pkgmgr virtual environment if missing
|
||||||
|
# * Install Python dependencies into that venv
|
||||||
|
# * Append auto-activation to ~/.bashrc and ~/.zshrc
|
||||||
|
# * Run `main.py install` using the venv Python
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
echo "[installation/main] Starting developer setup..."
|
||||||
|
|
||||||
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
cd "${PROJECT_ROOT}"
|
||||||
|
|
||||||
|
VENV_DIR="${HOME}/.venvs/pkgmgr"
|
||||||
|
RC_LINE='if [ -d "${HOME}/.venvs/pkgmgr" ]; then . "${HOME}/.venvs/pkgmgr/bin/activate"; if [ -n "${PS1:-}" ]; then echo "Global Python virtual environment '\''~/.venvs/pkgmgr'\'' activated."; fi; fi'
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Nix shell mode: do not touch venv, only run main.py install
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
if [[ -n "${IN_NIX_SHELL:-}" ]]; then
|
||||||
|
echo "[installation/main] Nix shell detected (IN_NIX_SHELL=1)."
|
||||||
|
echo "[installation/main] Skipping virtualenv creation and dependency installation."
|
||||||
|
echo "[installation/main] Running main.py install via system python3..."
|
||||||
|
python3 main.py install
|
||||||
|
echo "[installation/main] Developer setup finished (Nix mode)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Normal host mode: create/update venv and run main.py install
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
echo "[installation/main] Ensuring main.py is executable..."
|
||||||
|
chmod +x main.py || true
|
||||||
|
|
||||||
|
echo "[installation/main] Ensuring global virtualenv root: ${HOME}/.venvs"
|
||||||
|
mkdir -p "${HOME}/.venvs"
|
||||||
|
|
||||||
|
if [[ ! -d "${VENV_DIR}" ]]; then
|
||||||
|
echo "[installation/main] Creating virtual environment at: ${VENV_DIR}"
|
||||||
|
python3 -m venv "${VENV_DIR}"
|
||||||
|
else
|
||||||
|
echo "[installation/main] Virtual environment already exists at: ${VENV_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[installation/main] Installing Python tooling into venv..."
|
||||||
|
"${VENV_DIR}/bin/python" -m ensurepip --upgrade
|
||||||
|
"${VENV_DIR}/bin/pip" install --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
if [[ -f "requirements.txt" ]]; then
|
||||||
|
echo "[installation/main] Installing dependencies from requirements.txt..."
|
||||||
|
"${VENV_DIR}/bin/pip" install -r requirements.txt
|
||||||
|
elif [[ -f "_requirements.txt" ]]; then
|
||||||
|
echo "[installation/main] Installing dependencies from _requirements.txt..."
|
||||||
|
"${VENV_DIR}/bin/pip" install -r _requirements.txt
|
||||||
|
else
|
||||||
|
echo "[installation/main] No requirements.txt or _requirements.txt found. Skipping dependency installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[installation/main] Ensuring ~/.bashrc and ~/.zshrc exist..."
|
||||||
|
touch "${HOME}/.bashrc" "${HOME}/.zshrc"
|
||||||
|
|
||||||
|
echo "[installation/main] Ensuring venv auto-activation is present in shell rc files..."
|
||||||
|
for rc in "${HOME}/.bashrc" "${HOME}/.zshrc"; do
|
||||||
|
if ! grep -qxF "${RC_LINE}" "$rc"; then
|
||||||
|
echo "${RC_LINE}" >> "$rc"
|
||||||
|
echo "[installation/main] Appended auto-activation to $rc"
|
||||||
|
else
|
||||||
|
echo "[installation/main] Auto-activation already present in $rc"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[installation/main] Running main.py install via venv Python..."
|
||||||
|
"${VENV_DIR}/bin/python" main.py install
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[installation/main] Developer setup complete."
|
||||||
|
echo "Restart your shell (or run 'exec bash' or 'exec zsh') to activate the environment."
|
||||||
29
scripts/installation/run-dependencies.sh
Executable file
29
scripts/installation/run-dependencies.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "${SCRIPT_DIR}/lib.sh"
|
||||||
|
|
||||||
|
OS_ID="$(detect_os_id)"
|
||||||
|
|
||||||
|
echo "[run-dependencies] Detected OS: ${OS_ID}"
|
||||||
|
|
||||||
|
case "${OS_ID}" in
|
||||||
|
arch|debian|ubuntu|fedora|centos)
|
||||||
|
DEP_SCRIPT="${SCRIPT_DIR}/${OS_ID}/dependencies.sh"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "[run-dependencies] Unsupported OS: ${OS_ID}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ ! -f "${DEP_SCRIPT}" ]]; then
|
||||||
|
echo "[run-dependencies] Dependency script not found: ${DEP_SCRIPT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[run-dependencies] Executing: ${DEP_SCRIPT}"
|
||||||
|
exec bash "${DEP_SCRIPT}"
|
||||||
29
scripts/installation/run-package.sh
Executable file
29
scripts/installation/run-package.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "${SCRIPT_DIR}/lib.sh"
|
||||||
|
|
||||||
|
OS_ID="$(detect_os_id)"
|
||||||
|
|
||||||
|
echo "[run-package] Detected OS: ${OS_ID}"
|
||||||
|
|
||||||
|
case "${OS_ID}" in
|
||||||
|
arch|debian|ubuntu|fedora|centos)
|
||||||
|
PKG_SCRIPT="${SCRIPT_DIR}/${OS_ID}/package.sh"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "[run-package] Unsupported OS: ${OS_ID}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ ! -f "${PKG_SCRIPT}" ]]; then
|
||||||
|
echo "[run-package] Package script not found: ${PKG_SCRIPT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[run-package] Executing: ${PKG_SCRIPT}"
|
||||||
|
exec bash "${PKG_SCRIPT}"
|
||||||
22
scripts/installation/ubuntu/dependencies.sh
Executable file
22
scripts/installation/ubuntu/dependencies.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[ubuntu/dependencies] Installing Ubuntu build dependencies..."
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
debhelper \
|
||||||
|
dpkg-dev \
|
||||||
|
git \
|
||||||
|
tzdata \
|
||||||
|
lsb-release \
|
||||||
|
rsync \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
xz-utils
|
||||||
|
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
echo "[ubuntu/dependencies] Done."
|
||||||
13
scripts/installation/ubuntu/package.sh
Executable file
13
scripts/installation/ubuntu/package.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[ubuntu/package] Building Ubuntu (Debian-style) package..."
|
||||||
|
|
||||||
|
dpkg-buildpackage -us -uc -b
|
||||||
|
|
||||||
|
echo "[ubuntu/package] Installing generated DEB package..."
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y ./../package-manager_*.deb
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
echo "[ubuntu/package] Done."
|
||||||
32
scripts/pkgmgr-wrapper.sh
Normal file → Executable file
32
scripts/pkgmgr-wrapper.sh
Normal file → Executable file
@@ -1,10 +1,40 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Ensure NIX_CONFIG has our defaults if not already set
|
||||||
if [[ -z "${NIX_CONFIG:-}" ]]; then
|
if [[ -z "${NIX_CONFIG:-}" ]]; then
|
||||||
export NIX_CONFIG="experimental-features = nix-command flakes"
|
export NIX_CONFIG="experimental-features = nix-command flakes"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FLAKE_DIR="/usr/lib/package-manager"
|
FLAKE_DIR="/usr/lib/package-manager"
|
||||||
|
|
||||||
exec nix run "${FLAKE_DIR}#pkgmgr" -- "$@"
|
# ------------------------------------------------------------
|
||||||
|
# Try to ensure that "nix" is on PATH
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
if ! command -v nix >/dev/null 2>&1; then
|
||||||
|
# Common locations for Nix installations
|
||||||
|
CANDIDATES=(
|
||||||
|
"/nix/var/nix/profiles/default/bin/nix"
|
||||||
|
"${HOME:-/root}/.nix-profile/bin/nix"
|
||||||
|
)
|
||||||
|
|
||||||
|
for candidate in "${CANDIDATES[@]}"; do
|
||||||
|
if [[ -x "$candidate" ]]; then
|
||||||
|
# Prepend the directory of the candidate to PATH
|
||||||
|
PATH="$(dirname "$candidate"):${PATH}"
|
||||||
|
export PATH
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Primary (and only) path: use Nix flake if available
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
if command -v nix >/dev/null 2>&1; then
|
||||||
|
exec nix run "${FLAKE_DIR}#pkgmgr" -- "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[pkgmgr-wrapper] ERROR: 'nix' binary not found on PATH."
|
||||||
|
echo "[pkgmgr-wrapper] Nix is required to run pkgmgr (no Python fallback)."
|
||||||
|
exit 1
|
||||||
|
|||||||
12
scripts/test/test-common.sh
Executable file
12
scripts/test/test-common.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
detect_container_distro() {
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/os-release
|
||||||
|
echo "${ID:-unknown}"
|
||||||
|
else
|
||||||
|
echo "unknown"
|
||||||
|
fi
|
||||||
|
}
|
||||||
40
scripts/test/test-container.sh
Executable file
40
scripts/test/test-container.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> Running sanity test: verifying test containers start"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
for distro in $DISTROS; do
|
||||||
|
IMAGE="package-manager-test-$distro"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
echo ">>> Testing container: $IMAGE"
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
|
||||||
|
echo "[test-container] Running: docker run --rm --entrypoint pkgmgr $IMAGE --help"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Run the command and capture the output
|
||||||
|
if OUTPUT=$(docker run --rm \
|
||||||
|
-e PKGMGR_DEV=1 \
|
||||||
|
-v "$(pwd):/src" \
|
||||||
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
|
"$IMAGE" 2>&1); then
|
||||||
|
echo "$OUTPUT"
|
||||||
|
echo
|
||||||
|
echo "[test-container] SUCCESS: $IMAGE responded to 'pkgmgr --help'"
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "$OUTPUT"
|
||||||
|
echo
|
||||||
|
echo "[test-container] ERROR: $IMAGE failed to run 'pkgmgr --help'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> All containers passed the sanity check"
|
||||||
|
echo "============================================================"
|
||||||
56
scripts/test/test-e2e.sh
Executable file
56
scripts/test/test-e2e.sh
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo ">>> Running E2E tests in all distros: $DISTROS"
|
||||||
|
|
||||||
|
for distro in $DISTROS; do
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> Running E2E tests: $distro"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
MOUNT_NIX=""
|
||||||
|
if [[ "$distro" == "arch" ]]; then
|
||||||
|
MOUNT_NIX="-v pkgmgr_nix_store:/nix"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "$(pwd):/src" \
|
||||||
|
$MOUNT_NIX \
|
||||||
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
|
-e PKGMGR_DEV=1 \
|
||||||
|
--workdir /src \
|
||||||
|
--entrypoint bash \
|
||||||
|
"package-manager-test-$distro" \
|
||||||
|
-c '
|
||||||
|
set -e;
|
||||||
|
|
||||||
|
if [ -f /etc/os-release ]; then
|
||||||
|
. /etc/os-release;
|
||||||
|
fi;
|
||||||
|
|
||||||
|
echo "Running tests inside distro: $ID";
|
||||||
|
|
||||||
|
# Try to load nix environment
|
||||||
|
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
|
||||||
|
|
||||||
|
PATH="/nix/var/nix/profiles/default/bin:$HOME/.nix-profile/bin:$PATH";
|
||||||
|
|
||||||
|
command -v nix >/dev/null || {
|
||||||
|
echo "ERROR: nix not found.";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
git config --global --add safe.directory /src || true;
|
||||||
|
|
||||||
|
nix develop .#default --no-write-lock-file -c \
|
||||||
|
python3 -m unittest discover \
|
||||||
|
-s /src/tests/e2e \
|
||||||
|
-p "test_*.py";
|
||||||
|
'
|
||||||
|
done
|
||||||
23
scripts/test/test-integration.sh
Executable file
23
scripts/test/test-integration.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> Running INTEGRATION tests in Arch container"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "$(pwd):/src" \
|
||||||
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
|
--workdir /src \
|
||||||
|
-e PKGMGR_DEV=1 \
|
||||||
|
--entrypoint bash \
|
||||||
|
"package-manager-test-arch" \
|
||||||
|
-c '
|
||||||
|
set -e;
|
||||||
|
git config --global --add safe.directory /src || true;
|
||||||
|
nix develop .#default --no-write-lock-file -c \
|
||||||
|
python -m unittest discover \
|
||||||
|
-s tests/integration \
|
||||||
|
-t /src \
|
||||||
|
-p "test_*.py";
|
||||||
|
'
|
||||||
23
scripts/test/test-unit.sh
Executable file
23
scripts/test/test-unit.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo ">>> Running UNIT tests in Arch container"
|
||||||
|
echo "============================================================"
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "$(pwd):/src" \
|
||||||
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
|
--workdir /src \
|
||||||
|
-e PKGMGR_DEV=1 \
|
||||||
|
--entrypoint bash \
|
||||||
|
"package-manager-test-arch" \
|
||||||
|
-c '
|
||||||
|
set -e;
|
||||||
|
git config --global --add safe.directory /src || true;
|
||||||
|
nix develop .#default --no-write-lock-file -c \
|
||||||
|
python -m unittest discover \
|
||||||
|
-s tests/unit \
|
||||||
|
-t /src \
|
||||||
|
-p "test_*.py";
|
||||||
|
'
|
||||||
34
scripts/uninstall.sh
Executable file
34
scripts/uninstall.sh
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "[uninstall] Starting pkgmgr uninstall..."
|
||||||
|
|
||||||
|
VENV_DIR="${HOME}/.venvs/pkgmgr"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Remove virtual environment
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
echo "[uninstall] Removing global user virtual environment if it exists..."
|
||||||
|
if [[ -d "$VENV_DIR" ]]; then
|
||||||
|
rm -rf "$VENV_DIR"
|
||||||
|
echo "[uninstall] Removed: $VENV_DIR"
|
||||||
|
else
|
||||||
|
echo "[uninstall] No venv found at: $VENV_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Remove auto-activation lines from shell RC files
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
RC_PATTERN='\.venvs\/pkgmgr\/bin\/activate"; if \[ -n "\$${PS1:-}" \]; then echo "Global Python virtual environment '\''~\/\.venvs\/pkgmgr'\'' activated."; fi; fi'
|
||||||
|
|
||||||
|
echo "[uninstall] Cleaning up ~/.bashrc and ~/.zshrc entries..."
|
||||||
|
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
|
||||||
|
if [[ -f "$rc" ]]; then
|
||||||
|
sed -i "/$RC_PATTERN/d" "$rc"
|
||||||
|
echo "[uninstall] Cleaned $rc"
|
||||||
|
else
|
||||||
|
echo "[uninstall] File not found: $rc (skipped)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[uninstall] Done. Restart your shell (or run 'exec bash' or 'exec zsh') to apply changes."
|
||||||
Reference in New Issue
Block a user