name: Void Linux XBPS Repository

on:
  schedule:
    - cron: "0 2,5,14,17,20,23 * * *" # 9am, 12pm, 3pm, 6pm, 9pm, 12am EST (UTC times shown)
  # release trigger disabled; dispatch manually after a release
  # release:
  #   types: [published]
  workflow_dispatch:
    inputs:
      version:
        description: 'Stable release tag/version to build (e.g. v1.5.0 or 1.5.0). Leave blank to use the selected ref/template version'
        type: string
        required: false
      force_rebuild:
        description: 'Force rebuilding packages even if they already exist in the repository'
        type: boolean
        required: false
        default: false
      build_git:
        description: 'Build dms-git package'
        type: boolean
        required: false
        default: true
      build_dms:
        description: 'Build stable dms package'
        type: boolean
        required: false
        default: true

permissions:
  contents: read

concurrency:
  group: void-xbps-${{ github.ref }}
  cancel-in-progress: false

jobs:
  preflight:
    name: Check for unpublished changes
    runs-on: ubuntu-latest
    outputs:
      should_build: ${{ steps.check.outputs.should_build }}
    steps:
      - name: Check published commit
        id: check
        env:
          MANIFEST_URL: https://void.danklinux.com/dms/current/manifest.json
        run: |
          SHOULD_BUILD=true
          if [ "${{ github.event_name }}" = "schedule" ]; then
            PUBLISHED_COMMIT="$(curl -fsSL --retry 3 "$MANIFEST_URL" | jq -r '.source_commit // empty' 2>/dev/null || true)"
            if [ "$PUBLISHED_COMMIT" = "${{ github.sha }}" ]; then
              SHOULD_BUILD=false
              echo "${{ github.sha }} is already published; skipping the scheduled build."
            fi
          fi
          echo "should_build=$SHOULD_BUILD" >> "$GITHUB_OUTPUT"

  build-and-deploy:
    name: Build & Deploy XBPS packages
    runs-on: ubuntu-latest
    needs: preflight
    if: github.repository == 'AvengeMedia/DankMaterialShell' && needs.preflight.outputs.should_build == 'true'
    env:
      AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
      AWS_DEFAULT_REGION: auto
      AWS_EC2_METADATA_DISABLED: true
      R2_BUCKET: danklinux-void
      R2_ENDPOINT: https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com
      R2_PREFIX: dms
      REPOSITORY_DIR: ${{ github.workspace }}/r2-repo
      SOURCE_COMMIT: ${{ github.sha }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          ref: ${{ github.event.release.tag_name || (github.event.inputs.version && (startsWith(github.event.inputs.version, 'v') && github.event.inputs.version || format('v{0}', github.event.inputs.version))) || github.ref }}
          fetch-depth: 0
          submodules: recursive

      - name: Record checked-out source commit
        run: echo "SOURCE_COMMIT=$(git rev-parse HEAD)" >> "$GITHUB_ENV"

      - name: Download current R2 repository
        run: |
          aws --version
          bash .github/scripts/publish-void-r2.sh download

      - name: Install XBPS Static Utilities
        run: |
          mkdir -p ${{ github.workspace }}/xbps
          curl -s -L https://repo-default.voidlinux.org/static/xbps-static-latest.x86_64-musl.tar.xz | tar -xJ -C ${{ github.workspace }}/xbps
          echo "${{ github.workspace }}/xbps/usr/bin" >> $GITHUB_PATH

      - name: Clone void-packages
        run: |
          git clone --depth=1 https://github.com/void-linux/void-packages.git

      - name: Inject templates
        run: |
          cp -R distro/void/srcpkgs/dms void-packages/srcpkgs/
          cp -R distro/void/srcpkgs/dms-git void-packages/srcpkgs/

      - name: Enable unprivileged user namespaces (Ubuntu 24.04)
        run: |
          sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true

      - name: Bootstrap xbps-src
        run: |
          cd void-packages
          ./xbps-src binary-bootstrap

      - name: Configure signing keys and trust
        run: |
          # Write private key; extract and register the public key
          echo "${{ secrets.XBPS_PRIVATE_KEY }}" > /tmp/xbps_privkey.pem
          chmod 600 /tmp/xbps_privkey.pem

          # Extract public key in PEM format
          openssl rsa -in /tmp/xbps_privkey.pem -pubout -out /tmp/dms-key.pub
          rm -f /tmp/xbps_privkey.pem

          # Compute MD5 fingerprint in colon-separated hex format
          FINGERPRINT=$(openssl rsa -pubin -in /tmp/dms-key.pub -outform DER 2>/dev/null | openssl dgst -md5 -c | tr '[:upper:]' '[:lower:]' | awk '{print $NF}')

          # Format key in XML property list (plist) format as expected by xbps
          mkdir -p /tmp/keys
          cat <<EOF > "/tmp/keys/${FINGERPRINT}.plist"
          <?xml version="1.0" encoding="UTF-8"?>
          <plist version="1.0">
          <dict>
          	<key>public-key</key>
          	<data>$(base64 -w0 /tmp/dms-key.pub)</data>
          	<key>public-key-size</key>
          	<integer>4096</integer>
          	<key>signature-by</key>
          	<string>AvengeMedia</string>
          </dict>
          </plist>
          EOF

          # Copy keys to all host and chroot trust stores
          sudo mkdir -p /var/db/xbps/keys
          sudo cp "/tmp/keys/${FINGERPRINT}.plist" "/var/db/xbps/keys/${FINGERPRINT}.plist"

          mkdir -p void-packages/masterdir/var/db/xbps/keys
          cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/masterdir/var/db/xbps/keys/${FINGERPRINT}.plist"

          mkdir -p void-packages/etc/xbps.d/keys
          cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/etc/xbps.d/keys/${FINGERPRINT}.plist"

          mkdir -p void-packages/common/repo-keys
          cp "/tmp/keys/${FINGERPRINT}.plist" "void-packages/common/repo-keys/${FINGERPRINT}.plist"

          rm -rf /tmp/keys /tmp/dms-key.pub

      - name: Configure repositories
        run: |
          # Append the repository to repos-remote templates so xbps-src translates it automatically
          echo "repository=https://void.danklinux.com/danklinux/current" >> void-packages/etc/xbps.d/repos-remote.conf
          echo "repository=https://void.danklinux.com/danklinux/current" >> void-packages/etc/xbps.d/repos-remote-x86_64-multilib.conf

          # Add any existing compiled packages to the build cache directory to avoid rebuilds
          if [ -d "r2-repo/current" ]; then
            mkdir -p void-packages/hostdir/binpkgs
            cp -L r2-repo/current/*.xbps void-packages/hostdir/binpkgs/ 2>/dev/null || true
            xbps-rindex -a void-packages/hostdir/binpkgs/*.xbps 2>/dev/null || true
          fi

      - name: Build packages
        run: |
          mkdir -p r2-repo/current

          BUILD_DMS="${{ github.event.inputs.build_dms || 'true' }}"
          BUILD_GIT="${{ github.event.inputs.build_git || 'true' }}"
          FORCE_REBUILD="${{ github.event.inputs.force_rebuild || 'false' }}"

          if [ "${{ github.event_name }}" = "schedule" ]; then
            BUILD_DMS="false"
            BUILD_GIT="true"
          fi

          if [ "${{ github.event_name }}" = "release" ]; then
            BUILD_DMS="true"
            BUILD_GIT="false"
          fi

          RELEASE_TAG=""
          if [ "${{ github.event_name }}" = "release" ]; then
            RELEASE_TAG="${{ github.event.release.tag_name }}"
          elif [ -n "${{ github.event.inputs.version || '' }}" ]; then
            RELEASE_TAG="${{ github.event.inputs.version }}"
          elif [ "${{ github.ref_type }}" = "tag" ]; then
            RELEASE_TAG="${{ github.ref_name }}"
          fi

          if [ -n "$RELEASE_TAG" ]; then
            RELEASE_VER="${RELEASE_TAG#v}"
            ARCHIVE_TAG="v${RELEASE_VER}"
            echo "Stable release tag:          $ARCHIVE_TAG"
          else
            RELEASE_VER=""
            ARCHIVE_TAG=""
            echo "Stable release tag:          (template version)"
          fi

          echo "=== Starting Builds ==="
          echo "DMS stable build enabled:     $BUILD_DMS"
          echo "Git build enabled:            $BUILD_GIT"
          echo "Force rebuild:                $FORCE_REBUILD"

          cd void-packages

          if [ -n "$RELEASE_VER" ] && [ "$BUILD_DMS" = "true" ]; then
            echo "🔧 Updating stable template for $ARCHIVE_TAG"
            TARBALL="$(mktemp)"
            curl -fsSL -o "$TARBALL" "https://github.com/${{ github.repository }}/releases/download/${ARCHIVE_TAG}/dms-source.tar.gz"
            RELEASE_CHECKSUM="$(sha256sum "$TARBALL" | cut -d' ' -f1)"
            rm -f "$TARBALL"

            sed -i "s/^version=.*/version=${RELEASE_VER}/" srcpkgs/dms/template
            sed -i "s/^checksum=.*/checksum=${RELEASE_CHECKSUM}/" srcpkgs/dms/template
          fi

          # 1. Build dms-git (development package)
          if [ "$BUILD_GIT" = "true" ]; then
            # Calculate dynamic git version (tag.commits.hash)
            GIT_VER=$(git -C .. describe --tags --always | sed 's/^v//; s/-/./g')
            echo "🔨 Preparing dms-git version $GIT_VER"

            # Stage source tarball in the xbps-src source cache.
            # --transform adds a top-level directory so xbps-src can extract
            # into $wrksrc (create_wrksrc=yes handles the rest).
            SRC_CACHE="hostdir/sources/dms-git-${GIT_VER}"
            mkdir -p "$SRC_CACHE"
            tar -czhf "${SRC_CACHE}/dms-git-${GIT_VER}.tar.gz" \
              --exclude=void-packages \
              --exclude=r2-repo \
              --exclude=.git \
              --exclude=danklinux \
              -C .. .

            CHECKSUM=$(sha256sum "${SRC_CACHE}/dms-git-${GIT_VER}.tar.gz" | cut -d' ' -f1)

            # Dynamically patch template version, checksum, and distfiles
            sed -i "s/^version=.*/version=${GIT_VER}/" srcpkgs/dms-git/template
            sed -i "s/^checksum=.*/checksum=${CHECKSUM}/" srcpkgs/dms-git/template
            sed -i "s|^distfiles=.*|distfiles=\"dms-git-${GIT_VER}.tar.gz\"|" srcpkgs/dms-git/template

            EXPECTED_GIT_FILE="dms-git-${GIT_VER}_1.x86_64.xbps"

            if [ -f "../r2-repo/current/$EXPECTED_GIT_FILE" ] && [ "$FORCE_REBUILD" != "true" ]; then
              echo "✅ $EXPECTED_GIT_FILE already exists, skipping build."
            else
              echo "🔨 Compiling dms-git..."
              ./xbps-src pkg dms-git
              rm -f "../r2-repo/current/${EXPECTED_GIT_FILE}"
              cp -L "hostdir/binpkgs/${EXPECTED_GIT_FILE}" ../r2-repo/current/
            fi
          fi

          # 2. Build stable dms package
          if [ "$BUILD_DMS" = "true" ]; then
            STABLE_VER=$(grep -E '^version=' srcpkgs/dms/template | cut -d= -f2 | tr -d '"')
            STABLE_REV=$(grep -E '^revision=' srcpkgs/dms/template | cut -d= -f2 | tr -d '"')

            EXPECTED_DMS_FILE="dms-${STABLE_VER}_${STABLE_REV}.x86_64.xbps"
            if [ -f "../r2-repo/current/$EXPECTED_DMS_FILE" ] && [ "$FORCE_REBUILD" != "true" ]; then
              echo "✅ $EXPECTED_DMS_FILE already exists, skipping build."
            else
              echo "🔨 Compiling dms ($STABLE_VER)..."
              ./xbps-src pkg dms
              rm -f "../r2-repo/current/${EXPECTED_DMS_FILE}"
              cp -L hostdir/binpkgs/dms-${STABLE_VER}_${STABLE_REV}.x86_64.xbps ../r2-repo/current/
            fi
          fi

      - name: Index and sign repository
        run: |
          cd r2-repo/current

          rm -f *.sig

          # Guard: nothing to index if no .xbps files exist
          if ! ls *.xbps 1>/dev/null 2>&1; then
            echo "⚠️ No .xbps files found to index, skipping."
            exit 0
          fi

          # Regenerate repo index
          xbps-rindex -a $(pwd)/*.xbps
          xbps-rindex --remove-obsoletes $(pwd)

          # Remove signatures left behind by obsolete packages. Signatures for
          # unchanged immutable packages are retained byte-for-byte.
          for sig in *.sig2; do
            [ -e "$sig" ] || break
            [ -f "${sig%.sig2}" ] || rm -f "$sig"
          done

          # Sign repository
          echo "${{ secrets.XBPS_PRIVATE_KEY }}" > /tmp/xbps_privkey.pem
          chmod 600 /tmp/xbps_privkey.pem

          xbps-rindex --sign --signedby "AvengeMedia <AvengeMedia.US@gmail.com>" --privkey /tmp/xbps_privkey.pem $(pwd)
          xbps-rindex --sign-pkg --privkey /tmp/xbps_privkey.pem $(pwd)/*.xbps

          rm -f /tmp/xbps_privkey.pem

      - name: Publish repository to R2
        run: bash .github/scripts/publish-void-r2.sh publish
