🔒 Repository is read-only – file editing is disabled.

PaganLinux/builder-chroot.sh main

203 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
#!/usr/bin/env bash
# =============================================================================
# builder-chroot.sh – powtarzalne środowisko budowania PaganOS
#
# Tworzy Debian-based chroot dla pagbuild. Nie zastępuje rootfs PaganOS:
# jest osobnym, pełnym środowiskiem BUILDROOT z narzędziami developerskimi.
#
# Użycie:
#   sudo ./builder-chroot.sh --rootfs /mnt/pagan-builder --rebuild
#   sudo ./builder-chroot.sh --rootfs /mnt/pagan-builder
# =============================================================================
set -Eeuo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOTFS="${BUILDER_ROOTFS:-/mnt/pagan-builder-rootfs}"
SUITE="${BUILDER_SUITE:-trixie}"
MIRROR="${BUILDER_MIRROR:-https://deb.debian.org/debian}"
REBUILD=0
ACTIVATE=0
KEEP_MOUNTS=0
ACTIVE_ROOTFS="${BUILDER_ACTIVE_ROOTFS:-/var/lib/pagan-build/rootfs}"

usage() {
    sed -n '1,22p' "$0"
    exit "${1:-0}"
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --rootfs) [[ $# -ge 2 ]] || usage 2; ROOTFS="$2"; shift 2 ;;
        --suite)  [[ $# -ge 2 ]] || usage 2; SUITE="$2"; shift 2 ;;
        --mirror) [[ $# -ge 2 ]] || usage 2; MIRROR="$2"; shift 2 ;;
        --rebuild|--clean) REBUILD=1; shift ;;
        --activate) ACTIVATE=1; REBUILD=1; ROOTFS="${BUILDER_STAGING_ROOTFS:-${ACTIVE_ROOTFS}.new}"; shift ;;
        --active-rootfs) [[ $# -ge 2 ]] || usage 2; ACTIVE_ROOTFS="$2"; shift 2 ;;
        --keep-mounts) KEEP_MOUNTS=1; shift ;;
        -h|--help) usage 0 ;;
        *) echo "Nieznany argument: $1" >&2; usage 2 ;;
    esac
done

[[ $EUID -eq 0 ]] || { echo "Uruchom jako root: sudo $0 ..." >&2; exit 1; }
[[ "$ROOTFS" != "/" && -n "$ROOTFS" ]] || { echo "Niebezpieczny ROOTFS=$ROOTFS" >&2; exit 1; }

log() { printf '[builder-chroot] %s\n' "$*"; }
die() { echo "[builder-chroot] BŁĄD: $*" >&2; exit 1; }

for cmd in mount umount chroot rsync tar sha256sum; do
    command -v "$cmd" >/dev/null || die "Brak programu hosta: $cmd"
done

if [[ $REBUILD -eq 1 ]]; then
    log "Czyszczenie $ROOTFS"
    rm -rf --one-file-system "$ROOTFS"
fi
mkdir -p "$ROOTFS"

# Debian bootstrap jest celowo osobny od LFS/PaganOS rootfs. Dzięki temu
# builder ma spójne ABI i działający menedżer pakietów.
if [[ ! -x "$ROOTFS/usr/bin/apt-get" ]]; then
    command -v debootstrap >/dev/null || die "Brak debootstrap. Zainstaluj na hoście: apt install debootstrap"
    log "Bootstrap Debian $SUITE"
    debootstrap --variant=minbase "$SUITE" "$ROOTFS" "$MIRROR"
fi

MOUNTS=()
unmount_all() {
    for m in "${MOUNTS[@]:-}"; do umount -l "$m" 2>/dev/null || true; done
    MOUNTS=()
}

cleanup() {
    local rc=$?
    if [[ $KEEP_MOUNTS -eq 0 ]]; then unmount_all; fi
    exit "$rc"
}
trap cleanup EXIT INT TERM

mount_one() {
    local options="$1" source="$2" target="$3"
    mkdir -p "$target"
    mount $options "$source" "$target"
    MOUNTS=("$target" "${MOUNTS[@]}")
}

# Montowania są potrzebne dla apt, testów kompilatora oraz programów używających
# /proc, /sys i /dev. --rbind zachowuje /dev/pts i /dev/shm.
mount_one "-t proc" proc "$ROOTFS/proc"
mount --rbind /sys "$ROOTFS/sys"; mount --make-rslave "$ROOTFS/sys"; MOUNTS=("$ROOTFS/sys" "${MOUNTS[@]}")
mount --rbind /dev "$ROOTFS/dev"; mount --make-rslave "$ROOTFS/dev"; MOUNTS=("$ROOTFS/dev" "${MOUNTS[@]}")
mount --rbind /run "$ROOTFS/run"; mount --make-rslave "$ROOTFS/run"; MOUNTS=("$ROOTFS/run" "${MOUNTS[@]}")

rm -f "$ROOTFS/etc/resolv.conf"
cp -L /etc/resolv.conf "$ROOTFS/etc/resolv.conf"
cat > "$ROOTFS/etc/apt/apt.conf.d/99builder" <<'EOF'
Acquire::Retries "5";
APT::Install-Recommends "false";
APT::Install-Suggests "false";
EOF

# Kompletna baza do budowania core/libs/desktop. Nazwy są Debianowe i służą
# tylko builderowi; zależności PaganOS nadal pochodzą z PAGBUILD.yaml.
BUILD_PACKAGES=(
    build-essential gcc g++ gcc-multilib libc6-dev-i386 make ninja-build meson cmake
    autoconf automake libtool pkg-config gettext autopoint bison flex gawk m4 texinfo
    git curl wget ca-certificates rsync patch file diffutils findutils sed grep
    tar gzip bzip2 xz-utils zstd unzip cpio gperf xsltproc docbook-xsl docbook-xml
    libxml2-utils libxml-parser-perl perl python3 python3-dev python3-pip python3-yaml
    python3-venv sqlite3 libsqlite3-dev gpg gpg-agent fakeroot
    libssl-dev libffi-dev libreadline-dev libncurses-dev zlib1g-dev liblzma-dev
    libbz2-dev libzstd-dev libexpat1-dev libpcre2-dev libxml2-dev libxslt1-dev
    libglib2.0-dev libdbus-1-dev libsystemd-dev libudev-dev libmount-dev
    libacl1-dev libattr1-dev libpam0g-dev libcap-dev libmnl-dev libevdev-dev
    libgirepository1.0-dev gobject-introspection valac shared-mime-info
    libgtk-3-dev libpango1.0-dev libcairo2-dev libgdk-pixbuf-2.0-dev
    libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxft-dev
    libxrender-dev libxrandr-dev libxi-dev libxinerama-dev libxkbcommon-dev
    libwayland-dev wayland-protocols libdrm-dev
    qtbase5-dev qtdeclarative5-dev qttools5-dev libqt5svg5-dev
    libpolkit-qt5-1-dev intltool
)

log "Instalowanie ${#BUILD_PACKAGES[@]} pakietów developerskich"
chroot "$ROOTFS" /usr/bin/env DEBIAN_FRONTEND=noninteractive \
    apt-get update
chroot "$ROOTFS" /usr/bin/env DEBIAN_FRONTEND=noninteractive \
    apt-get install -y "${BUILD_PACKAGES[@]}"

# Stałe środowisko dla każdego przepisu.
cat > "$ROOTFS/etc/profile.d/pagan-builder.sh" <<'EOF'
export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
export HOME=/root
export LANG=C.UTF-8
export LC_ALL=C.UTF-8
export FORCE_UNSAFE_CONFIGURE=1
export CC=/usr/bin/gcc
export CXX=/usr/bin/g++
export AR=/usr/bin/ar
export RANLIB=/usr/bin/ranlib
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
export PKG_CONFIG_LIBDIR=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig
export CMAKE_PREFIX_PATH=/usr:/
export MAKEFLAGS="-j$(nproc)"
EOF

mkdir -p "$ROOTFS/var/cache/pagbuild" "$ROOTFS/var/lib/pagan-sync" "$ROOTFS/opt/pagan"
# Aktualne narzędzia z tego samego checkoutu, bez starego heredoc/stuba.
for tool in pag pagbuild pagsync; do
    [[ -f "$SCRIPT_DIR/$tool" ]] || die "Brak pliku projektu: $SCRIPT_DIR/$tool"
    install -Dm755 "$SCRIPT_DIR/$tool" "$ROOTFS/usr/local/bin/$tool"
done
install -Dm644 "$SCRIPT_DIR/pagbuild" "$ROOTFS/opt/pagan/pagbuild"
install -Dm644 "$SCRIPT_DIR/pagsync" "$ROOTFS/opt/pagan/pagsync"

cat > "$ROOTFS/etc/pagan-builder-release" <<EOF
PaganOS builder chroot
suite=$SUITE
created=$(date -u +%Y-%m-%dT%H:%M:%SZ)
tools=pag,pagbuild,pagsync
EOF

log "Weryfikacja buildera"
chroot "$ROOTFS" /usr/bin/env -i PATH=/usr/local/bin:/usr/bin:/bin \
    HOME=/root LANG=C.UTF-8 bash -lc '
set -e
for x in bash gcc g++ make cmake meson ninja pkg-config git gpg python3 perl xsltproc xmllint gperf intltool-update; do
    command -v "$x" >/dev/null || { echo "missing:$x" >&2; exit 1; }
done
python3 -c "import yaml,sys; print(\"python-yaml:ok\")"
test "$(pkg-config --modversion glib-2.0)"
test "$(pkg-config --modversion dbus-1)"
test "$(pkg-config --modversion gtk+-3.0)"
test -f /usr/lib/x86_64-linux-gnu/cmake/Qt5/Qt5Config.cmake
pagbuild --help >/dev/null 2>&1 || true
printf "builder-chroot:ok\\n"
'

# Archiwum i checksum są tworzone obok rootfs, gotowe do scp.
ARCHIVE="${ROOTFS%/}.tar.xz"
log "Pakowanie $ARCHIVE"
tar -cJf "$ARCHIVE" -C "$ROOTFS" \
    --exclude='./proc' --exclude='./sys' --exclude='./dev' --exclude='./run' --exclude='./tmp' .
sha256sum "$ARCHIVE" > "$ARCHIVE.sha256"
log "Gotowe: $ARCHIVE"
log "Checksum: $ARCHIVE.sha256"

if [[ $ACTIVATE -eq 1 ]]; then
    [[ "$ACTIVE_ROOTFS" != "/var/lib/pagan-build/rootfs" ]] || die "Odmowa: Debianowy builder-chroot nie może zastąpić PaganOS rootfs. Użyj go jako osobnego środowiska BUILDROOT."
    [[ "$ROOTFS" == "${ACTIVE_ROOTFS}.new" ]] || die "Tryb --activate wymaga stagingu ${ACTIVE_ROOTFS}.new"
    # Nie przełączaj środowiska, gdy kolejka nadal używa starego rootfs.
    if ps -eo args= | grep -E '[p]agsync|[p]agbuild /var/lib/pagan-sync' | grep -v 'builder-chroot.sh' >/dev/null; then
        die "Aktywna kolejka pagsync/pagbuild. Zatrzymaj ją i uruchom --activate ponownie."
    fi
    unmount_all
    BACKUP="${ACTIVE_ROOTFS}.previous-$(date -u +%Y%m%dT%H%M%SZ)"
    log "Backup obecnego rootfs: $BACKUP"
    [[ -d "$ACTIVE_ROOTFS" ]] && mv "$ACTIVE_ROOTFS" "$BACKUP"
    mv "$ROOTFS" "$ACTIVE_ROOTFS"
    # Zachowaj artefakty do weryfikacji po przełączeniu.
    cp -f "$ARCHIVE" "$ACTIVE_ROOTFS.tar.xz"
    cp -f "$ARCHIVE.sha256" "$ACTIVE_ROOTFS.tar.xz.sha256"
    log "Aktywowano nowy rootfs: $ACTIVE_ROOTFS"
fi