diff --git a/.github/workflows/build-disk.yml b/.github/workflows/build-disk.yml index b39a6c0..047654c 100644 --- a/.github/workflows/build-disk.yml +++ b/.github/workflows/build-disk.yml @@ -30,7 +30,7 @@ jobs: fail-fast: false matrix: variant: - - name: "regular" + - name: "main" tag: "latest" - name: "nvidia" tag: "latest-nvidia" @@ -46,10 +46,10 @@ jobs: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} - name: Maximize build space - uses: ublue-os/remove-unwanted-software@695eb75bc387dbcd9685a8e72d23439d8686cba6 # v10 + uses: ublue-os/remove-unwanted-software@v9 - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@v4 - name: Build ISO id: build @@ -71,7 +71,7 @@ jobs: echo "iso-name=$NEW_NAME" >> $GITHUB_OUTPUT - name: Upload ISO as artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@v4 with: name: ${{ env.IMAGE_NAME }}-${{ matrix.variant.name }}-iso path: output/ @@ -81,7 +81,7 @@ jobs: - name: Upload ISO to release if: inputs.create-release == true && inputs.release-tag != '' - uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2 + uses: softprops/action-gh-release@v2 with: tag_name: ${{ inputs.release-tag }} files: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a53fe8..20a135e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,9 +16,9 @@ on: env: IMAGE_DESC: "Hypercube - A Hyprland-focused bootc image built on Bluefin-DX" IMAGE_KEYWORDS: "bootc,ublue,universal-blue,hyprland,hypercube,wayland" - IMAGE_LOGO_URL: "https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/main/branding/hypercube-logo.png" # Hypercube logo - IMAGE_NAME: "${{ github.event.repository.name }}" # output image name, usually same as repo name - IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit + IMAGE_LOGO_URL: "https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/main/branding/hypercube-logo.png" + IMAGE_NAME: "${{ github.event.repository.name }}" + IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" DEFAULT_TAG: "latest" concurrency: @@ -28,7 +28,7 @@ concurrency: jobs: build_push: name: Build and push image - runs-on: ubuntu-latest-m + runs-on: ubuntu-24.04 permissions: contents: read @@ -39,9 +39,11 @@ jobs: fail-fast: false matrix: variant: - - base_image: "ghcr.io/ublue-os/bluefin-dx:stable-daily" + - flavor: "main" + base_image: "ghcr.io/ublue-os/bluefin-dx:stable-daily" tag_suffix: "" - - base_image: "ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily" + - flavor: "nvidia" + base_image: "ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily" tag_suffix: "-nvidia" steps: @@ -51,22 +53,15 @@ jobs: echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV} echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} - # These stage versions are pinned by https://github.com/renovatebot/renovate - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5 + uses: actions/checkout@v4 - # This is optional, but if you see that your builds are way too big for the runners, you can enable this by uncommenting the following lines: - # - name: Maximize build space - # uses: ublue-os/remove-unwanted-software@517622d6452028f266b7ba4cc9a123b5f58a6b53 # v7 - # with: - # remove-codeql: true + - name: Maximize build space + uses: ublue-os/remove-unwanted-software@v9 - name: Mount BTRFS for podman storage id: container-storage-action - uses: ublue-os/container-storage-action@911baca08baf30c8654933e9e9723cb399892140 - - # Fallback to the remove-unwanted-software-action if github doesn't allocate enough space - # See: https://github.com/ublue-os/container-storage-action/pull/11 + uses: ublue-os/container-storage-action@main continue-on-error: true with: target-dir: /var/lib/containers @@ -75,21 +70,13 @@ jobs: - name: Get current date id: date run: | - # This generates a timestamp like what is defined on the ArtifactHub documentation - # E.G: 2022-02-08T15:38:15Z' - # https://artifacthub.io/docs/topics/repositories/container-images/ - # https://linux.die.net/man/1/date echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT + echo "version=$(date +%Y%m%d)" >> $GITHUB_OUTPUT - # Image metadata for https://artifacthub.io/ - This is optional but is highly recommended so we all can get a index of all the custom images - # The metadata by itself is not going to do anything, you choose if you want your image to be on ArtifactHub or not. - name: Image Metadata - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@v5 id: metadata with: - # This generates all the tags for your image, you can add custom tags here too! - # Default tags are "$DEFAULT_TAG" and "$DEFAULT_TAG.$date". - # Matrix tag_suffix is appended to differentiate variants (e.g., latest vs latest-nvidia) tags: | type=raw,value=${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }} type=raw,value=${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}.{{date 'YYYYMMDD'}} @@ -105,7 +92,7 @@ jobs: org.opencontainers.image.title=${{ env.IMAGE_NAME }} org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} org.opencontainers.image.vendor=${{ github.repository_owner }} - org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}} + org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.${{ steps.date.outputs.version }} io.artifacthub.package.deprecated=false io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }} io.artifacthub.package.license=Apache-2.0 @@ -117,47 +104,42 @@ jobs: - name: Build Image id: build_image - uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2 + uses: redhat-actions/buildah-build@v2 with: containerfiles: | ./Containerfile - # Postfix image name with -custom to make it a little more descriptive - # Syntax: https://docs.github.com/en/actions/learn-github-actions/expressions#format image: ${{ env.IMAGE_NAME }} tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} build-args: | BASE_IMAGE=${{ matrix.variant.base_image }} + IMAGE_NAME=${{ env.IMAGE_NAME }} + IMAGE_VENDOR=${{ github.repository_owner }} oci: false - # Rechunk is a script that we use on Universal Blue to make sure there isnt a single huge layer when your image gets published. - # This does not make your image faster to download, just provides better resumability and fixes a few errors. - # Documentation for Rechunk is provided on their github repository at https://github.com/hhd-dev/rechunk - # You can enable it by uncommenting the following lines: - # - name: Run Rechunker - # id: rechunk - # uses: hhd-dev/rechunk@f153348d8100c1f504dec435460a0d7baf11a9d2 # v1.1.1 - # with: - # rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.1' - # ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" - # prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}" - # skip_compression: true - # version: ${{ env.CENTOS_VERSION }} - # labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator - - # This is necessary so that the podman socket can find the rechunked image on its storage - # - name: Load in podman and tag - # run: | - # IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }}) - # sudo rm -rf ${{ steps.rechunk.outputs.output }} - # for tag in ${{ steps.metadata.outputs.tags }}; do - # podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag - # done - - # These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing - # They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work + # Rechunk for optimized OCI layers + - name: Run Rechunker + id: rechunk + uses: hhd-dev/rechunk@v1.1.1 + if: github.event_name != 'pull_request' + with: + rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.3' + ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}" + prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}" + skip_compression: true + labels: ${{ steps.metadata.outputs.labels }} + + - name: Load rechunked image and tag + if: github.event_name != 'pull_request' + run: | + IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }}) + sudo rm -rf ${{ steps.rechunk.outputs.output }} + for tag in ${{ steps.metadata.outputs.tags }}; do + podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag + done + - name: Login to GitHub Container Registry - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3 + uses: docker/login-action@v3 if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) with: registry: ghcr.io @@ -165,7 +147,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Push To GHCR - uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2 + uses: redhat-actions/push-to-registry@v2 if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) id: push env: @@ -178,22 +160,19 @@ jobs: username: ${{ env.REGISTRY_USER }} password: ${{ env.REGISTRY_PASSWORD }} - # This section is optional and only needs to be enabled if you plan on distributing - # your project for others to consume. You will need to create a public and private key - # using Cosign and save the private key as a repository secret in Github for this workflow - # to consume. For more details, review the image signing section of the README. - name: Install Cosign - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + uses: sigstore/cosign-installer@v3 if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) - name: Sign container image if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) run: | - IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}" - for tag in ${{ steps.metadata.outputs.tags }}; do - cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag - done + # Sign by digest for better security + IMAGE_DIGEST="${{ steps.push.outputs.digest }}" + IMAGE_REF="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}@${IMAGE_DIGEST}" + + echo "Signing image: ${IMAGE_REF}" + cosign sign -y --key env://COSIGN_PRIVATE_KEY "${IMAGE_REF}" env: - TAGS: ${{ steps.push.outputs.digest }} COSIGN_EXPERIMENTAL: false COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} diff --git a/.gitignore b/.gitignore index a6c4a6a..ab799f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,20 @@ +# Secrets cosign.key -_build_* -output -_build-*/** + +# Build artifacts +_build* +_rechunk_output/ +output/ +output.env +previous.manifest.json +changelog.md + +# Titanoboa ISO builder _titanoboa/ + +# VM testing _vm_build/ + +# ISO files *.iso +result-iso/ diff --git a/Containerfile b/Containerfile index 036c9e2..fa4f098 100644 --- a/Containerfile +++ b/Containerfile @@ -1,40 +1,52 @@ -# This build argument allows building different variants (regular vs NVIDIA) -ARG BASE_IMAGE=ghcr.io/ublue-os/bluefin-dx:stable-daily +# Hypercube Container Build +# Aligned with Bluefin patterns -# Allow build scripts to be referenced without being copied into the final image +# ============================================ +# Build Arguments +# ============================================ +ARG BASE_IMAGE=ghcr.io/ublue-os/bluefin-dx:stable-daily +ARG IMAGE_NAME=hypercube +ARG IMAGE_VENDOR=binarypie-dev +ARG SHA_HEAD_SHORT="" + +# ============================================ +# Stage 1: Context Aggregation +# ============================================ +# Aggregate all build context into a single layer for mounting FROM scratch AS ctx -COPY build_files / -COPY branding /branding +COPY system_files /system_files +COPY build_files /build_files -# Base Image +# ============================================ +# Stage 2: Main Build +# ============================================ FROM ${BASE_IMAGE} -# Copy dot_files into the image at /usr/share/hypercube/config +# Re-declare ARGs after FROM (they don't persist across stages) +ARG IMAGE_NAME +ARG IMAGE_VENDOR +ARG SHA_HEAD_SHORT + +# Export build-time environment variables +ENV IMAGE_NAME=${IMAGE_NAME} +ENV IMAGE_VENDOR=${IMAGE_VENDOR} + +# Copy dot_files (config templates) into the image COPY dot_files /usr/share/hypercube/config # Ensure all config files are readable by everyone RUN chmod -R a+rX /usr/share/hypercube/config -## Other possible base images include: -# FROM ghcr.io/ublue-os/bazzite:latest -# FROM ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily -# -# ... and so on, here are more base images -# Universal Blue Images: https://github.com/orgs/ublue-os/packages -# Fedora base image: quay.io/fedora/fedora-bootc:41 -# CentOS base images: quay.io/centos-bootc/centos-bootc:stream10 - -### MODIFICATIONS -## make modifications desired in your image and install packages by modifying the build.sh script -## the following RUN directive does all the things required to run "build.sh" as recommended. - +# Build with mounted context and caches +# - Bind mount from ctx stage for build scripts and system files +# - Cache mounts for DNF and rpm-ostree to speed up rebuilds +# - Tmpfs for /tmp to avoid polluting the image RUN --mount=type=bind,from=ctx,source=/,target=/ctx \ - --mount=type=cache,dst=/var/cache \ - --mount=type=cache,dst=/var/log \ - --mount=type=tmpfs,dst=/tmp \ - /ctx/build.sh && \ - ostree container commit - -### LINTING -## Verify final image and contents are correct. + --mount=type=cache,dst=/var/cache/libdnf5 \ + --mount=type=cache,dst=/var/cache/rpm-ostree \ + --mount=type=tmpfs,dst=/tmp \ + /ctx/build_files/shared/build.sh && \ + ostree container commit + +# Final validation RUN bootc container lint diff --git a/Justfile b/Justfile index b56a2c5..7f199fe 100644 --- a/Justfile +++ b/Justfile @@ -1,87 +1,178 @@ +# Hypercube Build System +# Aligned with Bluefin patterns for consistency + +# Configuration +export repo_organization := env("REPO_ORGANIZATION", "binarypie-dev") export image_name := env("IMAGE_NAME", "hypercube") -export default_tag := env("DEFAULT_TAG", "latest") -export base_image := env("BASE_IMAGE", "ghcr.io/ublue-os/bluefin-dx:stable-daily") -export base_image_nvidia := env("BASE_IMAGE_NVIDIA", "ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily") +export base_image := env("BASE_IMAGE", "ghcr.io/ublue-os/bluefin-dx") +export base_image_nvidia := env("BASE_IMAGE_NVIDIA", "ghcr.io/ublue-os/bluefin-dx-nvidia") +export default_tag := env("DEFAULT_TAG", "stable-daily") +export rechunker_image := "ghcr.io/hhd-dev/rechunk:v1.0.3" -export SUDOIF := if `id -u` == "0" { "" } else { "sudo" } +# Runtime detection +export SUDO := if `id -u` == "0" { "" } else { "sudo" } export PODMAN := if path_exists("/usr/bin/podman") == "true" { "/usr/bin/podman" } else { "podman" } [private] default: @just --list -# Check Just Syntax -[group('Just')] -check: - #!/usr/bin/bash - find . -type f -name "*.just" | while read -r file; do - echo "Checking syntax: $file" - just --unstable --fmt --check -f $file - done - echo "Checking syntax: Justfile" - just --unstable --fmt --check -f Justfile - -# Fix Just Syntax -[group('Just')] -fix: - #!/usr/bin/bash - find . -type f -name "*.just" | while read -r file; do - echo "Checking syntax: $file" - just --unstable --fmt -f $file - done - echo "Checking syntax: Justfile" - just --unstable --fmt -f Justfile || { exit 1; } +# ============================================ +# Build Recipes +# ============================================ -# Clean Repo -[group('Utility')] -clean: - #!/usr/bin/bash - set -eoux pipefail - touch _build - find *_build* -exec rm -rf {} \; - rm -f previous.manifest.json - rm -f changelog.md - rm -f output.env - rm -rf output/ - rm -rf _titanoboa/ - rm -f *.iso - -# Build the image using the specified parameters +# Build container image [group('Build')] -build $target_image=image_name $tag=default_tag $base_img=base_image: +build flavor="main" ghcr="0" rechunk="0": #!/usr/bin/env bash set -euo pipefail + # Determine base image based on flavor + if [[ "{{ flavor }}" == "nvidia" ]]; then + BASE="{{ base_image_nvidia }}:{{ default_tag }}" + TAG="{{ default_tag }}-nvidia" + else + BASE="{{ base_image }}:{{ default_tag }}" + TAG="{{ default_tag }}" + fi + + IMAGE_FULL="{{ image_name }}:${TAG}" + + echo "========================================" + echo "Building: ${IMAGE_FULL}" + echo "Base: ${BASE}" + echo "========================================" + BUILD_ARGS=() - BUILD_ARGS+=("--build-arg" "BASE_IMAGE={{ base_img }}") + BUILD_ARGS+=("--build-arg" "BASE_IMAGE=${BASE}") + BUILD_ARGS+=("--build-arg" "IMAGE_NAME={{ image_name }}") + BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR={{ repo_organization }}") if [[ -z "$(git status -s)" ]]; then BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=$(git rev-parse --short HEAD)") fi - podman build \ - "${BUILD_ARGS[@]}" \ - --pull=newer \ - --tag "{{ target_image }}:{{ tag }}" \ - . + # Use rootful podman for GHCR builds + if [[ "{{ ghcr }}" == "1" ]]; then + {{ SUDO }} {{ PODMAN }} build \ + "${BUILD_ARGS[@]}" \ + --pull=newer \ + --tag "${IMAGE_FULL}" \ + . + else + {{ PODMAN }} build \ + "${BUILD_ARGS[@]}" \ + --pull=newer \ + --tag "${IMAGE_FULL}" \ + . + fi + + # Rechunk if requested + if [[ "{{ rechunk }}" == "1" ]]; then + just rechunk "{{ image_name }}" "${TAG}" + just load-rechunk "{{ image_name }}" "${TAG}" + fi + + echo "" + echo "========================================" + echo "Build complete: ${IMAGE_FULL}" + echo "========================================" -# Build the regular (non-NVIDIA) variant +# Build with rechunking enabled (recommended for production) [group('Build')] -build-regular $target_image=image_name: - @just build "{{ target_image }}" "{{ default_tag }}" "{{ base_image }}" +build-rechunk flavor="main": + @just build {{ flavor }} 0 1 -# Build the NVIDIA variant +# Build for GHCR push (rootful, with rechunking) [group('Build')] -build-nvidia $target_image=image_name: - @just build "{{ target_image }}" "{{ default_tag }}-nvidia" "{{ base_image_nvidia }}" +build-ghcr flavor="main": + @just build {{ flavor }} 1 1 -# Build both variants (regular and NVIDIA) +# Build both flavors +[group('Build')] +build-all: + @echo "Building main flavor..." + @just build-rechunk main + @echo "" + @echo "Building nvidia flavor..." + @just build-rechunk nvidia + +# Rechunk image for optimized OCI layers [group('Build')] -build-all $target_image=image_name: - @echo "Building regular variant..." - @just build-regular "{{ target_image }}" - @echo "Building NVIDIA variant..." - @just build-nvidia "{{ target_image }}" +[private] +rechunk image tag: + #!/usr/bin/env bash + set -euo pipefail + + IMAGE_FULL="localhost/{{ image }}:{{ tag }}" + OUTPUT_DIR="${PWD}/_rechunk_output" + + echo "Rechunking: ${IMAGE_FULL}" + + rm -rf "${OUTPUT_DIR}" + mkdir -p "${OUTPUT_DIR}" + + # Run rechunker container + {{ PODMAN }} run --rm \ + --privileged \ + --security-opt label=disable \ + -v "${OUTPUT_DIR}:/output" \ + -v /var/lib/containers:/var/lib/containers \ + {{ rechunker_image }} \ + "${IMAGE_FULL}" \ + /output + + echo "Rechunk output saved to: ${OUTPUT_DIR}" + +# Load rechunked image into podman +[group('Build')] +[private] +load-rechunk image tag: + #!/usr/bin/env bash + set -euo pipefail + + OUTPUT_DIR="${PWD}/_rechunk_output" + IMAGE_FULL="{{ image }}:{{ tag }}" + + if [[ ! -d "${OUTPUT_DIR}" ]]; then + echo "Error: Rechunk output not found at ${OUTPUT_DIR}" + exit 1 + fi + + echo "Loading rechunked image..." + + # Load the OCI image + {{ PODMAN }} load -i "${OUTPUT_DIR}/oci-archive.tar" + + # Tag it properly + LOADED_IMAGE=$({{ PODMAN }} images --format "{{`{{.ID}}`}}" | head -1) + {{ PODMAN }} tag "${LOADED_IMAGE}" "${IMAGE_FULL}" + + # Cleanup + rm -rf "${OUTPUT_DIR}" + + echo "Loaded: ${IMAGE_FULL}" + +# Run container interactively for testing +[group('Build')] +run flavor="main": + #!/usr/bin/env bash + set -euo pipefail + + if [[ "{{ flavor }}" == "nvidia" ]]; then + TAG="{{ default_tag }}-nvidia" + else + TAG="{{ default_tag }}" + fi + + {{ PODMAN }} run -it --rm \ + --privileged \ + "localhost/{{ image_name }}:${TAG}" \ + /bin/bash + +# ============================================ +# ISO Recipes +# ============================================ # Clone or update Titanoboa repository [group('ISO')] @@ -100,113 +191,101 @@ _titanoboa-setup: sed -i 's/PODMAN }} pull /PODMAN }} pull --policy=missing /' _titanoboa/Justfile sed -i 's/podman pull /podman pull --policy=missing /' _titanoboa/Justfile -# Build a live ISO using Titanoboa (requires sudo) +# Build ISO from local image [group('ISO')] -build-iso $target_image=image_name $tag=default_tag: _titanoboa-setup +build-iso flavor="main": _titanoboa-setup #!/usr/bin/bash set -euo pipefail - IMAGE_FULL="localhost/{{ target_image }}:{{ tag }}" + if [[ "{{ flavor }}" == "nvidia" ]]; then + TAG="{{ default_tag }}-nvidia" + ISO_NAME="{{ image_name }}-nvidia.iso" + else + TAG="{{ default_tag }}" + ISO_NAME="{{ image_name }}.iso" + fi + + IMAGE_FULL="localhost/{{ image_name }}:${TAG}" echo "Building ISO for ${IMAGE_FULL}..." - echo "" - # Check if image exists in user podman - ID=$(${PODMAN} images --filter reference="${IMAGE_FULL}" --format '{{ '{{.ID}}' }}') + # Check if image exists + ID=$({{ PODMAN }} images --filter reference="${IMAGE_FULL}" --format '{{`{{.ID}}`}}') if [[ -z "$ID" ]]; then - echo "Error: Image ${IMAGE_FULL} not found. Run 'just build-regular' first." + echo "Error: Image ${IMAGE_FULL} not found. Run 'just build-rechunk {{ flavor }}' first." exit 1 fi - # Copy image from user podman to root podman using podman image scp + # Copy image to root podman storage if running as non-root if [[ "${UID}" -gt 0 ]]; then echo "Copying image to root podman storage..." COPYTMP=$(mktemp -p "${PWD}" -d -t podman_scp.XXXXXXXXXX) - ${SUDOIF} TMPDIR=${COPYTMP} ${PODMAN} image scp "${UID}@localhost::${IMAGE_FULL}" root@localhost::"${IMAGE_FULL}" + {{ SUDO }} TMPDIR=${COPYTMP} {{ PODMAN }} image scp "${UID}@localhost::${IMAGE_FULL}" root@localhost::"${IMAGE_FULL}" rm -rf "${COPYTMP}" fi # Build ISO with Titanoboa cd _titanoboa - ${SUDOIF} just build "${IMAGE_FULL}" + {{ SUDO }} just build "${IMAGE_FULL}" # Fix ownership if [[ "${UID}" -gt 0 ]]; then - ${SUDOIF} chown "${UID}:$(id -g)" -R "${PWD}" + {{ SUDO }} chown "${UID}:$(id -g)" -R "${PWD}" fi # Move ISO to project root if [[ -f "output.iso" ]]; then - mv output.iso "../{{ image_name }}-regular.iso" + mv output.iso "../${ISO_NAME}" echo "" - echo "==========================================" - echo "ISO built successfully: {{ image_name }}-regular.iso" + echo "========================================" + echo "ISO built successfully: ${ISO_NAME}" + echo "========================================" else - echo "" - echo "==========================================" echo "Error: ISO build failed." exit 1 fi -# Build a live ISO for the NVIDIA variant using Titanoboa +# Build ISO from GHCR image [group('ISO')] -build-iso-nvidia $target_image=image_name $tag=(default_tag + "-nvidia"): _titanoboa-setup +build-iso-ghcr flavor="main": _titanoboa-setup #!/usr/bin/bash set -euo pipefail - IMAGE_FULL="localhost/{{ target_image }}:{{ tag }}" - - echo "Building ISO for ${IMAGE_FULL}..." - echo "" + REGISTRY="ghcr.io/{{ repo_organization }}" - # Check if image exists in user podman - ID=$(${PODMAN} images --filter reference="${IMAGE_FULL}" --format '{{ '{{.ID}}' }}') - if [[ -z "$ID" ]]; then - echo "Error: Image ${IMAGE_FULL} not found. Run 'just build-nvidia' first." - exit 1 + if [[ "{{ flavor }}" == "nvidia" ]]; then + TAG="latest-nvidia" + ISO_NAME="{{ image_name }}-nvidia.iso" + else + TAG="latest" + ISO_NAME="{{ image_name }}.iso" fi - # Copy image from user podman to root podman using podman image scp - if [[ "${UID}" -gt 0 ]]; then - echo "Copying image to root podman storage..." - COPYTMP=$(mktemp -p "${PWD}" -d -t podman_scp.XXXXXXXXXX) - ${SUDOIF} TMPDIR=${COPYTMP} ${PODMAN} image scp "${UID}@localhost::${IMAGE_FULL}" root@localhost::"${IMAGE_FULL}" - rm -rf "${COPYTMP}" - fi + IMAGE_FULL="${REGISTRY}/{{ image_name }}:${TAG}" + + echo "Building ISO for ${IMAGE_FULL}..." - # Build ISO with Titanoboa cd _titanoboa - ${SUDOIF} just build "${IMAGE_FULL}" + {{ SUDO }} just build "${IMAGE_FULL}" - # Fix ownership if [[ "${UID}" -gt 0 ]]; then - ${SUDOIF} chown "${UID}:$(id -g)" -R "${PWD}" + {{ SUDO }} chown "${UID}:$(id -g)" -R "${PWD}" fi - # Move ISO to project root if [[ -f "output.iso" ]]; then - mv output.iso "../{{ image_name }}-nvidia.iso" + mv output.iso "../${ISO_NAME}" echo "" - echo "==========================================" - echo "ISO built successfully: {{ image_name }}-nvidia.iso" + echo "========================================" + echo "ISO built successfully: ${ISO_NAME}" + echo "========================================" else - echo "" - echo "==========================================" echo "Error: ISO build failed." exit 1 fi -# Build container and then create ISO (regular variant) -[group('ISO')] -rebuild-iso: build-regular build-iso - -# Build container and then create ISO (NVIDIA variant) +# Run ISO in QEMU VM [group('ISO')] -rebuild-iso-nvidia: build-nvidia build-iso-nvidia - -# Run a virtual machine from an ISO using qemu container -[group('VM')] -run-vm-iso iso_file: +run-iso iso_file: #!/usr/bin/bash set -euo pipefail @@ -215,7 +294,7 @@ run-vm-iso iso_file: exit 1 fi - # Determine an available port to use + # Find available port port=8006 while grep -q :${port} <<< $(ss -tunalp); do port=$(( port + 1 )) @@ -223,48 +302,101 @@ run-vm-iso iso_file: echo "Using Port: ${port}" echo "Connect to http://localhost:${port}" - # Ram Size + # Calculate RAM size mem_free=$(awk '/MemAvailable/ { printf "%.0f\n", $2/1024/1024 - 1 }' /proc/meminfo) ram_size=$(( mem_free > 64 ? mem_free / 2 : (mem_free > 8 ? 8 : (mem_free < 3 ? 3 : mem_free)) )) - # Set up the arguments for running the VM - run_args=() - run_args+=(--rm --privileged) - run_args+=(--pull=newer) - run_args+=(--publish "127.0.0.1:${port}:8006") - run_args+=(--env "CPU_CORES=$(( $(nproc) / 2 > 0 ? $(nproc) / 2 : 1 ))") - run_args+=(--env "RAM_SIZE=${ram_size}G") - run_args+=(--env "DISK_SIZE=64G") - run_args+=(--env "TPM=Y") - run_args+=(--env "GPU=Y") - run_args+=(--env "BOOT_MODE=windows_secure") - run_args+=(--device=/dev/kvm) - run_args+=(--volume "$(realpath {{ iso_file }})":"/boot.iso") - run_args+=(ghcr.io/qemus/qemu) - - # Run the VM and open the browser to connect - podman run "${run_args[@]}" & + # Run QEMU container + {{ PODMAN }} run --rm --privileged \ + --pull=newer \ + --publish "127.0.0.1:${port}:8006" \ + --env "CPU_CORES=$(( $(nproc) / 2 > 0 ? $(nproc) / 2 : 1 ))" \ + --env "RAM_SIZE=${ram_size}G" \ + --env "DISK_SIZE=64G" \ + --env "TPM=Y" \ + --env "GPU=Y" \ + --env "BOOT_MODE=windows_secure" \ + --device=/dev/kvm \ + --volume "$(realpath {{ iso_file }})":"/boot.iso" \ + ghcr.io/qemus/qemu & + sleep 3 xdg-open http://localhost:${port} -# Runs shellcheck on all Bash scripts +# ============================================ +# Verification Recipes +# ============================================ + +# Verify container image signature +[group('Verify')] +verify-container image tag: + #!/usr/bin/env bash + set -euo pipefail + + IMAGE_REF="ghcr.io/{{ repo_organization }}/{{ image }}:{{ tag }}" + + echo "Verifying signature for: ${IMAGE_REF}" + + cosign verify \ + --key cosign.pub \ + "${IMAGE_REF}" + + echo "Signature verified successfully!" + +# ============================================ +# Utility Recipes +# ============================================ + +# Clean build artifacts +[group('Utility')] +clean: + #!/usr/bin/bash + set -eoux pipefail + rm -rf _build* _titanoboa _rechunk_output + rm -f previous.manifest.json changelog.md output.env + rm -rf output/ + rm -f *.iso + +# Lint bash scripts with shellcheck [group('Lint')] lint: #!/usr/bin/env bash set -eoux pipefail if ! command -v shellcheck &> /dev/null; then - echo "shellcheck could not be found. Please install it." + echo "shellcheck not found. Please install it." exit 1 fi - /usr/bin/find . -iname "*.sh" -type f -exec shellcheck "{}" ';' + find . -type f -name "*.sh" -exec shellcheck {} \; -# Runs shfmt on all Bash scripts +# Format bash scripts with shfmt [group('Lint')] format: #!/usr/bin/env bash set -eoux pipefail if ! command -v shfmt &> /dev/null; then - echo "shfmt could not be found. Please install it." + echo "shfmt not found. Please install it." exit 1 fi - /usr/bin/find . -iname "*.sh" -type f -exec shfmt --write "{}" ';' + find . -type f -name "*.sh" -exec shfmt --write {} \; + +# Check Just syntax +[group('Just')] +check: + #!/usr/bin/bash + find . -type f -name "*.just" | while read -r file; do + echo "Checking syntax: $file" + just --unstable --fmt --check -f "$file" + done + echo "Checking syntax: Justfile" + just --unstable --fmt --check -f Justfile + +# Fix Just syntax +[group('Just')] +fix: + #!/usr/bin/bash + find . -type f -name "*.just" | while read -r file; do + echo "Fixing syntax: $file" + just --unstable --fmt -f "$file" + done + echo "Fixing syntax: Justfile" + just --unstable --fmt -f Justfile || exit 1 diff --git a/build_files/build.sh b/build_files/build.sh deleted file mode 100755 index a0d3564..0000000 --- a/build_files/build.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash - -set -ouex pipefail - -### Apply Hypercube Branding -# This must run early to set up os-release and image-info -/ctx/00-hypercube-branding.sh - -### Install packages - -# Packages can be installed from any enabled yum repo on the image. -# RPMfusion repos are available by default in ublue main images -# List of rpmfusion packages can be found here: -# https://mirrors.rpmfusion.org/mirrorlist?path=free/fedora/updates/39/x86_64/repoview/index.html&protocol=https&redirect=1 - -# Compositor / Hyprland Utilities -dnf5 -y clean all -dnf5 -y copr enable sdegler/hyprland -dnf5 -y install waybar-git xdg-desktop-portal-hyprland hyprland hyprland-contrib hyprland-plugins hyprpaper hyprpicker hypridle hyprshot hyprlock pyprland xdg-desktop-portal-hyprland hyprland-qtutils hyprpolkitagent - -# CLI Tools -dnf5 -y install fd-find brightnessctl playerctl lazygit qt6ct - -# Tokyo Night GTK Theme -dnf5 -y install gtk-murrine-engine sassc git adwaita-cursor-theme -# Clone and install Tokyo Night GTK theme -git clone --depth 1 https://github.com/Fausto-Korpsvart/Tokyonight-GTK-Theme.git /tmp/tokyonight-gtk -/tmp/tokyonight-gtk/themes/install.sh -d /usr/share/themes -n Tokyonight --tweaks black -# Install icon theme -mkdir -p /usr/share/icons -cp -r /tmp/tokyonight-gtk/icons/Tokyonight-Dark /usr/share/icons/ -cp -r /tmp/tokyonight-gtk/icons/Tokyonight-Light /usr/share/icons/ -gtk-update-icon-cache /usr/share/icons/Tokyonight-Dark 2>/dev/null || true -gtk-update-icon-cache /usr/share/icons/Tokyonight-Light 2>/dev/null || true -rm -rf /tmp/tokyonight-gtk - -# Remove extra things -# TODO: Figure out what we don't need from solopasha/hyprland - -# Quickshell - Application Launcher, Notifications, OSD -dnf5 -y copr enable errornointernet/quickshell -dnf5 -y install quickshell - -# Terminals -dnf5 -y copr enable wezfurlong/wezterm-nightly -dnf5 -y install wezterm - -dnf -y copr enable scottames/ghostty -dnf -y install ghostty - -# Editor -dnf5 -y copr enable agriffis/neovim-nightly -dnf5 -y install neovim python3-neovim - -# Install nvimd (containerized neovim wrapper) -install -Dm755 /usr/share/hypercube/config/nvim/bin/nvimd /usr/bin/nvimd - -# Fish shell configs -# Fish doesn't use XDG_CONFIG_DIRS, so we install to /etc/fish -install -Dm644 /usr/share/hypercube/config/fish/config.fish /etc/fish/config.fish -cp -r /usr/share/hypercube/config/fish/conf.d /etc/fish/ -cp -r /usr/share/hypercube/config/fish/functions /etc/fish/ 2>/dev/null || true -cp -r /usr/share/hypercube/config/fish/completions /etc/fish/ 2>/dev/null || true - -# Wezterm configs -# Wezterm doesn't support XDG_CONFIG_DIRS for system defaults, so we install to /etc/skel -# which will be copied to new user home directories -install -Dm644 /usr/share/hypercube/config/wezterm/wezterm.lua /etc/skel/.config/wezterm/wezterm.lua - -# GTK theme settings - install to /etc/skel for new users -install -Dm644 /usr/share/hypercube/config/gtk-3.0/settings.ini /etc/skel/.config/gtk-3.0/settings.ini -install -Dm644 /usr/share/hypercube/config/gtk-4.0/settings.ini /etc/skel/.config/gtk-4.0/settings.ini - -# Git UI tools configs (Tokyo Night themed) -install -Dm644 /usr/share/hypercube/config/gitui/theme.ron /etc/skel/.config/gitui/theme.ron -install -Dm644 /usr/share/hypercube/config/gitui/key_bindings.ron /etc/skel/.config/gitui/key_bindings.ron -install -Dm644 /usr/share/hypercube/config/lazygit/config.yml /etc/skel/.config/lazygit/config.yml - -# Qt6 theming (Tokyo Night color scheme) -install -Dm644 /usr/share/hypercube/config/qt6ct/qt6ct.conf /etc/skel/.config/qt6ct/qt6ct.conf -install -Dm644 /usr/share/hypercube/config/qt6ct/colors/TokyoNight.conf /usr/share/qt6ct/colors/TokyoNight.conf - - -# Configure XDG environment for Hypercube -# This makes all configs in /usr/share/hypercube/config discoverable -# while preserving user and admin override capabilities -install -Dm644 /ctx/60-hypercube-xdg.conf /usr/lib/environment.d/60-hypercube-xdg.conf - -# systemctl enable podman.socket - - -### Install Quickshell config -# Install quickshell launcher configuration to system-wide location -if [ -d /usr/share/hypercube/config/quickshell ]; then - echo "Installing Quickshell launcher configuration..." - mkdir -p /etc/skel/.config/quickshell - cp -r /usr/share/hypercube/config/quickshell/* /etc/skel/.config/quickshell/ - echo "Quickshell configuration installed successfully" -fi diff --git a/build_files/00-hypercube-branding.sh b/build_files/hypercube/00-hypercube-branding.sh similarity index 100% rename from build_files/00-hypercube-branding.sh rename to build_files/hypercube/00-hypercube-branding.sh diff --git a/build_files/hypercube/01-hypercube-packages.sh b/build_files/hypercube/01-hypercube-packages.sh new file mode 100755 index 0000000..fe8cf7a --- /dev/null +++ b/build_files/hypercube/01-hypercube-packages.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Hypercube Package Installation +# Installs Hyprland compositor stack, CLI tools, terminals, and editors + +set -ouex pipefail + +echo "Installing Hypercube packages..." + +# Clean DNF cache first +dnf5 -y clean all + +### Compositor / Hyprland Stack +dnf5 -y copr enable sdegler/hyprland +dnf5 -y install \ + hyprland \ + hyprland-contrib \ + hyprland-plugins \ + hyprland-qtutils \ + hyprpaper \ + hyprpicker \ + hypridle \ + hyprshot \ + hyprlock \ + hyprpolkitagent \ + pyprland \ + waybar-git \ + xdg-desktop-portal-hyprland + +### CLI Tools (skip packages already in bluefin-dx) +dnf5 -y install \ + fd-find \ + qt6ct + +### Lazygit from COPR +dnf5 -y copr enable atim/lazygit +dnf5 -y install lazygit + +### Quickshell - Application Launcher, Notifications, OSD +dnf5 -y copr enable errornointernet/quickshell +dnf5 -y install quickshell + +### Terminals +dnf5 -y copr enable wezfurlong/wezterm-nightly +dnf5 -y install wezterm + +dnf5 -y copr enable scottames/ghostty +dnf5 -y install ghostty + +### Editor +dnf5 -y copr enable agriffis/neovim-nightly +dnf5 -y install neovim python3-neovim + +echo "Hypercube packages installed successfully" diff --git a/build_files/hypercube/02-hypercube-theming.sh b/build_files/hypercube/02-hypercube-theming.sh new file mode 100755 index 0000000..2ce1f05 --- /dev/null +++ b/build_files/hypercube/02-hypercube-theming.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Hypercube Theming +# Installs Tokyo Night GTK theme and icon themes + +set -ouex pipefail + +echo "Installing Tokyo Night theme..." + +### Build dependencies for Tokyo Night GTK theme +dnf5 -y install gtk-murrine-engine sassc git adwaita-cursor-theme + +### Clone and install Tokyo Night GTK theme +git clone --depth 1 https://github.com/Fausto-Korpsvart/Tokyonight-GTK-Theme.git /tmp/tokyonight-gtk +/tmp/tokyonight-gtk/themes/install.sh -d /usr/share/themes -n Tokyonight --tweaks black + +### Install icon themes +mkdir -p /usr/share/icons +cp -r /tmp/tokyonight-gtk/icons/Tokyonight-Dark /usr/share/icons/ +cp -r /tmp/tokyonight-gtk/icons/Tokyonight-Light /usr/share/icons/ + +### Update icon caches (ignore errors if themes don't have index.theme) +gtk-update-icon-cache /usr/share/icons/Tokyonight-Dark 2>/dev/null || true +gtk-update-icon-cache /usr/share/icons/Tokyonight-Light 2>/dev/null || true + +### Cleanup +rm -rf /tmp/tokyonight-gtk + +echo "Tokyo Night theme installed successfully" diff --git a/build_files/hypercube/03-hypercube-configs.sh b/build_files/hypercube/03-hypercube-configs.sh new file mode 100755 index 0000000..37a465e --- /dev/null +++ b/build_files/hypercube/03-hypercube-configs.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Hypercube Configuration Installation +# Installs config files to system locations and /etc/skel for new users + +set -ouex pipefail + +echo "Installing Hypercube configurations..." + +CONFIG_DIR="/usr/share/hypercube/config" + +### Install nvimd (containerized neovim wrapper) +install -Dm755 "${CONFIG_DIR}/nvim/bin/nvimd" /usr/bin/nvimd + +### Fish shell configs +# Fish doesn't use XDG_CONFIG_DIRS, so we install to /etc/fish +install -Dm644 "${CONFIG_DIR}/fish/config.fish" /etc/fish/config.fish +cp -r "${CONFIG_DIR}/fish/conf.d" /etc/fish/ +cp -r "${CONFIG_DIR}/fish/functions" /etc/fish/ 2>/dev/null || true +cp -r "${CONFIG_DIR}/fish/completions" /etc/fish/ 2>/dev/null || true + +### Wezterm configs +# Wezterm doesn't support XDG_CONFIG_DIRS for system defaults +install -Dm644 "${CONFIG_DIR}/wezterm/wezterm.lua" /etc/skel/.config/wezterm/wezterm.lua + +### GTK theme settings - install to /etc/skel for new users +install -Dm644 "${CONFIG_DIR}/gtk-3.0/settings.ini" /etc/skel/.config/gtk-3.0/settings.ini +install -Dm644 "${CONFIG_DIR}/gtk-4.0/settings.ini" /etc/skel/.config/gtk-4.0/settings.ini + +### Git UI tools configs (Tokyo Night themed) +install -Dm644 "${CONFIG_DIR}/gitui/theme.ron" /etc/skel/.config/gitui/theme.ron +install -Dm644 "${CONFIG_DIR}/gitui/key_bindings.ron" /etc/skel/.config/gitui/key_bindings.ron +install -Dm644 "${CONFIG_DIR}/lazygit/config.yml" /etc/skel/.config/lazygit/config.yml + +### Qt6 theming (Tokyo Night color scheme) +install -Dm644 "${CONFIG_DIR}/qt6ct/qt6ct.conf" /etc/skel/.config/qt6ct/qt6ct.conf +install -Dm644 "${CONFIG_DIR}/qt6ct/colors/TokyoNight.conf" /usr/share/qt6ct/colors/TokyoNight.conf + +### Quickshell launcher configuration +if [ -d "${CONFIG_DIR}/quickshell" ]; then + echo "Installing Quickshell launcher configuration..." + mkdir -p /etc/skel/.config/quickshell + cp -r "${CONFIG_DIR}/quickshell/"* /etc/skel/.config/quickshell/ + echo "Quickshell configuration installed successfully" +fi + +echo "Hypercube configurations installed successfully" diff --git a/build_files/hypercube/99-tests.sh b/build_files/hypercube/99-tests.sh new file mode 100755 index 0000000..74dddf6 --- /dev/null +++ b/build_files/hypercube/99-tests.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Hypercube Validation Tests +# Verifies that the build was successful + +set -ouex pipefail + +echo "Running Hypercube validation tests..." + +### Check critical packages are installed +REQUIRED_PACKAGES=( + "hyprland" + "hyprlock" + "hypridle" + "quickshell" + "wezterm" + "ghostty" + "neovim" + "lazygit" +) + +for pkg in "${REQUIRED_PACKAGES[@]}"; do + if ! rpm -q "$pkg" &>/dev/null; then + echo "ERROR: Required package '$pkg' is not installed!" + exit 1 + fi + echo " OK: $pkg installed" +done + +### Check critical files exist +REQUIRED_FILES=( + "/usr/share/hypercube/image-info.json" + "/usr/lib/environment.d/60-hypercube-xdg.conf" + "/usr/bin/nvimd" + "/etc/fish/config.fish" + "/usr/share/themes/Tokyonight-Dark/gtk-3.0/gtk.css" + "/usr/share/icons/Tokyonight-Dark/index.theme" +) + +for file in "${REQUIRED_FILES[@]}"; do + if [ ! -e "$file" ]; then + echo "ERROR: Required file '$file' does not exist!" + exit 1 + fi + echo " OK: $file exists" +done + +### Check os-release branding +if ! grep -q "ID=hypercube" /usr/lib/os-release; then + echo "ERROR: os-release branding not applied!" + exit 1 +fi +echo " OK: os-release branding applied" + +echo "All Hypercube validation tests passed!" diff --git a/build_files/shared/build.sh b/build_files/shared/build.sh new file mode 100755 index 0000000..94862f1 --- /dev/null +++ b/build_files/shared/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Hypercube Build Orchestrator +# Main build script that coordinates all build steps + +set -ouex pipefail + +echo "========================================" +echo "Starting Hypercube Build" +echo "========================================" + +### Rsync system files to root filesystem +echo "Installing system files..." +rsync -rlpvh --ignore-existing /ctx/system_files/shared/ / + +### Run hypercube build scripts in order +echo "Running build scripts..." +for script in /ctx/build_files/hypercube/*.sh; do + if [[ -f "$script" && -x "$script" ]]; then + echo "" + echo "========================================" + echo "Running: $(basename "$script")" + echo "========================================" + "$script" + fi +done + +### Final cleanup +echo "" +echo "========================================" +echo "Running cleanup..." +echo "========================================" +/ctx/build_files/shared/clean-stage.sh + +echo "" +echo "========================================" +echo "Hypercube Build Complete!" +echo "========================================" diff --git a/build_files/shared/clean-stage.sh b/build_files/shared/clean-stage.sh new file mode 100755 index 0000000..65ce81d --- /dev/null +++ b/build_files/shared/clean-stage.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Hypercube Cleanup Script +# Disables COPR repos and cleans up after build + +set -ouex pipefail + +echo "Disabling COPR repositories..." + +# Disable all COPR repos that were enabled during build +# This ensures the final image doesn't have external repos enabled +dnf5 -y copr disable sdegler/hyprland || true +dnf5 -y copr disable errornointernet/quickshell || true +dnf5 -y copr disable wezfurlong/wezterm-nightly || true +dnf5 -y copr disable scottames/ghostty || true +dnf5 -y copr disable agriffis/neovim-nightly || true +dnf5 -y copr disable atim/lazygit || true + +echo "Cleaning package caches..." +dnf5 -y clean all + +# Remove any leftover build artifacts +rm -rf /tmp/* 2>/dev/null || true + +echo "Cleanup complete" diff --git a/build_files/hypercube-kargs.json b/system_files/shared/usr/lib/bootc/kargs.d/hypercube-kargs.json similarity index 100% rename from build_files/hypercube-kargs.json rename to system_files/shared/usr/lib/bootc/kargs.d/hypercube-kargs.json diff --git a/build_files/60-hypercube-xdg.conf b/system_files/shared/usr/lib/environment.d/60-hypercube-xdg.conf similarity index 96% rename from build_files/60-hypercube-xdg.conf rename to system_files/shared/usr/lib/environment.d/60-hypercube-xdg.conf index 7dc9e9f..64cda04 100644 --- a/build_files/60-hypercube-xdg.conf +++ b/system_files/shared/usr/lib/environment.d/60-hypercube-xdg.conf @@ -17,8 +17,7 @@ XDG_CONFIG_DIRS=/etc/xdg:/usr/share/hypercube/config XDG_DATA_DIRS=/usr/local/share:/usr/share:/usr/share/hypercube/data # GTK theme settings for Wayland -GTK_THEME=Tokyonight-Dark-BL +GTK_THEME=Tokyonight-Dark # Qt theming - use qt6ct for Tokyo Night colors QT_QPA_PLATFORMTHEME=qt6ct -