From d8c5ea88e0b2f4fecca6b68bc692740342fff907 Mon Sep 17 00:00:00 2001 From: CharOfString Date: Sat, 10 Oct 2026 18:40:39 -0500 Subject: [PATCH] add: Build Archlinux --- .github/workflows/building-deb.yml | 4 + .github/workflows/building-pkg.yml | 138 +++++++++++++++++ .../configure-building-enviroment-arch.sh | 140 ++++++++++++++++++ builder-example/PKGBUILD | 33 +++++ gxde-arch.conf | 4 + tools/arch-repo-update.sh | 102 +++++++++++++ 6 files changed, 421 insertions(+) create mode 100644 .github/workflows/building-pkg.yml create mode 100644 .github/workflows/configure-building-enviroment-arch.sh create mode 100644 builder-example/PKGBUILD create mode 100644 gxde-arch.conf create mode 100644 tools/arch-repo-update.sh diff --git a/.github/workflows/building-deb.yml b/.github/workflows/building-deb.yml index 7632b33..5670d6a 100755 --- a/.github/workflows/building-deb.yml +++ b/.github/workflows/building-deb.yml @@ -29,4 +29,8 @@ jobs: call-hetao: uses: GXDE-OS/GXDE/.github/workflows/building-deb-hetao.yml@master secrets: inherit + + call-arch: + uses: GXDE-OS/GXDE/.github/workflows/building-pkg.yml@master + secrets: inherit diff --git a/.github/workflows/building-pkg.yml b/.github/workflows/building-pkg.yml new file mode 100644 index 0000000..754bac5 --- /dev/null +++ b/.github/workflows/building-pkg.yml @@ -0,0 +1,138 @@ +# Copyright (C) 2026 CharOfString +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# ----------------------------------------------------------------------------- +# 本工作流用于构建Archlinux软件包,仅接受根目录的PKGBUILD或arch/PKGBUILD,没有时跳过。 +# This workflow is used to build Arch Linux packages, it only accepts PKGBUILD +# in the root directory of the repo or arch/PKGBUILD, otherwise this will be +# skipped. + +name: Building GXDE Arch Package + +on: + workflow_call: + secrets: + PASSWD: + required: true + USERS: + required: true + HOST: + required: true + UPATH: + required: true + UPORT: + required: true + UPROGRAM_ARCH: + required: false + +env: + REPOSITORY: https://github.com/GXDE-OS/GXDE + BOTTLEPATH: system-bottle + GXDE_ARCH_REPO: https://repo1.gxde.top/gxde-arch + +jobs: + detect: + if: github.repository_owner == 'GXDE-OS' + runs-on: ubuntu-24.04 + outputs: + pkgbuild-dir: ${{ steps.find.outputs.dir }} + steps: + - uses: actions/checkout@v4 + - name: Find PKGBUILD + id: find + run: | + if [[ -f arch/PKGBUILD ]]; then + echo "dir=arch" >> $GITHUB_OUTPUT + elif [[ -f PKGBUILD ]]; then + echo "dir=." >> $GITHUB_OUTPUT + else + echo "No PKGBUILD found, skip Arch build" + fi + + build: + needs: detect + if: needs.detect.outputs.pkgbuild-dir != '' + name: ${{ matrix.arch }}-arch + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - arch: x86_64 + runner: ubuntu-24.04 + - arch: aarch64 + runner: ubuntu-24.04-arm + steps: + - name: Clone Repository To Get Script + run: | + git clone $REPOSITORY --depth=1 + mv $(basename $REPOSITORY)/* . -v + mv $(basename $REPOSITORY)/.* . -v | true + + - name: Configure Base System + run: | + bash .github/workflows/configure-building-enviroment-arch.sh ${{ matrix.arch }} \ + $REPOSITORY \ + https://github.com/$GITHUB_REPOSITORY \ + ${{ github.ref_name }} \ + $GXDE_ARCH_REPO + + - name: Building ${{ GITHUB.repository }} + run: | + gitPath=/home/builder/$(basename $GITHUB_REPOSITORY)/${{ needs.detect.outputs.pkgbuild-dir }} + sudo chroot $BOTTLEPATH sudo -H -u builder bash -c \ + "cd $gitPath && makepkg -s --noconfirm --needed" + mkdir -p packages + sudo find $BOTTLEPATH$gitPath -maxdepth 1 -name '*.pkg.tar.*' ! -name '*.sig' -exec cp -v {} packages/ \; + sudo chown -R $(id -u):$(id -g) packages + ls -l packages + + - name: Remove Debug Package + run: | + rm -fv packages/*-debug-*.pkg.tar.* + + - name: Pack tar + run: | + cd packages + tar -cvf ../arch-${{ matrix.arch }}-$(date +%s).tar *.pkg.tar.* + + - name: Push + env: + UPASSWD: ${{ secrets.PASSWD }} + UUSERS: ${{ secrets.USERS }} + UHOST: ${{ secrets.HOST }} + UPATH: ${{ secrets.UPATH }} + UPROGRAM_ARCH: ${{ secrets.UPROGRAM_ARCH }} + UPORT: ${{ secrets.UPORT }} + run: | + if [[ -z "$UPROGRAM_ARCH" ]]; then + echo "::warning::UPROGRAM_ARCH is not set, skip uploading Arch packages" + exit 0 + fi + sudo apt update + sudo apt install sshpass -y + mkdir -p ~/.ssh/ + ssh-keyscan -p $UPORT -H $UHOST >> ~/.ssh/known_hosts + tarName=$(ls | grep '^arch-.*\.tar$' | head -n 1) + sshpass -p "$UPASSWD" rsync -e "ssh -p $UPORT" $tarName $UUSERS@$UHOST:$UPATH + sshpass -p "$UPASSWD" ssh $UUSERS@$UHOST -p $UPORT $UPROGRAM_ARCH ${{ matrix.arch }} $UPATH/$tarName > /dev/null + + - name: Create Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_TOCKEN_GITHUB }} + with: + files: | + packages/*.pkg.tar.* diff --git a/.github/workflows/configure-building-enviroment-arch.sh b/.github/workflows/configure-building-enviroment-arch.sh new file mode 100644 index 0000000..a39d2d2 --- /dev/null +++ b/.github/workflows/configure-building-enviroment-arch.sh @@ -0,0 +1,140 @@ +#!/bin/bash + +# Copyright (C) 2026 CharOfString +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# ----------------------------------------------------------------------------- +# 本脚本用于构建GXDE Arch打包环境 +# 参数$1 = 架构,可选x86_64/aarch64 +# 参数$2 = GXDE仓库地址 +# 参数$3 = 源码包仓库地址 +# 参数$4 = 当前欲构建的分支 +# 参数$5 = GXDE Arch源地址,用于获取GXDE依赖 +# ----------------------------------------------------------------------------- +# This script is used to configure the packaging environment of GXDE on Arch. +# $1 = Archtecture required, either x86_64 or aarch64. +# $2 = GXDE repository address. +# $3 = Repository path of the software to be built. +# $4 = The branch that you want to build. +# $5 = The Arch PACMAN source of GXDE, we'll use it to install dependencies. + +set -e +build_arch=$1 +bottle_path=./system-bottle +gxde_arch_repo=${5:-https://repo1.gxde.top/gxde-arch} + +# 引用/Works Cited: https://patorjk.com/software/taag/#p=display&f=Linguaholic+Shadow+3D +echo ' ██████╗██╗ ██╗██████╗ ████████╗ ████╗ ' +echo '██╔═════╝╚═██╗ ██╔═╝██╔═══██╗██╔═════╝ ██╔═══╝ ████╗ ██╗ ████╗ ' +echo '██║ ████╗ ╚═██╔═╝ ██║ ██║██████╗ ██████╗ ██╔═══██╗████╔═══╝ ' +echo '██║ ╚═██║ ██╔═██╗ ██║ ██║██╔═══╝ ╚═██╔═╝ ██║ ██║██╔═╝ ' +echo '╚═██████║██╔═╝ ╚═██╗██████╔═╝████████╗ ██║ ╚═████╔═╝██║ ' +echo ' ╚═════╝╚═╝ ╚═╝╚═════╝ ╚═══════╝ ╚═╝ ╚═══╝ ╚═╝ ' +echo ' ' +echo ' ' +echo ' ████╗ ██╗ ██╗ ██╗ ' +echo '██╔═══██╗██╗ ████╗ ██████╗██████╗ ██║ ╚═╝██████╗ ██╗ ██╗██╗ ██╗' +echo '████████║████╔═══╝██╔═════╝██╔═══██╗██║ ██╗██╔═══██╗██║ ██║╚═████╔═╝' +echo '██╔═══██║██╔═╝ ██║ ██║ ██║██║ ██║██║ ██║██║ ██║ ████║ ' +echo '██║ ██║██║ ╚═██████╗██║ ██║████████╗██║██║ ██║╚═██████║██╔═══██╗' +echo '╚═╝ ╚═╝╚═╝ ╚═════╝╚═╝ ╚═╝╚═══════╝╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝' + +# 先安装解压chroot用的依赖 ・ Install the dependencies for extracting chroot first. +sudo apt update +sudo apt install wget zstd git -y + +# 根据架构下载解压对应chroot ・ Download & extract corresponding chroot by archtecture needed. +echo '[I] (Chroot) Init: Starting to download chroot for Archlinux...' +if [[ $build_arch == "x86_64" ]]; then + echo '[I] (Chroot) Init: Archtecture hit >> AMD64.' + wget -q https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.zst + sudo tar --zstd -xpf archlinux-bootstrap-x86_64.tar.zst --numeric-owner + sudo mv root.x86_64 $bottle_path + echo 'Server = https://geo.mirror.pkgbuild.com/$repo/os/$build_arch' | sudo tee $bottle_path/etc/pacman.d/mirrorlist + keyring=archlinux +elif [[ $build_arch == "aarch64" ]]; then + echo '[I] (Chroot) Init: Archtecture hit >> AARCH64.' + wget -q http://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz + sudo mkdir -p $bottle_path + sudo tar -xpf ArchLinuxARM-aarch64-latest.tar.gz -C $bottle_path --numeric-owner + keyring=archlinuxarm +else + echo '[E] (Chroot) Init: Unsupportted archtecture $arch, HALTED!' + exit 1 +fi +echo '[I] (Chroot) Init: Done downloading chroot for Archlinux.' + +# 挂载chroot ・ Mount chroot. +echo '[I] (Chroot) Mount: Starting to mount target chroot...' +sudo mount --bind $bottle_path $bottle_path +for i in proc sys dev dev/pts; do + sudo mount --bind /$i $bottle_path/$i +done +sudo cp -L /etc/resolv.conf $bottle_path/etc/resolv.conf +echo '[I] (Chroot) Mount: Done mounting the chroot!' + +# Pacman在chroot里无法做沙箱/空间检查 +# Pacman is not able to do space check or sandbox in chroot. +echo '[I] (Chroot) PostInit: Disabling sanbox and space check since we are in chroot...' +sudo sed -i 's/^CheckSpace/#CheckSpace/' $bottle_path/etc/pacman.conf +sudo sed -i 's/^#DisableSandbox/DisableSandbox/' $bottle_path/etc/pacman.conf +echo '[I] (Chroot) PostInit: Done disabling unavailable components!' + +# 一个小wrapper,在chroot中运行某指令 ・ A wrapper to run certain commands under chroot. +run() { + sudo chroot $bottle_path bash -c "$*" +} + +# 写入GXDE Arch源,以便安装dtk等自身提供的依赖 +# 新源刚建立时可能还不存在,因此只做可选信任 +# -------------------------------------------- +# Add GXDE Archlinux PACMAN source to install dependencies such as DTK. +# It may not exist when as we're just getting started, so we will do a Optional TrustAll. +echo '[I] (Chroot) PACMAN: Configuring GXDE pacman source...' +cat << EOF | sudo tee -a $bottle_path/etc/pacman.conf + +[gxde] +SigLevel = Optional TrustAll +Server = $gxde_arch_repo/\$build_arch +EOF +echo '[I] (Chroot) PACMAN: GXDE pacman source has been added to chroot!' +echo '[I] (Chroot) PACMAN: Doing upgrade...' +run pacman-key --init +run pacman-key --populate $keyring +for i in {1..5}; do + # GXDE 源尚不存在时 -Syu 会失败,此时去掉 GXDE 源再试一次 + if run pacman -Syu --noconfirm --needed base-devel git sudo; then + break + fi + if [[ $i == 3 ]]; then + echo "GXDE Arch repo unreachable, building without it" + sudo sed -i '/^\[gxde\]/,/^Server/d' $bottle_path/etc/pacman.conf + fi + sleep 2 +done +echo '[I] (Chroot) PACMAN: Shall be okay...' + +# makepkg不允许以root运行 ・ makepkg require another account other than root. +echo '[I] (Building) AccountCtl: Setting up builder account...' +run useradd -m builder +echo "builder ALL=(ALL) NOPASSWD: ALL" | sudo tee $bottle_path/etc/sudoers.d/builder +echo '[I] (Building) AccountCtl: Builder account is up!' + +# 以builder身份克隆仓库 ・ Clone the repo as builder. +echo '[I] (Building) Builder: Cloning target repository...' +run sudo -H -u builder git clone $3 -b $4 /home/builder/$(basename $3) +echo '[I] (Building) Builder: Done cloning target repository.' + +echo '[I] (Env) Setup: Setup finished, bye~' +exit 0 diff --git a/builder-example/PKGBUILD b/builder-example/PKGBUILD new file mode 100644 index 0000000..cbb38c7 --- /dev/null +++ b/builder-example/PKGBUILD @@ -0,0 +1,33 @@ +# PKGBUILD for testing purpose. + +pkgname=gxde-example +pkgver=0 +pkgrel=1 +pkgdesc="GXDE example component" +arch=('x86_64' 'aarch64') +url="https://github.com/GXDE-OS/${pkgname}" +license=('GPL-3.0-or-later') + +depends=('qt5-base') +makedepends=('git' 'cmake' 'qt5-tools') +source=() +sha256sums=() + +_srcdir() { + git -C "$startdir" rev-parse --show-toplevel +} + +pkgver() { + head -n 1 "$(_srcdir)/debian/changelog" | sed -E 's/.*\(([^)]*)\).*/\1/; s/^[0-9]+://; s/-/./g' +} + +build() { + cmake -B build -S "$(_srcdir)" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr + cmake --build build +} + +package() { + DESTDIR="$pkgdir" cmake --install build +} \ No newline at end of file diff --git a/gxde-arch.conf b/gxde-arch.conf new file mode 100644 index 0000000..be63ee7 --- /dev/null +++ b/gxde-arch.conf @@ -0,0 +1,4 @@ +# GXDE Arch Linux pacman source +[gxde] +SigLevel = Optional TrustAll +Server = https://repo1.gxde.top/gxde-arch/$arch diff --git a/tools/arch-repo-update.sh b/tools/arch-repo-update.sh new file mode 100644 index 0000000..44c2702 --- /dev/null +++ b/tools/arch-repo-update.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# Copyright (C) 2026 CharOfString +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# ----------------------------------------------------------------------------- +# 本脚本用于向GXDE Arch源上传包并更新数据库,由building-pkg.yml自动调用 +# 用法: +# arch-repo-update.sh +# 依赖: +# repo-add (Archlinux自带;Debian上需要安装pacman-package-manager) +# 环境变量: +# GXDE_ARCH_REPO_ROOT 源根目录,对外地址为 https://repo1.gxde.top/gxde-arch/$arch +# GXDE_ARCH_GPG_KEY 可选,设置后对包和数据库进行签名 +# ----------------------------------------------------------------------------- +# This script updates the artifacts in GXDE pacman source and is invoked by +# building-pkg.yml automatically. +# Usage: +# arch-repo-update.sh +# Dependencies: +# repo-add (Archlinux built-in; on Debian, install pacman-package-manager) +# Environment variables: +# GXDE_ARCH_REPO_ROOT The root directory of the source, externally accessible at +# https://repo1.gxde.top/gxde-arch/$arch +# GXDE_ARCH_GPG_KEY Optional, if set, will sign the packages and database. + +set -e +arch=$1 +tar_path=$2 +repo_root=${GXDE_ARCH_REPO_ROOT:-/var/www/repo/gxde-arch} +repo_name=gxde + +# 引用/Works Cited: https://patorjk.com/software/taag/#p=display&f=Linguaholic+Shadow+3D +echo ' ██████╗██╗ ██╗██████╗ ████████╗ ████╗ ' +echo '██╔═════╝╚═██╗ ██╔═╝██╔═══██╗██╔═════╝ ██╔═══╝ ████╗ ██╗ ████╗ ' +echo '██║ ████╗ ╚═██╔═╝ ██║ ██║██████╗ ██████╗ ██╔═══██╗████╔═══╝ ' +echo '██║ ╚═██║ ██╔═██╗ ██║ ██║██╔═══╝ ╚═██╔═╝ ██║ ██║██╔═╝ ' +echo '╚═██████║██╔═╝ ╚═██╗██████╔═╝████████╗ ██║ ╚═████╔═╝██║ ' +echo ' ╚═════╝╚═╝ ╚═╝╚═════╝ ╚═══════╝ ╚═╝ ╚═══╝ ╚═╝ ' +echo ' ' +echo ' ' +echo ' ████╗ ██╗ ██╗ ██╗ ' +echo '██╔═══██╗██╗ ████╗ ██████╗██████╗ ██║ ╚═╝██████╗ ██╗ ██╗██╗ ██╗' +echo '████████║████╔═══╝██╔═════╝██╔═══██╗██║ ██╗██╔═══██╗██║ ██║╚═████╔═╝' +echo '██╔═══██║██╔═╝ ██║ ██║ ██║██║ ██║██║ ██║██║ ██║ ████║ ' +echo '██║ ██║██║ ╚═██████╗██║ ██║████████╗██║██║ ██║╚═██████║██╔═══██╗' +echo '╚═╝ ╚═╝╚═╝ ╚═════╝╚═╝ ╚═╝╚═══════╝╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝' + +case $arch in + x86_64|aarch64) ;; + *) echo "Unsupported arch: $arch"; exit 1 ;; +esac + +if [[ ! -f $tar_path ]]; then + echo "$tar_path not found" + exit 1 +fi + +repoDir=$repo_root/$arch +mkdir -p $repoDir +exec 9> $repoDir/.lock +flock 9 + +tmpDir=$(mktemp -d) +trap "rm -rf $tmpDir" EXIT +tar -xf $tar_path -C $tmpDir + +newPackages=() +for pkg in $tmpDir/*.pkg.tar.*; do + [[ $pkg == *.sig ]] && continue + name=$(basename $pkg) + mv -f $pkg $repoDir/$name + if [[ -n $GXDE_ARCH_GPG_KEY ]]; then + rm -f $repoDir/$name.sig + gpg --batch --yes -u $GXDE_ARCH_GPG_KEY --detach-sign --no-armor $repoDir/$name + fi + newPackages+=($repoDir/$name) +done + +if [[ ${#newPackages[@]} == 0 ]]; then + echo "No package in $tar_path" + exit 1 +fi + +signArgs=() +if [[ -n $GXDE_ARCH_GPG_KEY ]]; then + signArgs=(--sign --key $GXDE_ARCH_GPG_KEY) +fi + +repo-add -R "${signArgs[@]}" $repoDir/$repo_name.db.tar.gz "${newPackages[@]}" +rm -f $tar_path \ No newline at end of file