Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bb6f8dddd
|
||
|
|
0fbec83573
|
||
|
|
a6c99b72d0
|
||
|
|
c64c64dc97
|
||
|
|
319333e400
|
||
|
|
bb6f64e977
|
||
|
|
3b3764573e
|
||
|
|
8501a60165
|
||
|
|
7c601ca53d
|
||
|
|
f3bd10cf0f
|
||
|
|
83ed87f6a9
|
||
|
|
5ffd5d0d82
|
||
|
|
8484bddcf2
|
||
|
|
0755091721
|
||
|
|
c71168371d
|
||
|
|
117b5e97aa
|
||
|
|
8a88921913
|
||
|
|
9614192416
|
||
|
|
2f1ac8d052
|
||
|
|
fa7eff8517
|
||
|
|
24f3f0f399
|
||
|
|
ac59de33c8
|
||
|
|
da0855d341
|
||
|
|
50d49bbe38 | ||
|
|
1090e3c75b
|
||
|
|
48b760d54e
|
||
|
|
7f91c189db
|
||
|
|
3816877b12
|
||
|
|
c9cf5ead97
|
||
|
|
01c7c4e1fa
|
||
|
|
d5356b772e
|
||
|
|
75bc4b3f4c | ||
|
|
10198915a1
|
||
|
|
56c02781c2
|
||
|
|
8e6e06155c
|
||
|
|
22bae5f19b
|
||
|
|
2dbbb3321d
|
||
|
|
c4ce0b3534
|
||
|
|
3c592d1e84
|
||
|
|
aad0ea2e03
|
||
|
|
2eb1e9f61a
|
||
|
|
08e947c7ea
|
+534
-43
@@ -1,10 +1,14 @@
|
|||||||
name: Scheduled ArchISO Build
|
name: Automated Arch ISO Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 0 1 * *" # Runs monthly on the 1st day of the month
|
- cron: "0 0 1 * *" # Runs monthly on the 1st day of the month
|
||||||
workflow_dispatch: # Allows manual triggers (multiple times a month)
|
workflow_dispatch: # Allows manual triggers (multiple times a month)
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: iso-build
|
||||||
|
cancel-in-progress: false # Never kill a build that is mid-flight
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: archlinux
|
runs-on: archlinux
|
||||||
@@ -15,80 +19,567 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup local AUR repo
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
shopt -s nullglob
|
||||||
|
mkdir -p /tmp/localrepo
|
||||||
|
cp localrepo/*.pkg.tar.zst localrepo/local-aur.db* localrepo/local-aur.files* /tmp/localrepo/
|
||||||
|
sed -i 's|file:///home/alvin/AlvinArch/localrepo|file:///tmp/localrepo|' pacman.conf
|
||||||
|
# The medium needs its own copy: the ISO's /etc/pacman.conf points
|
||||||
|
# [local-aur] at file:///opt/localrepo, which pacstrap reads at
|
||||||
|
# install time to resolve packages that are not in the official repos
|
||||||
|
# (built during the ISO build and harvested there by
|
||||||
|
# airootfs/root/customize_airootfs.sh).
|
||||||
|
mkdir -p airootfs/opt/localrepo
|
||||||
|
shipped=(localrepo/*.pkg.tar.zst localrepo/local-aur.db* localrepo/local-aur.files*)
|
||||||
|
if (( ${#shipped[@]} > 0 )); then
|
||||||
|
cp -L "${shipped[@]}" airootfs/opt/localrepo/
|
||||||
|
fi
|
||||||
|
echo "airootfs/opt/localrepo: $(ls airootfs/opt/localrepo | wc -l) file(s)"
|
||||||
|
|
||||||
- name: Install archiso and dependencies
|
- name: Install archiso and dependencies
|
||||||
run: |
|
run: |
|
||||||
pacman -Syu --noconfirm archiso jq
|
set -euo pipefail
|
||||||
|
# Install with a *private* config instead of /etc/pacman.conf.
|
||||||
|
# The host config is shared mutable state: the tests workflow
|
||||||
|
# rewrites it and jobs overlap on this runner (runs 132 and 133
|
||||||
|
# ran concurrently), so writing it here could corrupt a concurrent
|
||||||
|
# tests run. It also carries [cachyos] and [chaotic-aur] leftovers
|
||||||
|
# from tests.yaml, and syncing those two repos means extra DNS
|
||||||
|
# lookups against a gateway that intermittently drops UDP/53 —
|
||||||
|
# that is what failed run 131 at this very step. The build only
|
||||||
|
# needs archiso/jq from extra; mkarchiso reads the *profile's*
|
||||||
|
# pacman.conf for everything that goes into the ISO.
|
||||||
|
BUILD_CONF=$(mktemp)
|
||||||
|
trap 'rm -f "$BUILD_CONF"' EXIT
|
||||||
|
cat > "$BUILD_CONF" << 'STOCKCONF'
|
||||||
|
[options]
|
||||||
|
DisableSandbox
|
||||||
|
HoldPkg = pacman glibc
|
||||||
|
Architecture = auto
|
||||||
|
CheckSpace
|
||||||
|
ParallelDownloads = 5
|
||||||
|
SigLevel = Required DatabaseOptional
|
||||||
|
LocalFileSigLevel = Optional
|
||||||
|
|
||||||
|
[core]
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
Include = /etc/pacman.d/mirrorlist
|
||||||
|
STOCKCONF
|
||||||
|
sed -i 's/^ //' "$BUILD_CONF"
|
||||||
|
|
||||||
|
# Warm the resolver cache for the mirrors we are about to query.
|
||||||
|
# systemd-resolved serves later lookups from cache, so a gateway
|
||||||
|
# UDP/53 burst cannot hit them again. Failures here are not fatal —
|
||||||
|
# the retry loop below is the real safety net.
|
||||||
|
for host in mirror.aarnet.edu.au gsl-syd.mm.fcix.net au.arch.niranjan.co; do
|
||||||
|
for try in 1 2 3 4 5; do
|
||||||
|
if getent hosts "$host" >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " ⏳ DNS for $host failed (try $try/5), retrying in $(( try * 3 ))s..."
|
||||||
|
sleep $(( try * 3 ))
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# The gateway drops DNS queries in bursts; one burst must not fail
|
||||||
|
# the whole job, so retry with backoff before giving up.
|
||||||
|
synced=0
|
||||||
|
for try in 1 2 3 4 5; do
|
||||||
|
if pacman --config "$BUILD_CONF" -Syu --noconfirm --needed archiso jq; then
|
||||||
|
synced=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " ⚠️ pacman -Syu failed (attempt $try/5), retrying in $(( try * 15 ))s..." >&2
|
||||||
|
sleep $(( try * 15 ))
|
||||||
|
done
|
||||||
|
if [ "$synced" -ne 1 ]; then
|
||||||
|
echo "❌ pacman -Syu failed after 5 attempts — giving up" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Ensure /dev/fd symlinks exist for mkinitcpio and procsub
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# mkinitcpio's preset step pipes through /dev/stdin and bash process
|
||||||
|
# substitution (< <(...)) uses /dev/fd; both break if these symlinks
|
||||||
|
# are missing (they are normally created once at boot by mkinitcpio's
|
||||||
|
# init). Two places need them, so cover both:
|
||||||
|
# 1. the executor's own /dev: mkarchiso reads /dev/stdin on the host
|
||||||
|
# (machine-id, version, pkglist) and the workflow's own scripts use
|
||||||
|
# process substitution here. A no-op if the links already exist.
|
||||||
|
ln -sfn /proc/self/fd /dev/fd
|
||||||
|
ln -sfn /proc/self/fd/0 /dev/stdin
|
||||||
|
ln -sfn /proc/self/fd/1 /dev/stdout
|
||||||
|
ln -sfn /proc/self/fd/2 /dev/stderr
|
||||||
|
# 2. the chroot's /dev: devtmpfs is single-instance, so mounting it
|
||||||
|
# here yields the same tree that pacstrap/arch-chroot expose as
|
||||||
|
# <chroot>/dev. When the executor's /dev is itself devtmpfs (1)
|
||||||
|
# already fixed that tree; this pass is what makes it work when
|
||||||
|
# the executor's /dev is a plain tmpfs or directory instead.
|
||||||
|
d="$(mktemp -d)"
|
||||||
|
trap 'umount "$d" 2>/dev/null || true; rmdir "$d" 2>/dev/null || true' EXIT
|
||||||
|
mount -t devtmpfs devtmpfs "$d"
|
||||||
|
ln -sfn /proc/self/fd "$d/fd"
|
||||||
|
ln -sfn /proc/self/fd/0 "$d/stdin"
|
||||||
|
ln -sfn /proc/self/fd/1 "$d/stdout"
|
||||||
|
ln -sfn /proc/self/fd/2 "$d/stderr"
|
||||||
|
ls -l "$d/fd" "$d/stdin" "$d/stdout" "$d/stderr"
|
||||||
|
umount "$d"
|
||||||
|
rmdir "$d"
|
||||||
|
trap - EXIT
|
||||||
|
|
||||||
- name: Build Arch ISO
|
- name: Build Arch ISO
|
||||||
run: |
|
run: |
|
||||||
# Replace 'releng' with your custom profile directory if needed
|
set -euo pipefail
|
||||||
mkarchiso -v -w work -o out/ releng
|
# Pin one timestamp for the whole job: mkarchiso derives the ISO label,
|
||||||
|
# volume UUID, file mtimes, and ext4 hash seed from SOURCE_DATE_EPOCH.
|
||||||
|
# Exporting it explicitly makes every timestamp-derived value traceable
|
||||||
|
# (and lets later steps log the same value via $GITHUB_ENV).
|
||||||
|
SOURCE_DATE_EPOCH="$(date -u +%s)"
|
||||||
|
export SOURCE_DATE_EPOCH
|
||||||
|
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> "$GITHUB_ENV"
|
||||||
|
echo "Building with SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
|
||||||
|
# Clean up immediately even if this step is interrupted (cancel/exit):
|
||||||
|
# unmount leftovers first, then remove the multi-GB work dir.
|
||||||
|
trap 'umount -R "$PWD/work" 2>/dev/null || true; rm -rf "$PWD/work"' EXIT HUP INT TERM
|
||||||
|
rm -rf "$PWD/work"
|
||||||
|
# Always start from an empty out dir so stale ISOs are never re-uploaded
|
||||||
|
rm -rf "$PWD/out"
|
||||||
|
mkdir -p "$PWD/out"
|
||||||
|
mkarchiso -v -w "$PWD/work" -o "$PWD/out" -- "$PWD"
|
||||||
|
|
||||||
|
- name: Verify ISO search metadata
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
shopt -s nullglob
|
||||||
|
isos=(out/*.iso)
|
||||||
|
if (( ${#isos[@]} != 1 )); then
|
||||||
|
echo "❌ Expected exactly 1 ISO in out/, found ${#isos[@]}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
iso=${isos[0]}
|
||||||
|
|
||||||
|
# blkid exits non-zero when a field is missing; keep going so the
|
||||||
|
# explicit guard below can report a useful error.
|
||||||
|
vol_uuid=$(blkid -o value -s UUID "$iso" || true)
|
||||||
|
vol_label=$(blkid -o value -s LABEL "$iso" || true)
|
||||||
|
if [ -z "$vol_uuid" ]; then
|
||||||
|
echo "❌ blkid found no UUID for $iso — volume date chain broken?" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Volume UUID: $vol_uuid"
|
||||||
|
echo "Volume label: ${vol_label:-<none>}"
|
||||||
|
echo "SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:-<unset>}"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "❌ $1" >&2
|
||||||
|
echo " If you changed boot configs (efiboot/, syslinux/, grub/) on purpose," >&2
|
||||||
|
echo " update this 'Verify ISO search metadata' step to match." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1) /boot/<uuid>.uuid (the archisosearchfilename fallback key) must
|
||||||
|
# exist inside the ISO and its stem must equal the volume UUID.
|
||||||
|
uuid_refs=0
|
||||||
|
while IFS= read -r member; do
|
||||||
|
[ -z "$member" ] && continue
|
||||||
|
member=${member#/}
|
||||||
|
stem=$(basename "$member" .uuid)
|
||||||
|
if [ "$stem" != "$vol_uuid" ]; then
|
||||||
|
fail "$member: stem '$stem' != volume UUID '$vol_uuid'"
|
||||||
|
fi
|
||||||
|
echo " ✅ $member matches volume UUID"
|
||||||
|
uuid_refs=$((uuid_refs + 1))
|
||||||
|
done < <(bsdtar -tf "$iso" | grep -E '(^|/)boot/[0-9A-Za-z-]+\.uuid$' || true)
|
||||||
|
if (( uuid_refs == 0 )); then
|
||||||
|
fail "no /boot/<uuid>.uuid file found inside the ISO"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) Every archisosearchuuid= in shipped boot configs must equal the
|
||||||
|
# volume UUID; every %ARCHISO% placeholder must have been substituted.
|
||||||
|
search_refs=0
|
||||||
|
while IFS= read -r member; do
|
||||||
|
[ -z "$member" ] && continue
|
||||||
|
member=${member#/}
|
||||||
|
if ! content=$(bsdtar -xOf "$iso" "$member" 2>/dev/null); then
|
||||||
|
fail "could not extract $member from the ISO"
|
||||||
|
fi
|
||||||
|
if printf '%s\n' "$content" | grep -q '%ARCHISO'; then
|
||||||
|
fail "$member contains an unsubstituted %ARCHISO% placeholder"
|
||||||
|
fi
|
||||||
|
while IFS= read -r val; do
|
||||||
|
[ -z "$val" ] && continue
|
||||||
|
search_refs=$((search_refs + 1))
|
||||||
|
if [ "$val" != "$vol_uuid" ]; then
|
||||||
|
fail "$member: archisosearchuuid=$val != volume UUID '$vol_uuid'"
|
||||||
|
fi
|
||||||
|
echo " ✅ $member: archisosearchuuid=$val matches volume UUID"
|
||||||
|
done < <(printf '%s\n' "$content" | grep -o 'archisosearchuuid=[^[:space:]]*' | cut -d= -f2- || true)
|
||||||
|
done < <(bsdtar -tf "$iso" | grep -E '(^|/)(loader/entries/.*\.conf|boot/.*\.(cfg|conf))$' || true)
|
||||||
|
if (( search_refs == 0 )); then
|
||||||
|
fail "no archisosearchuuid= references found in shipped boot configs (params removed without updating this check?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ ISO search metadata consistent: $uuid_refs uuid file(s), $search_refs search reference(s)"
|
||||||
|
|
||||||
- name: Generate Unique Dynamic Tag
|
- name: Generate Unique Dynamic Tag
|
||||||
id: tag
|
id: tag
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
SERVER_URL: ${{ github.server_url }}
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
test -n "$GITEA_TOKEN"
|
||||||
|
|
||||||
|
# Pre-flight: confirm the internal Gitea API is reachable so failures are clear
|
||||||
|
if ! curl -sfS -o /dev/null "$GITEA_API/version"; then
|
||||||
|
echo "❌ Cannot reach Gitea API at $GITEA_API" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
BASE_DATE=$(date -u +'%Y.%m.%d')
|
BASE_DATE=$(date -u +'%Y.%m.%d')
|
||||||
REVISION=1
|
REVISION=1
|
||||||
TAG_NAME="iso-${BASE_DATE}-r${REVISION}"
|
TAG_NAME="iso-${BASE_DATE}-r${REVISION}"
|
||||||
|
|
||||||
# Check if the tag already exists via Gitea API, increment revision loop if it does
|
# Check if the tag already exists via Gitea API, increment revision loop if it does
|
||||||
while curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITEA_TOKEN" \
|
while curl -sf -o /dev/null -H "Authorization: token $GITEA_TOKEN" \
|
||||||
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases/tags/$TAG_NAME" | grep -q "200"; do
|
"$GITEA_API/repos/$REPOSITORY/releases/tags/$TAG_NAME"; do
|
||||||
REVISION=$((REVISION + 1))
|
REVISION=$((REVISION + 1))
|
||||||
TAG_NAME="iso-${BASE_DATE}-r${REVISION}"
|
TAG_NAME="iso-${BASE_DATE}-r${REVISION}"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
|
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
echo "release_name=Arch Linux ISO (${BASE_DATE} Rev ${REVISION})" >> $GITHUB_OUTPUT
|
echo "release_name=Arch Linux ISO (${BASE_DATE} Rev ${REVISION})" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Create Release and Upload ISO
|
- name: Create Release and Upload ISO
|
||||||
|
id: release
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
SERVER_URL: ${{ github.server_url }}
|
# Use internal Gitea URL to bypass traefik proxy timeout on large uploads
|
||||||
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
|
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
|
||||||
RELEASE_NAME: ${{ steps.tag.outputs.release_name }}
|
RELEASE_NAME: ${{ steps.tag.outputs.release_name }}
|
||||||
run: |
|
run: |
|
||||||
# Create the release via Gitea API
|
set -eu
|
||||||
RELEASE_ID=$(curl -s -X POST \
|
shopt -s nullglob
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
tmpdir=$(mktemp -d)
|
||||||
-H "Content-Type: application/json" \
|
trap 'rm -rf "$tmpdir"' EXIT
|
||||||
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases" \
|
if [ -z "$GITEA_TOKEN" ]; then
|
||||||
-d "{\"tag_name\": \"$TAG_NAME\", \"name\": \"$RELEASE_NAME\"}" \
|
echo "❌ GITEA_TOKEN is empty" >&2
|
||||||
| jq -r '.id')
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TAG_NAME" ]; then
|
||||||
|
echo "❌ TAG_NAME is empty" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$RELEASE_NAME" ]; then
|
||||||
|
echo "❌ RELEASE_NAME is empty" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Created release ID: $RELEASE_ID"
|
# Pre-flight: confirm the internal Gitea API is reachable so failures are clear
|
||||||
|
if ! curl -sfS -o /dev/null "$GITEA_API/version"; then
|
||||||
|
echo "❌ Cannot reach Gitea API at $GITEA_API" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Upload each ISO as a release asset
|
# Collect the ISOs produced by the build and record SHA-256
|
||||||
for iso in out/*.iso; do
|
isos=(out/*.iso)
|
||||||
echo "Uploading $iso..."
|
if (( ${#isos[@]} == 0 )); then
|
||||||
curl -s -X POST \
|
echo "❌ No ISO found in out/ — nothing to upload, aborting." >&2
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
exit 1
|
||||||
-F "attachment=@$iso" \
|
fi
|
||||||
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases/$RELEASE_ID/assets"
|
|
||||||
|
sha256sums=()
|
||||||
|
for iso in "${isos[@]}"; do
|
||||||
|
fname=$(basename "$iso")
|
||||||
|
size=$(stat -c %s "$iso")
|
||||||
|
# Sanity check: a real ISO is multi-GB; anything tiny is the wrong file
|
||||||
|
if (( size < 100000000 )); then
|
||||||
|
echo "❌ '$iso' is only $size bytes — refusing to upload (not an ISO)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sha=$(sha256sum "$iso" | awk '{print $1}')
|
||||||
|
if [ -z "$sha" ]; then
|
||||||
|
echo "❌ Failed to compute SHA-256 for '$iso'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " ✅ $fname: $(( size / 1024 / 1024 )) MiB, sha256=$sha"
|
||||||
|
sha256sums+=("$sha")
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Release $TAG_NAME created and ISOs uploaded."
|
# Build the release body with SHA-256 checksums
|
||||||
|
printf -v body 'Arch Linux live ISO %s\n\nChecksums (SHA-256):\n' "$RELEASE_NAME"
|
||||||
|
for i in "${!isos[@]}"; do
|
||||||
|
# Release body: markdown backticks are literal (printf format below)
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
printf -v line -- '- `%s`: sha256 `%s`\n' "$(basename "${isos[$i]}")" "${sha256sums[$i]}"
|
||||||
|
body+="$line"
|
||||||
|
done
|
||||||
|
|
||||||
- name: Keep only latest 3 releases
|
# Create the release (curl result written to a file, checked with if)
|
||||||
env:
|
payload=$(jq -nc --arg tag "$TAG_NAME" --arg name "$RELEASE_NAME" --arg body "$body" \
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
'{tag_name:$tag,name:$name,body:$body}')
|
||||||
SERVER_URL: ${{ github.server_url }}
|
if ! curl -sf -X POST \
|
||||||
REPOSITORY: ${{ github.repository }}
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
run: |
|
-H "Content-Type: application/json" \
|
||||||
# Fetch all releases
|
"$GITEA_API/repos/$REPOSITORY/releases" \
|
||||||
releases=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
|
-d "$payload" -o "$tmpdir/release.json"; then
|
||||||
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases")
|
echo "❌ Failed to create release $TAG_NAME" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! RELEASE_ID=$(jq -er '.id' "$tmpdir/release.json"); then
|
||||||
|
echo "❌ Release response contained no id" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo " ✅ Created release $TAG_NAME (ID: $RELEASE_ID)"
|
||||||
|
|
||||||
# Sort by creation date and delete old ones, keeping only the 3 newest releases
|
# Upload each ISO as a release asset, up to 3 attempts per file
|
||||||
echo "$releases" | jq -r 'sort_by(.created_at) | .[].id' | head -n -3 | while read -r id; do
|
MAX_ATTEMPTS=3
|
||||||
if [ -n "$id" ]; then
|
for i in "${!isos[@]}"; do
|
||||||
echo "Deleting old release ID: $id"
|
iso=${isos[$i]}
|
||||||
curl -s -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
fname=$(basename "$iso")
|
||||||
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases/$id"
|
size=$(stat -c %s "$iso")
|
||||||
|
echo "Uploading $fname ($(( size / 1024 / 1024 )) MiB) to release $TAG_NAME..."
|
||||||
|
uploaded=0
|
||||||
|
attempt=1
|
||||||
|
while [ "$attempt" -le "$MAX_ATTEMPTS" ]; do
|
||||||
|
# Fresh output file each attempt: curl does not truncate -o on
|
||||||
|
# transport failure, so a stale body must not be misreported.
|
||||||
|
rm -f "$tmpdir/upload.json"
|
||||||
|
# A previous attempt may have saved the asset but lost the
|
||||||
|
# response; Gitea rejects duplicate names, so only after the
|
||||||
|
# first attempt check for and remove same-name leftovers
|
||||||
|
if [ "$attempt" -gt 1 ]; then
|
||||||
|
if curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" \
|
||||||
|
-o "$tmpdir/assets.json"; then
|
||||||
|
asset_ids=$(jq -r --arg name "$fname" \
|
||||||
|
'.[] | select(.name == $name) | .id' "$tmpdir/assets.json")
|
||||||
|
while read -r asset_id; do
|
||||||
|
if [ -n "$asset_id" ]; then
|
||||||
|
echo " ↻ Removing leftover asset id=$asset_id from a previous attempt"
|
||||||
|
if ! curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets/$asset_id" \
|
||||||
|
-o /dev/null; then
|
||||||
|
echo " ⚠️ Could not remove leftover asset id=$asset_id (continuing)" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$asset_ids"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Capture HTTP status explicitly: `-f` would swallow the Gitea
|
||||||
|
# error body (e.g. attachment size-limit messages) and leave the
|
||||||
|
# failure reason unknown.
|
||||||
|
if http_code=$(curl -sS -X POST --max-time 600 \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-F "attachment=@$iso" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" \
|
||||||
|
-o "$tmpdir/upload.json" -w '%{http_code}'); then
|
||||||
|
if [ "${http_code:0:1}" = "2" ] \
|
||||||
|
&& download_url=$(jq -er '.browser_download_url' "$tmpdir/upload.json"); then
|
||||||
|
echo " ✅ Uploaded $fname (attempt $attempt/$MAX_ATTEMPTS): $download_url"
|
||||||
|
uploaded=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " ⚠️ Upload of $fname: HTTP $http_code (attempt $attempt/$MAX_ATTEMPTS)" >&2
|
||||||
|
echo " Response: $(head -c 2000 "$tmpdir/upload.json" 2>/dev/null)" >&2
|
||||||
|
else
|
||||||
|
rc=$?
|
||||||
|
echo " ⚠️ Upload of $fname failed (attempt $attempt/$MAX_ATTEMPTS): curl exit $rc, HTTP ${http_code:-000}" >&2
|
||||||
|
if [ -s "$tmpdir/upload.json" ]; then
|
||||||
|
echo " Response: $(head -c 2000 "$tmpdir/upload.json")" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$attempt" -lt "$MAX_ATTEMPTS" ]; then
|
||||||
|
sleep $(( attempt * 10 ))
|
||||||
|
fi
|
||||||
|
attempt=$(( attempt + 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$uploaded" -ne 1 ]; then
|
||||||
|
echo "❌ Failed to upload $fname after $MAX_ATTEMPTS attempts — aborting." >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "✅ All ISOs uploaded to release $TAG_NAME"
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
- name: Verify uploaded ISO checksums
|
||||||
|
if: success()
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
# Internal origin bypasses traefik (and its Anubis bot wall) — the
|
||||||
|
# same host the upload step already uses.
|
||||||
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
|
GITEA_ORIGIN: http://192.168.1.168:3000
|
||||||
|
REPOSITORY: ${{ github.repository }}
|
||||||
|
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
|
||||||
|
RELEASE_ID: ${{ steps.release.outputs.release_id }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
shopt -s nullglob
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmpdir"' EXIT
|
||||||
|
|
||||||
|
for var in GITEA_TOKEN TAG_NAME RELEASE_ID; do
|
||||||
|
if [ -z "${!var:-}" ]; then
|
||||||
|
echo "❌ $var is empty" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
case "$RELEASE_ID" in
|
||||||
|
''|*[!0-9]*) echo "❌ RELEASE_ID is not numeric: $RELEASE_ID" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# fail_verify <reason...>: job fails but the release is kept — used
|
||||||
|
# for transport/API errors where the upload itself may be fine.
|
||||||
|
fail_verify() {
|
||||||
|
echo "❌ $1" >&2
|
||||||
|
echo " Release $TAG_NAME (ID $RELEASE_ID) left in place (not proven corrupt)." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# abort_release <reason...>: the asset is provably wrong — delete the
|
||||||
|
# release so a corrupt asset can never be published, then fail.
|
||||||
|
abort_release() {
|
||||||
|
echo "❌ $1" >&2
|
||||||
|
echo "Deleting release $TAG_NAME (ID $RELEASE_ID) so the bad upload cannot be used..." >&2
|
||||||
|
if ! curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID" -o /dev/null; then
|
||||||
|
echo "⚠️ Could not delete release $RELEASE_ID — delete it manually!" >&2
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
isos=(out/*.iso)
|
||||||
|
if (( ${#isos[@]} == 0 )); then
|
||||||
|
echo "❌ No ISO in out/ to verify" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recompute local checksums
|
||||||
|
declare -A local_sha local_size
|
||||||
|
for iso in "${isos[@]}"; do
|
||||||
|
fname=$(basename "$iso")
|
||||||
|
local_sha["$fname"]=$(sha256sum "$iso" | awk '{print $1}')
|
||||||
|
local_size["$fname"]=$(stat -c %s "$iso")
|
||||||
|
if [ -z "${local_sha[$fname]}" ]; then
|
||||||
|
echo "❌ Failed to compute SHA-256 for '$iso'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# List the release's assets as uploaded (API error = transient, no delete)
|
||||||
|
if ! curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" \
|
||||||
|
-o "$tmpdir/assets.json"; then
|
||||||
|
fail_verify "Failed to list assets of release $RELEASE_ID (API/transport error)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for iso in "${isos[@]}"; do
|
||||||
|
fname=$(basename "$iso")
|
||||||
|
api_size=$(jq -er --arg name "$fname" \
|
||||||
|
'.[] | select(.name == $name) | .size' "$tmpdir/assets.json" 2>/dev/null) \
|
||||||
|
|| abort_release "Asset '$fname' missing from release $RELEASE_ID"
|
||||||
|
if [ "$api_size" != "${local_size[$fname]}" ]; then
|
||||||
|
abort_release "Asset '$fname' size mismatch: server=$api_size local=${local_size[$fname]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download from the internal origin (traefik/Anubis bypassed).
|
||||||
|
# iso_name contains a space ("Alvin archlinux"), so the filename
|
||||||
|
# must be percent-encoded or curl rejects the URL outright.
|
||||||
|
enc_fname=$(jq -rn --arg v "$fname" '$v|@uri')
|
||||||
|
url="$GITEA_ORIGIN/$REPOSITORY/releases/download/$TAG_NAME/$enc_fname"
|
||||||
|
downloaded=0
|
||||||
|
for attempt in 1 2 3; do
|
||||||
|
# Try header auth, then ?token=, then anonymous (public repo).
|
||||||
|
if curl -sfL --max-time 600 -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$url" -o "$tmpdir/$fname"; then
|
||||||
|
downloaded=1
|
||||||
|
elif curl -sfL --max-time 600 "$url?token=$GITEA_TOKEN" \
|
||||||
|
-o "$tmpdir/$fname"; then
|
||||||
|
downloaded=1
|
||||||
|
elif curl -sfL --max-time 600 "$url" -o "$tmpdir/$fname"; then
|
||||||
|
downloaded=1
|
||||||
|
fi
|
||||||
|
[ "$downloaded" -eq 1 ] && break
|
||||||
|
echo " ⚠️ Download of $fname failed (attempt $attempt/3)" >&2
|
||||||
|
[ "$attempt" -lt 3 ] && sleep $(( attempt * 10 ))
|
||||||
|
done
|
||||||
|
if [ "$downloaded" -ne 1 ]; then
|
||||||
|
fail_verify "Could not download asset '$fname' back from release $RELEASE_ID (auth/transport error, not proven corrupt)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
actual=$(sha256sum "$tmpdir/$fname" | awk '{print $1}')
|
||||||
|
expected=${local_sha[$fname]}
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
abort_release "SHA-256 mismatch for '$fname': server=$actual local=$expected"
|
||||||
|
fi
|
||||||
|
echo " ✅ $fname: size and SHA-256 match"
|
||||||
|
rm -f "$tmpdir/$fname"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ All uploaded assets verified against local ISO checksums"
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
- name: Keep only latest 2 releases
|
||||||
|
if: success()
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
|
REPOSITORY: ${{ github.repository }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
test -n "$GITEA_TOKEN"
|
||||||
|
|
||||||
|
echo "Pruning old releases in $REPOSITORY..."
|
||||||
|
readarray -t ids < <(curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases" \
|
||||||
|
| jq -er 'sort_by(.created_at) | .[].id')
|
||||||
|
|
||||||
|
to_delete=$(( ${#ids[@]} - 2 ))
|
||||||
|
if (( to_delete > 0 )); then
|
||||||
|
for ((i = 0; i < to_delete; i++)); do
|
||||||
|
id=${ids[$i]}
|
||||||
|
echo "Deleting old release ID: $id"
|
||||||
|
curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_API/repos/$REPOSITORY/releases/$id"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Cleanup mkarchiso mounts and workdirs
|
||||||
|
if: always() # Runs on success, failure, or cancellation
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
# Steps run as root (pacman is used directly); fall back to sudo if not
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
PRIV=""
|
||||||
|
else
|
||||||
|
PRIV="sudo"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unmount any leftover loop devices or bind mounts in the work directory
|
||||||
|
$PRIV umount -R "$PWD/work" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Clean up loop devices if any remain attached to the work dir
|
||||||
|
$PRIV losetup -D || true
|
||||||
|
|
||||||
|
# Remove working directories with proper permissions
|
||||||
|
$PRIV rm -rf "$PWD/work"
|
||||||
|
|
||||||
|
- name: Remove built ISO
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
rm -rf "$PWD/out"
|
||||||
|
|||||||
@@ -36,7 +36,23 @@ jobs:
|
|||||||
rm -f /var/lib/pacman/sync/cachyos* /var/lib/pacman/sync/chaotic*
|
rm -f /var/lib/pacman/sync/cachyos* /var/lib/pacman/sync/chaotic*
|
||||||
|
|
||||||
- name: Install prerequisites
|
- name: Install prerequisites
|
||||||
run: pacman -Syu --noconfirm --needed shellcheck yamllint
|
run: |
|
||||||
|
# The gateway intermittently drops UDP/53 (it failed build run 131
|
||||||
|
# at the equivalent step); retry with backoff instead of dying on
|
||||||
|
# the first bad DNS burst.
|
||||||
|
synced=0
|
||||||
|
for try in 1 2 3 4 5; do
|
||||||
|
if pacman -Syu --noconfirm --needed shellcheck yamllint; then
|
||||||
|
synced=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "⚠️ pacman -Syu failed (attempt $try/5), retrying in $(( try * 15 ))s..." >&2
|
||||||
|
sleep $(( try * 15 ))
|
||||||
|
done
|
||||||
|
if [ "$synced" -ne 1 ]; then
|
||||||
|
echo "❌ pacman -Syu failed after 5 attempts — giving up" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Set up CachyOS repo
|
- name: Set up CachyOS repo
|
||||||
run: |
|
run: |
|
||||||
@@ -54,7 +70,20 @@ jobs:
|
|||||||
printf '\n[cachyos]\nInclude = /etc/pacman.d/cachyos-mirrorlist\n' \
|
printf '\n[cachyos]\nInclude = /etc/pacman.d/cachyos-mirrorlist\n' \
|
||||||
>> /etc/pacman.conf
|
>> /etc/pacman.conf
|
||||||
|
|
||||||
pacman -Syu --noconfirm
|
# Retry: gateway drops UDP/53 in bursts (see run 131)
|
||||||
|
synced=0
|
||||||
|
for try in 1 2 3 4 5; do
|
||||||
|
if pacman -Syu --noconfirm --needed; then
|
||||||
|
synced=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "⚠️ pacman -Syu failed (attempt $try/5), retrying in $(( try * 15 ))s..." >&2
|
||||||
|
sleep $(( try * 15 ))
|
||||||
|
done
|
||||||
|
if [ "$synced" -ne 1 ]; then
|
||||||
|
echo "❌ pacman -Syu failed after 5 attempts — giving up" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Set up chaotic-aur repo
|
- name: Set up chaotic-aur repo
|
||||||
run: |
|
run: |
|
||||||
@@ -65,7 +94,20 @@ jobs:
|
|||||||
printf '\n[chaotic-aur]\nInclude = /etc/pacman.d/chaotic-mirrorlist\n' \
|
printf '\n[chaotic-aur]\nInclude = /etc/pacman.d/chaotic-mirrorlist\n' \
|
||||||
>> /etc/pacman.conf
|
>> /etc/pacman.conf
|
||||||
|
|
||||||
pacman -Syu --noconfirm
|
# Retry: gateway drops UDP/53 in bursts (see run 131)
|
||||||
|
synced=0
|
||||||
|
for try in 1 2 3 4 5; do
|
||||||
|
if pacman -Syu --noconfirm --needed; then
|
||||||
|
synced=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "⚠️ pacman -Syu failed (attempt $try/5), retrying in $(( try * 15 ))s..." >&2
|
||||||
|
sleep $(( try * 15 ))
|
||||||
|
done
|
||||||
|
if [ "$synced" -ne 1 ]; then
|
||||||
|
echo "❌ pacman -Syu failed after 5 attempts — giving up" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Lint shell scripts with ShellCheck
|
- name: Lint shell scripts with ShellCheck
|
||||||
run: |
|
run: |
|
||||||
@@ -80,7 +122,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
FAILED=0
|
FAILED=0
|
||||||
for f in $SH_FILES; do
|
while IFS= read -r f; do
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Checking: $f"
|
echo "── Checking: $f"
|
||||||
if shellcheck -x -s bash "$f"; then
|
if shellcheck -x -s bash "$f"; then
|
||||||
@@ -89,7 +131,7 @@ jobs:
|
|||||||
echo " ❌ $f failed"
|
echo " ❌ $f failed"
|
||||||
FAILED=1
|
FAILED=1
|
||||||
fi
|
fi
|
||||||
done
|
done <<< "$SH_FILES"
|
||||||
|
|
||||||
if [ "$FAILED" -ne 0 ]; then
|
if [ "$FAILED" -ne 0 ]; then
|
||||||
echo ""
|
echo ""
|
||||||
@@ -110,14 +152,14 @@ jobs:
|
|||||||
echo " Running yamllint on all YAML files"
|
echo " Running yamllint on all YAML files"
|
||||||
echo "═══════════════════════════════════════════════════════════════"
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
|
||||||
YAML_FILES=$(find . -name '*.yml' -o -name '*.yaml' | grep -v '.git/')
|
YAML_FILES=$(find . -not -path './.git/*' \( -name '*.yml' -o -name '*.yaml' \))
|
||||||
if [ -z "$YAML_FILES" ]; then
|
if [ -z "$YAML_FILES" ]; then
|
||||||
echo "No YAML files found."
|
echo "No YAML files found."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FAILED=0
|
FAILED=0
|
||||||
for f in $YAML_FILES; do
|
while IFS= read -r f; do
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Checking: $f"
|
echo "── Checking: $f"
|
||||||
if yamllint -d "{extends: relaxed, rules: {document-start: disable, line-length: disable, new-line-at-end-of-file: disable}}" "$f"; then
|
if yamllint -d "{extends: relaxed, rules: {document-start: disable, line-length: disable, new-line-at-end-of-file: disable}}" "$f"; then
|
||||||
@@ -126,7 +168,7 @@ jobs:
|
|||||||
echo " ❌ $f failed"
|
echo " ❌ $f failed"
|
||||||
FAILED=1
|
FAILED=1
|
||||||
fi
|
fi
|
||||||
done
|
done <<< "$YAML_FILES"
|
||||||
|
|
||||||
if [ "$FAILED" -ne 0 ]; then
|
if [ "$FAILED" -ne 0 ]; then
|
||||||
echo ""
|
echo ""
|
||||||
@@ -260,3 +302,30 @@ jobs:
|
|||||||
echo ""
|
echo ""
|
||||||
echo "✅ All packages verified successfully!"
|
echo "✅ All packages verified successfully!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Check for conflicting packages
|
||||||
|
run: |
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo " Checking for conflicting packages in packages.x86_64"
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
|
||||||
|
# Collect all package names from the list
|
||||||
|
PKGS=()
|
||||||
|
while IFS= read -r pkg; do
|
||||||
|
[[ -z "$pkg" || "$pkg" =~ ^# ]] && continue
|
||||||
|
PKGS+=("$pkg")
|
||||||
|
done < packages.x86_64
|
||||||
|
|
||||||
|
# Use pacman -Sp --print to resolve the full install set and check for conflicts
|
||||||
|
# This catches "X and Y are in conflict" errors before the ISO build
|
||||||
|
PKG_LIST=$(printf '%s\n' "${PKGS[@]}")
|
||||||
|
if CONFLICTS=$(echo "$PKG_LIST" | pacman -Sp --needed - 2>&1); then
|
||||||
|
echo "✅ No package conflicts detected"
|
||||||
|
else
|
||||||
|
echo "$CONFLICTS" | grep -i "conflict" || true
|
||||||
|
echo ""
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo " ❌ Conflicting packages found — fix packages.x86_64"
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# Multi-GB mkarchiso output (see AGENTS.md build command)
|
||||||
|
work/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# In-image copy of localrepo/ — populated by localrepo/update.sh and
|
||||||
|
# .gitea/workflows/build-iso.yaml, shipped as /opt/localrepo on the ISO
|
||||||
|
airootfs/opt/localrepo/
|
||||||
|
|
||||||
|
# Build stamp staged by profiledef.sh at ISO build time (see AGENTS.md);
|
||||||
|
# consumed by customize_airootfs.sh, never committed
|
||||||
|
airootfs/root/.iso-build-stamp
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
Arch Linux ISO profile (archiso). Builds a live ISO with Hyprland desktop, end-4 dots-hyprland, and curated packages. Hosted on Gitea.
|
||||||
|
|
||||||
|
## Build & Test Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the ISO (repo root IS the profile directory)
|
||||||
|
sudo mkarchiso -v -w work -o out/ .
|
||||||
|
|
||||||
|
# Build AUR deps for end-4 (run locally before ISO build if localrepo/ is stale)
|
||||||
|
./localrepo/build-end4-deps.sh # build all
|
||||||
|
./localrepo/build-end4-deps.sh --quick # skip large AUR pkgs
|
||||||
|
|
||||||
|
# Refresh localrepo DB after adding/moving .pkg.tar.zst files
|
||||||
|
./localrepo/update.sh # re-indexes existing packages
|
||||||
|
./localrepo/update.sh pkg1.pkg.tar.zst # add files, then re-index
|
||||||
|
```
|
||||||
|
|
||||||
|
`update.sh` also refreshes `airootfs/opt/localrepo/` (the copy that ships on the
|
||||||
|
ISO), so run it after touching `localrepo/` before building.
|
||||||
|
|
||||||
|
## CI Checks (must pass before merge)
|
||||||
|
|
||||||
|
- **ShellCheck**: all `.sh` files checked with `shellcheck -x -s bash`
|
||||||
|
- **yamllint**: all `.yml`/`.yaml` files (relaxed config)
|
||||||
|
- **packages.x86_64 syntax**: one package per line, no trailing whitespace, `[a-zA-Z0-9._@+\-]+` only
|
||||||
|
- **Package repo check**: every package in `packages.x86_64` must be resolvable via `pacman -Si` in allowed repos (`cachyos`, `extra`, `multilib`, `chaotic-aur`), OR have a pre-built `.pkg.tar.zst` in `localrepo/`, OR appear in `localrepo/build-end4-deps.sh`
|
||||||
|
|
||||||
|
## Package Management
|
||||||
|
|
||||||
|
**Three sources** contribute packages to the ISO:
|
||||||
|
|
||||||
|
1. **`packages.x86_64`** — main list, installed by mkarchiso. Must be in an allowed repo.
|
||||||
|
2. **`localrepo/*.pkg.tar.zst`** — pre-built AUR packages. The `local-aur` repo is configured in `pacman.conf` and picked up by mkarchiso automatically.
|
||||||
|
3. **`build-end4-deps.sh`** — builds end-4 AUR deps at build time.
|
||||||
|
|
||||||
|
There is a **fourth source**: `customize_airootfs.sh` runs end-4's own
|
||||||
|
`./setup install-deps` inside the image (as a throwaway `ii-builder` account),
|
||||||
|
which resolves and compiles everything the dotfiles need (quickshell, MicroTeX,
|
||||||
|
theming, fonts, ...). Those packages are installed in the live system, land in
|
||||||
|
`pkglist.x86_64.txt`, and are harvested into `/opt/localrepo` so pacstrap can
|
||||||
|
install them into the target without the network.
|
||||||
|
|
||||||
|
**Important**: `localrepo/update.sh` auto-appends new package names to `packages.x86_64`. If you remove a package from `packages.x86_64` that exists in `localrepo/`, it will be re-added on the next `update.sh` run.
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `packages.x86_64` | Live ISO package list (~402 packages) |
|
||||||
|
| `profiledef.sh` | ISO metadata, compression, boot modes, build-stamp staging |
|
||||||
|
| `pacman.conf` | Repos: cachyos → core → extra → multilib → chaotic-aur → local-aur |
|
||||||
|
| `bootstrap_packages` | Minimal build-time packages (`base`, `arch-install-scripts`) |
|
||||||
|
| `airootfs/root/customize_airootfs.sh` | Runs inside chroot during build: keyrings, skel dotfiles (incl. end4-pC), qsConfig patch, end-4 `install-deps`, package harvest, uv/font pre-warm |
|
||||||
|
| `airootfs/root/.live-pacman.conf` | `/etc/pacman.conf` of the built image (adds `[local-aur]` = `file:///opt/localrepo`) |
|
||||||
|
| `airootfs/usr/local/bin/alvin-install` | Installer: partitions, pacstrap, LUKS (systemd initramfs **or** experimental unl0kr + optional TPM2 unlock), user, git identity + GitHub SSH keys, login manager (none/greetd/sddm/gdm) + autologin, end-4 dotfiles (`--skip-alldeps`), build-stamp motd, boot |
|
||||||
|
| `localrepo/build-end4-deps.sh` | Non-interactive AUR builds for end-4 dependencies |
|
||||||
|
| `localrepo/update.sh` | Regenerates localrepo DB, syncs names to packages.x86_64, syncs `airootfs/opt/localrepo/` |
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- The profile root is the **repo root** (not a `releng/` subdirectory). The CI build-iso workflow uses `mkarchiso -v -w work -o out/ releng` but this is a naming convention — the actual profile files live at the repo root.
|
||||||
|
- `customize_airootfs.sh` clones git repos (oh-my-zsh, lazy.nvim, plugins, end-4 dots) into `/etc/skel` and `/opt` during the ISO build. These require network access at build time but make the live ISO work offline.
|
||||||
|
- `customize_airootfs.sh` runs `./setup install-deps -f -s --skip-plasmaintg` as the throwaway user `ii-builder` (end-4's scripts refuse to run as root) and aborts the build if it fails. `--skip-plasmaintg` is deliberate: that optional Firefox widget pulls 410 packages / 526 MiB of KDE.
|
||||||
|
- The `[local-aur]` repo path in `pacman.conf` (`file:///home/alvin/alvinarch/localrepo`) is for local builds only. The CI does not use this path.
|
||||||
|
- The **image** ships its own `[local-aur]` at `file:///opt/localrepo` (see `.live-pacman.conf`). It holds `localrepo/` (copied by CI/`update.sh`) plus everything `install-deps` built. pacstrap runs without `-P`, so the target keeps the stock `/etc/pacman.conf`; `alvin-install` strips `[local-aur]` from it anyway as a safety net, because `/opt/localrepo` exists only on the medium.
|
||||||
|
- `alvin-install` runs end-4 with `--skip-alldeps` — dependencies must come from the ISO. It feeds `yes i` to end-4's failure prompt: inside the installer chroot the medium's `/run` is bind-mounted in, so end-4's `systemctl --machine=…@.host --user enable … --now` lines can never work (and `--now` would start services on the live medium). `install_end4_dots` re-applies the enable-only part (bluetooth, ydotool, i2c module) outside the chroot and reports every step end-4 had to skip. If the end-4 step reports "incomplete", check that `hyprctl`/`quickshell`/the venv were resolvable (harvest) before re-running anything.
|
||||||
|
- `/etc/skel/.cache/uv` + `/etc/skel/.local/share/uv/python` are pre-warmed by the build (~460 MB: CPython 3.12 and the pinned wheel cache) so end-4's `uv venv`/`uv pip install` at install time needs no network.
|
||||||
|
- **end4-pC** (`pctrade/end4-pC`) is the default quickshell config: cloned into `/etc/skel/.config/quickshell/end4-pC` at build time, selected by patching `hl.env("qsConfig", "ii")` → `"end4-pC"` in the **staged** `/opt/dots-hyprland/dots/.config/hypr/hyprland/variables.lua` (there is no `hypr/hyprland/` in this repo — `./setup install` copies it to the installed system). `alvin-install` re-copies end4-pC into the user's home *after* `./setup install`, because end-4's installer `rsync --delete`s all of `~/.config/quickshell`.
|
||||||
|
- `airootfs/etc/skel/.config/illogical-impulse/presets/` carries the user's presets (`Laptop.json`, `Personal-Performance.json`, `Personal-Performance.zip`). They embed `/home/alvin/...` paths, so wallpapers/screenshots need fixing up after install.
|
||||||
|
- End-4 metapackages are built from `localrepo/end4-pkgbuilds/` (quickshell-git, bibata-modern-classic-bin, microtex-git).
|
||||||
|
- `packages.x86_64` is sorted alphabetically. Keep it sorted when adding/removing entries.
|
||||||
|
- `airootfs/opt/localrepo/` is a build artifact (gitignored) — never commit it.
|
||||||
|
- **Build stamp flow**: `profiledef.sh` (sourced by mkarchiso) stages the gitignored `airootfs/root/.iso-build-stamp` when a `.git` dir exists **or** `CI`/`GITEA_ACTIONS` is set — line reads `AlvinArch build <date> | commit <date> | <4-char hash>` (falls back to `commit unknown` if `git -c safe.directory` can't read the repo; without `.git`/CI no file is staged). `customize_airootfs.sh` installs it as `/etc/alvin-build-stamp` on the live medium, and `alvin-install`'s `install_motd` copies the live `/etc/motd` banner to the target and appends the stamp. If the medium has no stamp, the installed system gets no motd from us.
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFhTCCA22gAwIBAgIJBJPyuFHF1b7RMA0GCSqGSIb3DQEBDQUAMF8xDjAMBgNV
|
|
||||||
BAsTBUFyYm9yMQ4wDAYDVQQKEwVDaXNjbzE9MDsGA1UEAxM0Q2lzY28gU29mdHdh
|
|
||||||
cmUgSWRlbnRpdHkgUm9vdCBDQSBSU0EgNDA5NiBTSEE1MTIgMjA5OTAgFw0yNDAx
|
|
||||||
MjQxODQ1MjVaGA8yMDk5MDEyNDE4NDUyNVowXzEOMAwGA1UECxMFQXJib3IxDjAM
|
|
||||||
BgNVBAoTBUNpc2NvMT0wOwYDVQQDEzRDaXNjbyBTb2Z0d2FyZSBJZGVudGl0eSBS
|
|
||||||
b290IENBIFJTQSA0MDk2IFNIQTUxMiAyMDk5MIICIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
Ag8AMIICCgKCAgEA14hoPbzqZxPr8Wqpq2H+tOib+DkQP80mUP6zAw3uu+eNygd+
|
|
||||||
jOBCenO6B7sp1sqCRT8QBQWQxNHVeVfMQN1vjMrqEMNh/eflVtOGy32UbkuQrVzj
|
|
||||||
2H+G1PtjeMQKa26LD8XPDUIOpj9rzPdjKFFfz13tm21gNIiVSTI34T5BS5BNEQj1
|
|
||||||
b+VQg+0kbANCOOTiTh+H/gxhpXRv8F3VNUrrPxA7a3WF5jhZZoPBns1LuBDW0fQ0
|
|
||||||
av6q/uEWtfxMdSNsAxYWVhO90Nx4khOISA1Fs1h1klGsee5XZkLKdUWedZQzbUz1
|
|
||||||
f7VPRxX+ddcK0Js2VPvxemMf2WaTbkrEi62y/cOaxqDs2xDTWEXrgOYYEfQ+RoeY
|
|
||||||
pbzBCaErqZvCeOgrnXFSHSyyd9+dTOxJuypBH+AWKtmkQMQQ7RQJSkGvrP9NgRxD
|
|
||||||
MXb1U4kpVn7kEEhv6telV9E8R635Zm4h/H9FQyc2LrLOuL5UPewMMWt8HqPbs2Xc
|
|
||||||
n1kTLvpEDciDJDRvu4XuBsjgQMA0rlt5BHAmZdGO5Dq4+ARWAYrzN9+M0dK+0phT
|
|
||||||
T9OOHItIL6wXcIiYLZBJlHfiemCByIcBBEYaRwdt3VP9tTl0F370StI2t1RMDPgt
|
|
||||||
xHcsYqN09QG/tWzwr/yNckFhVs/+UGQWslv2/W6eiKge5REUFuxT6i7V6oUCAwEA
|
|
||||||
AaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
|
|
||||||
FLd8Wz4X/JJ6Oi/+znsT0DTPuju8MA0GCSqGSIb3DQEBDQUAA4ICAQCZEut7iqp8
|
|
||||||
39u7CHD8zMrvOMmUKtJ7G1MrhkJfdyek8g7ArG74bgcxM3ptwDusdFgKh/mmCj/m
|
|
||||||
FU6TNjsufZ9hAyOE16ZtGflkOrRlihPQThDdGCxQjRsLVQa9S0IDkM1v1ZqvIMEc
|
|
||||||
PJOj3rhvkIJVjpHc0AZQP/TnaT/7dKD1wFOSNYwzdvE2HKVNA8XbeS9TNpHqYPvE
|
|
||||||
2gX6vQ7Pdn9DIF6YOmOuBobmaD1G7WbDz5Kvz5e3FdkzR+K3sGW4Qsr3OLt25dQS
|
|
||||||
H+x7X06fihUxhEgRJJp2cPKABSKVR2hoyzKNEbzgtV25gH7lr+EHA6CQYltkVpyM
|
|
||||||
4v1+PdX1EGY0+rAO+NsRwa6ndFteofJLh9PbvxHp0jGWnT1KF4lhmEyyka9JKbqT
|
|
||||||
yiyGzDsw/YA9NxiAsp/Ex8aYXX1/SeM/kb6dp7tytsHewwflns1jfGqRVyrXQ41x
|
|
||||||
CmmSioBvtZiry8BJTa8xIUWEsBL1pTl2RZrPDAw/qD10K2XJfh5HYFSkIppoIO+9
|
|
||||||
0wN8TYcXbyY+JnU/g32AvkmA3o8lotK6nbwuf7MAFdtPHMA4F8mPM3jADc1uGu9O
|
|
||||||
YweaA1c+P5KEOyr325cgsT04x4oeyvP3c3XMLpDpSgbzhfc9WyLYCf3R3jHlst1A
|
|
||||||
KaDwBk2xoE3knxihYjbcRfjaaYdUkWY4mg==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
To install [38;2;23;147;209mArch Linux[0m follow the installation guide:
|
To install [38;2;23;147;209mArch Linux[0m, follow the installation guide,
|
||||||
|
or run [35malvin-install[0m for an automated setup.
|
||||||
https://wiki.archlinux.org/title/Installation_guide
|
https://wiki.archlinux.org/title/Installation_guide
|
||||||
|
|
||||||
For Wi-Fi, authenticate to the wireless network using the [35miwctl[0m utility.
|
For Wi-Fi, run [35mnmtui[0m to configure a wireless network.
|
||||||
For mobile broadband (WWAN) modems, connect with the [35mmmcli[0m utility.
|
For mobile broadband (WWAN) modems, connect with the [35mmmcli[0m utility.
|
||||||
Ethernet, WLAN and WWAN interfaces using DHCP should work automatically.
|
Ethernet, WLAN and WWAN interfaces using DHCP should work automatically.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Trigger]
|
||||||
|
Type = Package
|
||||||
|
Operation = Install
|
||||||
|
Operation = Upgrade
|
||||||
|
Target = *
|
||||||
|
|
||||||
|
[Action]
|
||||||
|
Description = Ensuring /dev/stdin exists...
|
||||||
|
When = PreTransaction
|
||||||
|
Exec = /usr/bin/sh -c "[ -e /dev/stdin ] || ln -sf /proc/self/fd/0 /dev/stdin; [ -e /dev/stdout ] || ln -sf /proc/self/fd/1 /dev/stdout; [ -e /dev/stderr ] || ln -sf /proc/self/fd/2 /dev/stderr"
|
||||||
@@ -23,7 +23,7 @@ if status is-interactive
|
|||||||
alias celar "printf '\033[2J\033[3J\033[1;1H'"
|
alias celar "printf '\033[2J\033[3J\033[1;1H'"
|
||||||
alias claer "printf '\033[2J\033[3J\033[1;1H'"
|
alias claer "printf '\033[2J\033[3J\033[1;1H'"
|
||||||
alias pamcan pacman
|
alias pamcan pacman
|
||||||
alias q 'qs -c ii'
|
alias q 'qs -c end4-pC'
|
||||||
if test "$TERM" != "linux"
|
if test "$TERM" != "linux"
|
||||||
alias ls 'eza --icons'
|
alias ls 'eza --icons'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,677 @@
|
|||||||
|
{
|
||||||
|
"appearance": {
|
||||||
|
"extraBackgroundTint": true,
|
||||||
|
"fakeScreenRounding": 0,
|
||||||
|
"fonts": {
|
||||||
|
"expressive": "Space Grotesk",
|
||||||
|
"iconNerd": "JetBrains Mono NF",
|
||||||
|
"main": "Google Sans Flex",
|
||||||
|
"monospace": "JetBrains Mono NF",
|
||||||
|
"numbers": "Google Sans Flex",
|
||||||
|
"reading": "Readex Pro",
|
||||||
|
"title": "Google Sans Flex"
|
||||||
|
},
|
||||||
|
"palette": {
|
||||||
|
"accentColor": "",
|
||||||
|
"type": "scheme-tonal-spot"
|
||||||
|
},
|
||||||
|
"transparency": {
|
||||||
|
"automatic": true,
|
||||||
|
"backgroundTransparency": 0.11,
|
||||||
|
"contentTransparency": 0.57,
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"wallpaperTheming": {
|
||||||
|
"enableAppsAndShell": true,
|
||||||
|
"enableQtApps": true,
|
||||||
|
"enableTerminal": true,
|
||||||
|
"terminalGenerationProps": {
|
||||||
|
"forceDarkMode": false,
|
||||||
|
"harmonizeThreshold": 100,
|
||||||
|
"harmony": 0.5,
|
||||||
|
"termFgBoost": 0.35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"bluetooth": "kcmshell6 kcm_bluetooth",
|
||||||
|
"changePassword": "kitty -1 --hold=yes fish -i -c 'passwd'",
|
||||||
|
"manageUser": "kcmshell6 kcm_users",
|
||||||
|
"network": "kcmshell6 kcm_networkmanagement",
|
||||||
|
"networkEthernet": "kcmshell6 kcm_networkmanagement",
|
||||||
|
"taskManager": "plasma-systemmonitor --page-name Processes",
|
||||||
|
"terminal": "kitty -1",
|
||||||
|
"update": "kitty -1 --hold=yes fish -i -c 'pkexec pacman -Syu'",
|
||||||
|
"volumeMixer": "~/.config/hypr/hyprland/scripts/launch_first_available.sh \"pavucontrol-qt\" \"pavucontrol\""
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"blurRadius": 32,
|
||||||
|
"centeredWallpaper": false,
|
||||||
|
"centeredWallpaperColor": "primaryContainer",
|
||||||
|
"centeredWallpaperOnlyWhenLocked": false,
|
||||||
|
"centeredWallpaperShape": "Cookie7Sided",
|
||||||
|
"centeredWallpaperSize": 400,
|
||||||
|
"enableWallpaperPreview": false,
|
||||||
|
"hideWhenFullscreen": true,
|
||||||
|
"lockWall": "",
|
||||||
|
"parallax": {
|
||||||
|
"autoVertical": false,
|
||||||
|
"enableSidebar": true,
|
||||||
|
"enableWorkspace": true,
|
||||||
|
"vertical": false,
|
||||||
|
"widgetsFactor": 1.2,
|
||||||
|
"workspaceZoom": 1.07
|
||||||
|
},
|
||||||
|
"screenList": [],
|
||||||
|
"showBlur": true,
|
||||||
|
"showGrid": true,
|
||||||
|
"showSnapLines": true,
|
||||||
|
"splitRatio": "25",
|
||||||
|
"splitSide": "right",
|
||||||
|
"thumbnailPath": "",
|
||||||
|
"wallpaperAnimation": "random",
|
||||||
|
"wallpaperPath": "/home/alvin/Pictures/Wallpapers/Dynamic-Wallpapers/Dark/japan-street-Dark.png",
|
||||||
|
"widgets": {
|
||||||
|
"blurRadius": 32,
|
||||||
|
"blurWidgets": false,
|
||||||
|
"calendar": {
|
||||||
|
"enable": true,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "2x2",
|
||||||
|
"x": 1596,
|
||||||
|
"y": 744,
|
||||||
|
"z": 4
|
||||||
|
},
|
||||||
|
"clock": {
|
||||||
|
"color": "",
|
||||||
|
"cookie": {
|
||||||
|
"aiStyling": false,
|
||||||
|
"constantlyRotate": false,
|
||||||
|
"dateInClock": true,
|
||||||
|
"dateStyle": "bubble",
|
||||||
|
"dialNumberStyle": "full",
|
||||||
|
"hourHandStyle": "hollow",
|
||||||
|
"hourMarks": false,
|
||||||
|
"minuteHandStyle": "medium",
|
||||||
|
"secondHandStyle": "line",
|
||||||
|
"sides": 12,
|
||||||
|
"timeIndicators": true,
|
||||||
|
"useSineCookie": false
|
||||||
|
},
|
||||||
|
"digital": {
|
||||||
|
"adaptiveAlignment": true,
|
||||||
|
"animateChange": true,
|
||||||
|
"font": {
|
||||||
|
"family": "Google Sans Flex",
|
||||||
|
"roundness": 1.1290989771359807,
|
||||||
|
"size": 129.49608904933814,
|
||||||
|
"weight": 595.725165314564,
|
||||||
|
"width": 99.44532190132371
|
||||||
|
},
|
||||||
|
"showDate": true,
|
||||||
|
"vertical": false
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"pixel": {
|
||||||
|
"orientation": "vertical"
|
||||||
|
},
|
||||||
|
"placementStrategy": "leastBusy",
|
||||||
|
"quote": {
|
||||||
|
"enable": true,
|
||||||
|
"followClock": false,
|
||||||
|
"text": "Kawaī neko o zenbu tabe chaimasu."
|
||||||
|
},
|
||||||
|
"showOnlyWhenLocked": false,
|
||||||
|
"style": "digital",
|
||||||
|
"styleLocked": "cookie",
|
||||||
|
"x": 1423,
|
||||||
|
"y": 383,
|
||||||
|
"z": 3
|
||||||
|
},
|
||||||
|
"customImage": {
|
||||||
|
"enable": true,
|
||||||
|
"path": "",
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"shape": "Cookie4Sided",
|
||||||
|
"size": 200,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"customText": {
|
||||||
|
"alignment": "center",
|
||||||
|
"color": "",
|
||||||
|
"content": "Hello world",
|
||||||
|
"enable": true,
|
||||||
|
"fontFamily": "Caveat",
|
||||||
|
"fontSize": 72,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"shadow": true,
|
||||||
|
"x": 400,
|
||||||
|
"y": 300,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"backgroundShape": "Cookie4Sided",
|
||||||
|
"enable": true,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"showControls": true,
|
||||||
|
"showLyrics": false,
|
||||||
|
"showTitles": true,
|
||||||
|
"sizeMode": "1x3",
|
||||||
|
"x": 744,
|
||||||
|
"y": 876,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"notes": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"vertical": false,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"shadow": true,
|
||||||
|
"sticker": {
|
||||||
|
"enable": false,
|
||||||
|
"items": [],
|
||||||
|
"outlineColor": "#ffffff",
|
||||||
|
"outlineWidth": 8,
|
||||||
|
"path": "",
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"rotation": 0,
|
||||||
|
"size": 200,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"timers": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"vertical": false,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"todo": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"userCard": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "1x2",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"visualizer": {
|
||||||
|
"colorSource": "theme",
|
||||||
|
"enable": true,
|
||||||
|
"height": 343,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"ringSize": 380,
|
||||||
|
"sensitivity": 1.65,
|
||||||
|
"style": "mirror",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": -1000
|
||||||
|
},
|
||||||
|
"weather": {
|
||||||
|
"enable": false,
|
||||||
|
"expanded": false,
|
||||||
|
"placementStrategy": "mostBusy",
|
||||||
|
"sizeMode": "1x3",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"worldClock": {
|
||||||
|
"clockCount": 4,
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "2x2",
|
||||||
|
"timezones": [
|
||||||
|
"Australia/Sydney",
|
||||||
|
"Asia/Tokyo",
|
||||||
|
"Europe/London",
|
||||||
|
"America/New_York"
|
||||||
|
],
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgetsLocked": false
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
"autoHide": {
|
||||||
|
"enable": false,
|
||||||
|
"hoverRegionWidth": 2,
|
||||||
|
"pushWindows": false,
|
||||||
|
"showWhenPressingSuper": {
|
||||||
|
"delay": 140,
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"borderless": "transparent",
|
||||||
|
"bottom": false,
|
||||||
|
"centerOnlyReserveFrame": false,
|
||||||
|
"cornerStyle": 3,
|
||||||
|
"divider": {
|
||||||
|
"spacing": 20,
|
||||||
|
"style": "rect"
|
||||||
|
},
|
||||||
|
"dynamicIsland": {
|
||||||
|
"leftWidget": "clockWidget",
|
||||||
|
"rightWidget": "systemIcons",
|
||||||
|
"showMediaControls": false,
|
||||||
|
"visualizerStyle": "wave"
|
||||||
|
},
|
||||||
|
"floatStyleShadow": true,
|
||||||
|
"followFrameColor": false,
|
||||||
|
"frameColor": "secondaryContainer",
|
||||||
|
"frameThickness": 4,
|
||||||
|
"groupColor": "layer1",
|
||||||
|
"indicators": {
|
||||||
|
"notifications": {
|
||||||
|
"showUnreadCount": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"leftLayout": [
|
||||||
|
"leftSidebarButton",
|
||||||
|
"activeWindow",
|
||||||
|
"resources"
|
||||||
|
],
|
||||||
|
"middleLayout": [
|
||||||
|
"media",
|
||||||
|
"clockWidget",
|
||||||
|
"workspaces",
|
||||||
|
"utilButtons",
|
||||||
|
"weatherBar",
|
||||||
|
"batteryIndicator"
|
||||||
|
],
|
||||||
|
"rightLayout": [
|
||||||
|
"sysTray",
|
||||||
|
"updatesCount",
|
||||||
|
"bluetooth",
|
||||||
|
"systemIcons"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"alwaysVisible": false,
|
||||||
|
"maxWidth": 280,
|
||||||
|
"minWidth": 100,
|
||||||
|
"onlyTitle": false,
|
||||||
|
"preferredPlayer": "",
|
||||||
|
"showLyrics": false
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"alwaysShowCpu": true,
|
||||||
|
"alwaysShowCpuTemp": true,
|
||||||
|
"alwaysShowDisk": false,
|
||||||
|
"alwaysShowRam": true,
|
||||||
|
"alwaysShowSwap": false,
|
||||||
|
"cpuWarningThreshold": 90,
|
||||||
|
"memoryWarningThreshold": 95,
|
||||||
|
"showValue": true,
|
||||||
|
"style": "outline",
|
||||||
|
"swapWarningThreshold": 85
|
||||||
|
},
|
||||||
|
"screenList": [],
|
||||||
|
"showBackground": true,
|
||||||
|
"showFrame": false,
|
||||||
|
"tooltips": {
|
||||||
|
"clickToShow": false,
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"topLeftIcon": "spark",
|
||||||
|
"utilButtons": {
|
||||||
|
"isRecording": false,
|
||||||
|
"showColorPicker": false,
|
||||||
|
"showDarkModeToggle": false,
|
||||||
|
"showKeyboardToggle": true,
|
||||||
|
"showMicToggle": true,
|
||||||
|
"showPerformanceProfileToggle": true,
|
||||||
|
"showScreenRecord": false,
|
||||||
|
"showScreenSnip": false,
|
||||||
|
"showWallpaperToggle": false
|
||||||
|
},
|
||||||
|
"verbose": true,
|
||||||
|
"vertical": false,
|
||||||
|
"workspaces": {
|
||||||
|
"alwaysShowNumbers": true,
|
||||||
|
"indicatorStyle": "dot",
|
||||||
|
"monochromeIcons": true,
|
||||||
|
"numberMap": [],
|
||||||
|
"showAppIcons": true,
|
||||||
|
"showNumberDelay": 200,
|
||||||
|
"shown": 10,
|
||||||
|
"useNerdFont": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"calendar": {
|
||||||
|
"locale": "en-GB"
|
||||||
|
},
|
||||||
|
"conflictKiller": {
|
||||||
|
"autoKillNotificationDaemons": true,
|
||||||
|
"autoKillTrays": true
|
||||||
|
},
|
||||||
|
"crosshair": {
|
||||||
|
"code": "0;P;d;1;0l;10;0o;2;1b;0"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"colorizeIcon": true,
|
||||||
|
"distroIcon": "google-gemini-symbolic"
|
||||||
|
},
|
||||||
|
"dock": {
|
||||||
|
"enable": true,
|
||||||
|
"height": 60,
|
||||||
|
"hoverRegionHeight": 2,
|
||||||
|
"hoverToReveal": true,
|
||||||
|
"ignoredAppRegexes": [],
|
||||||
|
"monochromeIcons": false,
|
||||||
|
"pinnedApps": [
|
||||||
|
"org.kde.dolphin",
|
||||||
|
"zen"
|
||||||
|
],
|
||||||
|
"pinnedOnStartup": false,
|
||||||
|
"showAppsButton": true,
|
||||||
|
"showBackground": true,
|
||||||
|
"showMedia": true,
|
||||||
|
"showPinButton": true
|
||||||
|
},
|
||||||
|
"hacks": {
|
||||||
|
"arbitraryRaceConditionDelay": 20
|
||||||
|
},
|
||||||
|
"hyprland": {
|
||||||
|
"animations": {
|
||||||
|
"animation": "normal",
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"activeOpacity": 1,
|
||||||
|
"blur": {
|
||||||
|
"enabled": false,
|
||||||
|
"passes": 3,
|
||||||
|
"size": 1
|
||||||
|
},
|
||||||
|
"inactiveOpacity": 0.95,
|
||||||
|
"rounding": 22,
|
||||||
|
"shadow": {
|
||||||
|
"enabled": true,
|
||||||
|
"range": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"borderColor": {
|
||||||
|
"activeOpacity": 0.47,
|
||||||
|
"activeRole": "layer0Border",
|
||||||
|
"enable": false,
|
||||||
|
"inactiveOpacity": 0.2,
|
||||||
|
"inactiveRole": "layer0Border"
|
||||||
|
},
|
||||||
|
"borderSize": 1,
|
||||||
|
"gapsIn": 2,
|
||||||
|
"gapsOut": 5
|
||||||
|
},
|
||||||
|
"idle": {
|
||||||
|
"lock": 300,
|
||||||
|
"screenOff": 600,
|
||||||
|
"suspend": 10800
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interactions": {
|
||||||
|
"deadPixelWorkaround": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"scrolling": {
|
||||||
|
"fasterTouchpadScroll": false,
|
||||||
|
"mouseScrollDeltaThreshold": 120,
|
||||||
|
"mouseScrollFactor": 120,
|
||||||
|
"touchpadScrollFactor": 450
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"launcher": {
|
||||||
|
"pinnedApps": [
|
||||||
|
"org.kde.dolphin",
|
||||||
|
"kitty",
|
||||||
|
"cmake-gui"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"light": {
|
||||||
|
"antiFlashbang": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"night": {
|
||||||
|
"automatic": false,
|
||||||
|
"colorTemperature": 5559,
|
||||||
|
"from": "19:00",
|
||||||
|
"to": "06:30"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lock": {
|
||||||
|
"blur": {
|
||||||
|
"enable": false,
|
||||||
|
"extraZoom": 1.1,
|
||||||
|
"radius": 100,
|
||||||
|
"size": 20
|
||||||
|
},
|
||||||
|
"centerClock": true,
|
||||||
|
"launchOnStartup": false,
|
||||||
|
"materialShapeChars": true,
|
||||||
|
"security": {
|
||||||
|
"requirePasswordToPower": true,
|
||||||
|
"unlockKeyring": true
|
||||||
|
},
|
||||||
|
"showLockedText": true,
|
||||||
|
"showMedia": true,
|
||||||
|
"showToolbars": true,
|
||||||
|
"showWidgets": false,
|
||||||
|
"useHyprlock": false
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"filterDuplicatePlayers": true
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"position": "top_right",
|
||||||
|
"timeout": 7000
|
||||||
|
},
|
||||||
|
"osd": {
|
||||||
|
"timeout": 3000
|
||||||
|
},
|
||||||
|
"osk": {
|
||||||
|
"layout": "qwerty_full",
|
||||||
|
"pinnedOnStartup": false
|
||||||
|
},
|
||||||
|
"overlay": {
|
||||||
|
"clickthroughOpacity": 0.8,
|
||||||
|
"darkenScreen": false,
|
||||||
|
"floatingImage": {
|
||||||
|
"imageSource": "https://media.tenor.com/H5U5bJzj3oAAAAAi/kukuru.gif",
|
||||||
|
"scale": 0.5
|
||||||
|
},
|
||||||
|
"openingZoomAnimation": true
|
||||||
|
},
|
||||||
|
"overview": {
|
||||||
|
"centerIcons": true,
|
||||||
|
"columns": 5,
|
||||||
|
"enable": true,
|
||||||
|
"orderBottomUp": false,
|
||||||
|
"orderRightLeft": false,
|
||||||
|
"rows": 2,
|
||||||
|
"scale": 0.18,
|
||||||
|
"style": "default"
|
||||||
|
},
|
||||||
|
"panelFamily": "ii",
|
||||||
|
"policies": {
|
||||||
|
"ai": 1,
|
||||||
|
"weeb": 1
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"avatarPath": "/home/alvin/Sync_Documents/",
|
||||||
|
"avatarPicture": "/home/alvin/Sync_Documents/Alvin logo original.png",
|
||||||
|
"descriptionText": "::uptime::",
|
||||||
|
"displayName": "",
|
||||||
|
"onlinePresets": true
|
||||||
|
},
|
||||||
|
"regionSelector": {
|
||||||
|
"annotation": {
|
||||||
|
"useSatty": false
|
||||||
|
},
|
||||||
|
"circle": {
|
||||||
|
"padding": 10,
|
||||||
|
"strokeWidth": 6
|
||||||
|
},
|
||||||
|
"rect": {
|
||||||
|
"showAimLines": true
|
||||||
|
},
|
||||||
|
"targetRegions": {
|
||||||
|
"content": true,
|
||||||
|
"contentRegionOpacity": 0.8,
|
||||||
|
"layers": true,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"selectionPadding": 5,
|
||||||
|
"showLabel": false,
|
||||||
|
"windows": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"historyLength": 60,
|
||||||
|
"updateInterval": 3100
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"borderColor": "layer0Border",
|
||||||
|
"borderSize": 1,
|
||||||
|
"collapsedSections": [],
|
||||||
|
"style": "default"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"ai": {
|
||||||
|
"textFadeIn": false
|
||||||
|
},
|
||||||
|
"banner": true,
|
||||||
|
"bannerImage": "",
|
||||||
|
"booru": {
|
||||||
|
"allowNsfw": true,
|
||||||
|
"defaultProvider": "yandere",
|
||||||
|
"limit": 20,
|
||||||
|
"zerochan": {
|
||||||
|
"username": "theodorer61"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bottomGroup": false,
|
||||||
|
"cornerOpen": {
|
||||||
|
"bottom": true,
|
||||||
|
"bottomLeftAction": "sidebarLeftOpen",
|
||||||
|
"bottomRightAction": "sidebarRightOpen",
|
||||||
|
"clickless": false,
|
||||||
|
"clicklessCornerEnd": true,
|
||||||
|
"clicklessCornerVerticalOffset": 1,
|
||||||
|
"cornerRegionHeight": 5,
|
||||||
|
"cornerRegionWidth": 250,
|
||||||
|
"enable": true,
|
||||||
|
"valueScroll": true,
|
||||||
|
"visualize": false
|
||||||
|
},
|
||||||
|
"keepRightSidebarLoaded": false,
|
||||||
|
"media": {
|
||||||
|
"artColors": false,
|
||||||
|
"artShape": "Oval",
|
||||||
|
"blurredBackground": false,
|
||||||
|
"enable": true,
|
||||||
|
"shapeArt": false,
|
||||||
|
"showLyrics": true
|
||||||
|
},
|
||||||
|
"mediaPlayer": false,
|
||||||
|
"quickSliders": {
|
||||||
|
"enable": true,
|
||||||
|
"showBrightness": true,
|
||||||
|
"showMic": true,
|
||||||
|
"showVolume": true
|
||||||
|
},
|
||||||
|
"quickToggles": {
|
||||||
|
"android": {
|
||||||
|
"columns": 6,
|
||||||
|
"toggles": [
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "network"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "bluetooth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "audio"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 1,
|
||||||
|
"type": "idleInhibitor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "mic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 1,
|
||||||
|
"type": "nightLight"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "powerProfile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"style": "android"
|
||||||
|
},
|
||||||
|
"translator": {
|
||||||
|
"delay": 300,
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tray": {
|
||||||
|
"filterPassive": true,
|
||||||
|
"invertPinnedItems": true,
|
||||||
|
"monochromeIcons": false,
|
||||||
|
"pinnedItems": [
|
||||||
|
"Fcitx"
|
||||||
|
],
|
||||||
|
"showItemId": false
|
||||||
|
},
|
||||||
|
"wallpaperSelector": {
|
||||||
|
"changeInterval": 0,
|
||||||
|
"closeAfterSelection": true,
|
||||||
|
"columns": 4,
|
||||||
|
"liveWallpapersPath": "",
|
||||||
|
"showBlurBackground": false,
|
||||||
|
"showHomePath": true,
|
||||||
|
"showSearchbar": true,
|
||||||
|
"sortMode": "time",
|
||||||
|
"useSystemFileDialog": false,
|
||||||
|
"userPath": "/home/alvin/Pictures/Wallpapers/"
|
||||||
|
},
|
||||||
|
"windows": {
|
||||||
|
"centerTitle": true,
|
||||||
|
"showTitlebar": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,676 @@
|
|||||||
|
{
|
||||||
|
"appearance": {
|
||||||
|
"extraBackgroundTint": true,
|
||||||
|
"fakeScreenRounding": 0,
|
||||||
|
"fonts": {
|
||||||
|
"expressive": "Space Grotesk",
|
||||||
|
"iconNerd": "JetBrains Mono NF",
|
||||||
|
"main": "Google Sans Flex",
|
||||||
|
"monospace": "JetBrains Mono NF",
|
||||||
|
"numbers": "Google Sans Flex",
|
||||||
|
"reading": "Readex Pro",
|
||||||
|
"title": "Google Sans Flex"
|
||||||
|
},
|
||||||
|
"palette": {
|
||||||
|
"accentColor": "",
|
||||||
|
"type": "scheme-tonal-spot"
|
||||||
|
},
|
||||||
|
"transparency": {
|
||||||
|
"automatic": true,
|
||||||
|
"backgroundTransparency": 0.11,
|
||||||
|
"contentTransparency": 0.57,
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"wallpaperTheming": {
|
||||||
|
"enableAppsAndShell": true,
|
||||||
|
"enableQtApps": true,
|
||||||
|
"enableTerminal": true,
|
||||||
|
"terminalGenerationProps": {
|
||||||
|
"forceDarkMode": false,
|
||||||
|
"harmonizeThreshold": 100,
|
||||||
|
"harmony": 0.5,
|
||||||
|
"termFgBoost": 0.35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"bluetooth": "kcmshell6 kcm_bluetooth",
|
||||||
|
"changePassword": "kitty -1 --hold=yes fish -i -c 'passwd'",
|
||||||
|
"manageUser": "kcmshell6 kcm_users",
|
||||||
|
"network": "kcmshell6 kcm_networkmanagement",
|
||||||
|
"networkEthernet": "kcmshell6 kcm_networkmanagement",
|
||||||
|
"taskManager": "plasma-systemmonitor --page-name Processes",
|
||||||
|
"terminal": "kitty -1",
|
||||||
|
"update": "kitty -1 --hold=yes fish -i -c 'pkexec pacman -Syu'",
|
||||||
|
"volumeMixer": "~/.config/hypr/hyprland/scripts/launch_first_available.sh \"pavucontrol-qt\" \"pavucontrol\""
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"blurRadius": 32,
|
||||||
|
"centeredWallpaper": false,
|
||||||
|
"centeredWallpaperColor": "primaryContainer",
|
||||||
|
"centeredWallpaperOnlyWhenLocked": false,
|
||||||
|
"centeredWallpaperShape": "Cookie7Sided",
|
||||||
|
"centeredWallpaperSize": 400,
|
||||||
|
"enableWallpaperPreview": false,
|
||||||
|
"hideWhenFullscreen": true,
|
||||||
|
"lockWall": "",
|
||||||
|
"parallax": {
|
||||||
|
"autoVertical": false,
|
||||||
|
"enableSidebar": true,
|
||||||
|
"enableWorkspace": true,
|
||||||
|
"vertical": false,
|
||||||
|
"widgetsFactor": 1.2,
|
||||||
|
"workspaceZoom": 1.07
|
||||||
|
},
|
||||||
|
"screenList": [],
|
||||||
|
"showBlur": true,
|
||||||
|
"showGrid": true,
|
||||||
|
"showSnapLines": true,
|
||||||
|
"splitRatio": "25",
|
||||||
|
"splitSide": "right",
|
||||||
|
"thumbnailPath": "",
|
||||||
|
"wallpaperAnimation": "random",
|
||||||
|
"wallpaperPath": "/home/alvin/Pictures/Wallpapers/Dynamic-Wallpapers/Dark/japan-street-Dark.png",
|
||||||
|
"widgets": {
|
||||||
|
"blurRadius": 32,
|
||||||
|
"blurWidgets": false,
|
||||||
|
"calendar": {
|
||||||
|
"enable": true,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "2x2",
|
||||||
|
"x": 1596,
|
||||||
|
"y": 744,
|
||||||
|
"z": 4
|
||||||
|
},
|
||||||
|
"clock": {
|
||||||
|
"color": "",
|
||||||
|
"cookie": {
|
||||||
|
"aiStyling": false,
|
||||||
|
"constantlyRotate": false,
|
||||||
|
"dateInClock": true,
|
||||||
|
"dateStyle": "bubble",
|
||||||
|
"dialNumberStyle": "full",
|
||||||
|
"hourHandStyle": "hollow",
|
||||||
|
"hourMarks": false,
|
||||||
|
"minuteHandStyle": "medium",
|
||||||
|
"secondHandStyle": "line",
|
||||||
|
"sides": 12,
|
||||||
|
"timeIndicators": true,
|
||||||
|
"useSineCookie": false
|
||||||
|
},
|
||||||
|
"digital": {
|
||||||
|
"adaptiveAlignment": true,
|
||||||
|
"animateChange": true,
|
||||||
|
"font": {
|
||||||
|
"family": "Google Sans Flex",
|
||||||
|
"roundness": 1.1290989771359807,
|
||||||
|
"size": 129.49608904933814,
|
||||||
|
"weight": 350,
|
||||||
|
"width": 99.44532190132371
|
||||||
|
},
|
||||||
|
"showDate": true,
|
||||||
|
"vertical": false
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"pixel": {
|
||||||
|
"orientation": "vertical"
|
||||||
|
},
|
||||||
|
"placementStrategy": "leastBusy",
|
||||||
|
"quote": {
|
||||||
|
"enable": true,
|
||||||
|
"followClock": false,
|
||||||
|
"text": "Kawaī neko o zenbu tabe chaimasu."
|
||||||
|
},
|
||||||
|
"showOnlyWhenLocked": false,
|
||||||
|
"style": "digital",
|
||||||
|
"styleLocked": "cookie",
|
||||||
|
"x": 1423,
|
||||||
|
"y": 383,
|
||||||
|
"z": 3
|
||||||
|
},
|
||||||
|
"customImage": {
|
||||||
|
"enable": true,
|
||||||
|
"path": "",
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"shape": "Cookie4Sided",
|
||||||
|
"size": 200,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"customText": {
|
||||||
|
"alignment": "center",
|
||||||
|
"color": "",
|
||||||
|
"content": "Hello world",
|
||||||
|
"enable": true,
|
||||||
|
"fontFamily": "Caveat",
|
||||||
|
"fontSize": 72,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"shadow": true,
|
||||||
|
"x": 400,
|
||||||
|
"y": 300,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"backgroundShape": "Cookie4Sided",
|
||||||
|
"enable": true,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"showControls": true,
|
||||||
|
"showLyrics": false,
|
||||||
|
"showTitles": true,
|
||||||
|
"sizeMode": "1x3",
|
||||||
|
"x": 744,
|
||||||
|
"y": 876,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"notes": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"vertical": false,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"shadow": true,
|
||||||
|
"sticker": {
|
||||||
|
"enable": false,
|
||||||
|
"items": [],
|
||||||
|
"outlineColor": "#ffffff",
|
||||||
|
"outlineWidth": 8,
|
||||||
|
"path": "",
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"rotation": 0,
|
||||||
|
"size": 200,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"timers": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"vertical": false,
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"todo": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"userCard": {
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "1x2",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"visualizer": {
|
||||||
|
"colorSource": "theme",
|
||||||
|
"enable": true,
|
||||||
|
"height": 342,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"ringSize": 380,
|
||||||
|
"sensitivity": 1.65,
|
||||||
|
"style": "mirror",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": -1000
|
||||||
|
},
|
||||||
|
"weather": {
|
||||||
|
"enable": false,
|
||||||
|
"expanded": false,
|
||||||
|
"placementStrategy": "mostBusy",
|
||||||
|
"sizeMode": "1x3",
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"worldClock": {
|
||||||
|
"clockCount": 4,
|
||||||
|
"enable": false,
|
||||||
|
"placementStrategy": "free",
|
||||||
|
"sizeMode": "2x2",
|
||||||
|
"timezones": [
|
||||||
|
"Australia/Sydney",
|
||||||
|
"Asia/Tokyo",
|
||||||
|
"Europe/London",
|
||||||
|
"America/New_York"
|
||||||
|
],
|
||||||
|
"x": 400,
|
||||||
|
"y": 100,
|
||||||
|
"z": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgetsLocked": false
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
"autoHide": {
|
||||||
|
"enable": false,
|
||||||
|
"hoverRegionWidth": 2,
|
||||||
|
"pushWindows": false,
|
||||||
|
"showWhenPressingSuper": {
|
||||||
|
"delay": 140,
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"borderless": "transparent",
|
||||||
|
"bottom": false,
|
||||||
|
"centerOnlyReserveFrame": false,
|
||||||
|
"cornerStyle": 3,
|
||||||
|
"divider": {
|
||||||
|
"spacing": 20,
|
||||||
|
"style": "rect"
|
||||||
|
},
|
||||||
|
"dynamicIsland": {
|
||||||
|
"leftWidget": "clockWidget",
|
||||||
|
"rightWidget": "systemIcons",
|
||||||
|
"showMediaControls": false,
|
||||||
|
"visualizerStyle": "wave"
|
||||||
|
},
|
||||||
|
"floatStyleShadow": true,
|
||||||
|
"followFrameColor": false,
|
||||||
|
"frameColor": "secondaryContainer",
|
||||||
|
"frameThickness": 4,
|
||||||
|
"groupColor": "layer1",
|
||||||
|
"indicators": {
|
||||||
|
"notifications": {
|
||||||
|
"showUnreadCount": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"leftLayout": [
|
||||||
|
"leftSidebarButton",
|
||||||
|
"activeWindow",
|
||||||
|
"resources"
|
||||||
|
],
|
||||||
|
"middleLayout": [
|
||||||
|
"media",
|
||||||
|
"clockWidget",
|
||||||
|
"workspaces",
|
||||||
|
"utilButtons",
|
||||||
|
"weatherBar"
|
||||||
|
],
|
||||||
|
"rightLayout": [
|
||||||
|
"sysTray",
|
||||||
|
"updatesCount",
|
||||||
|
"bluetooth",
|
||||||
|
"systemIcons"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"alwaysVisible": false,
|
||||||
|
"maxWidth": 280,
|
||||||
|
"minWidth": 100,
|
||||||
|
"onlyTitle": false,
|
||||||
|
"preferredPlayer": "",
|
||||||
|
"showLyrics": false
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"alwaysShowCpu": true,
|
||||||
|
"alwaysShowCpuTemp": true,
|
||||||
|
"alwaysShowDisk": false,
|
||||||
|
"alwaysShowRam": true,
|
||||||
|
"alwaysShowSwap": false,
|
||||||
|
"cpuWarningThreshold": 90,
|
||||||
|
"memoryWarningThreshold": 95,
|
||||||
|
"showValue": true,
|
||||||
|
"style": "outline",
|
||||||
|
"swapWarningThreshold": 85
|
||||||
|
},
|
||||||
|
"screenList": [],
|
||||||
|
"showBackground": true,
|
||||||
|
"showFrame": false,
|
||||||
|
"tooltips": {
|
||||||
|
"clickToShow": false,
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"topLeftIcon": "spark",
|
||||||
|
"utilButtons": {
|
||||||
|
"isRecording": false,
|
||||||
|
"showColorPicker": false,
|
||||||
|
"showDarkModeToggle": false,
|
||||||
|
"showKeyboardToggle": false,
|
||||||
|
"showMicToggle": true,
|
||||||
|
"showPerformanceProfileToggle": true,
|
||||||
|
"showScreenRecord": false,
|
||||||
|
"showScreenSnip": false,
|
||||||
|
"showWallpaperToggle": false
|
||||||
|
},
|
||||||
|
"verbose": true,
|
||||||
|
"vertical": false,
|
||||||
|
"workspaces": {
|
||||||
|
"alwaysShowNumbers": true,
|
||||||
|
"indicatorStyle": "dot",
|
||||||
|
"monochromeIcons": true,
|
||||||
|
"numberMap": [],
|
||||||
|
"showAppIcons": true,
|
||||||
|
"showNumberDelay": 200,
|
||||||
|
"shown": 10,
|
||||||
|
"useNerdFont": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"calendar": {
|
||||||
|
"locale": "en-GB"
|
||||||
|
},
|
||||||
|
"conflictKiller": {
|
||||||
|
"autoKillNotificationDaemons": true,
|
||||||
|
"autoKillTrays": true
|
||||||
|
},
|
||||||
|
"crosshair": {
|
||||||
|
"code": "0;P;d;1;0l;10;0o;2;1b;0"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"colorizeIcon": true,
|
||||||
|
"distroIcon": "google-gemini-symbolic"
|
||||||
|
},
|
||||||
|
"dock": {
|
||||||
|
"enable": true,
|
||||||
|
"height": 60,
|
||||||
|
"hoverRegionHeight": 2,
|
||||||
|
"hoverToReveal": true,
|
||||||
|
"ignoredAppRegexes": [],
|
||||||
|
"monochromeIcons": false,
|
||||||
|
"pinnedApps": [
|
||||||
|
"org.kde.dolphin",
|
||||||
|
"zen"
|
||||||
|
],
|
||||||
|
"pinnedOnStartup": false,
|
||||||
|
"showAppsButton": true,
|
||||||
|
"showBackground": true,
|
||||||
|
"showMedia": true,
|
||||||
|
"showPinButton": true
|
||||||
|
},
|
||||||
|
"hacks": {
|
||||||
|
"arbitraryRaceConditionDelay": 20
|
||||||
|
},
|
||||||
|
"hyprland": {
|
||||||
|
"animations": {
|
||||||
|
"animation": "normal",
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"decoration": {
|
||||||
|
"activeOpacity": 1,
|
||||||
|
"blur": {
|
||||||
|
"enabled": false,
|
||||||
|
"passes": 3,
|
||||||
|
"size": 1
|
||||||
|
},
|
||||||
|
"inactiveOpacity": 0.95,
|
||||||
|
"rounding": 22,
|
||||||
|
"shadow": {
|
||||||
|
"enabled": true,
|
||||||
|
"range": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"borderColor": {
|
||||||
|
"activeOpacity": 0.47,
|
||||||
|
"activeRole": "layer0Border",
|
||||||
|
"enable": false,
|
||||||
|
"inactiveOpacity": 0.2,
|
||||||
|
"inactiveRole": "layer0Border"
|
||||||
|
},
|
||||||
|
"borderSize": 1,
|
||||||
|
"gapsIn": 2,
|
||||||
|
"gapsOut": 5
|
||||||
|
},
|
||||||
|
"idle": {
|
||||||
|
"lock": 300,
|
||||||
|
"screenOff": 600,
|
||||||
|
"suspend": 10800
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interactions": {
|
||||||
|
"deadPixelWorkaround": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"scrolling": {
|
||||||
|
"fasterTouchpadScroll": false,
|
||||||
|
"mouseScrollDeltaThreshold": 120,
|
||||||
|
"mouseScrollFactor": 120,
|
||||||
|
"touchpadScrollFactor": 450
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"launcher": {
|
||||||
|
"pinnedApps": [
|
||||||
|
"org.kde.dolphin",
|
||||||
|
"kitty",
|
||||||
|
"cmake-gui"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"light": {
|
||||||
|
"antiFlashbang": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"night": {
|
||||||
|
"automatic": false,
|
||||||
|
"colorTemperature": 5559,
|
||||||
|
"from": "19:00",
|
||||||
|
"to": "06:30"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lock": {
|
||||||
|
"blur": {
|
||||||
|
"enable": false,
|
||||||
|
"extraZoom": 1.1,
|
||||||
|
"radius": 100,
|
||||||
|
"size": 20
|
||||||
|
},
|
||||||
|
"centerClock": true,
|
||||||
|
"launchOnStartup": false,
|
||||||
|
"materialShapeChars": true,
|
||||||
|
"security": {
|
||||||
|
"requirePasswordToPower": true,
|
||||||
|
"unlockKeyring": true
|
||||||
|
},
|
||||||
|
"showLockedText": true,
|
||||||
|
"showMedia": true,
|
||||||
|
"showToolbars": true,
|
||||||
|
"showWidgets": false,
|
||||||
|
"useHyprlock": false
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"filterDuplicatePlayers": true
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"position": "top_right",
|
||||||
|
"timeout": 7000
|
||||||
|
},
|
||||||
|
"osd": {
|
||||||
|
"timeout": 3000
|
||||||
|
},
|
||||||
|
"osk": {
|
||||||
|
"layout": "qwerty_full",
|
||||||
|
"pinnedOnStartup": false
|
||||||
|
},
|
||||||
|
"overlay": {
|
||||||
|
"clickthroughOpacity": 0.8,
|
||||||
|
"darkenScreen": false,
|
||||||
|
"floatingImage": {
|
||||||
|
"imageSource": "https://media.tenor.com/H5U5bJzj3oAAAAAi/kukuru.gif",
|
||||||
|
"scale": 0.5
|
||||||
|
},
|
||||||
|
"openingZoomAnimation": true
|
||||||
|
},
|
||||||
|
"overview": {
|
||||||
|
"centerIcons": true,
|
||||||
|
"columns": 5,
|
||||||
|
"enable": true,
|
||||||
|
"orderBottomUp": false,
|
||||||
|
"orderRightLeft": false,
|
||||||
|
"rows": 2,
|
||||||
|
"scale": 0.18,
|
||||||
|
"style": "default"
|
||||||
|
},
|
||||||
|
"panelFamily": "ii",
|
||||||
|
"policies": {
|
||||||
|
"ai": 1,
|
||||||
|
"weeb": 1
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"avatarPath": "",
|
||||||
|
"avatarPicture": "",
|
||||||
|
"descriptionText": "::uptime::",
|
||||||
|
"displayName": "",
|
||||||
|
"onlinePresets": false
|
||||||
|
},
|
||||||
|
"regionSelector": {
|
||||||
|
"annotation": {
|
||||||
|
"useSatty": false
|
||||||
|
},
|
||||||
|
"circle": {
|
||||||
|
"padding": 10,
|
||||||
|
"strokeWidth": 6
|
||||||
|
},
|
||||||
|
"rect": {
|
||||||
|
"showAimLines": true
|
||||||
|
},
|
||||||
|
"targetRegions": {
|
||||||
|
"content": true,
|
||||||
|
"contentRegionOpacity": 0.8,
|
||||||
|
"layers": true,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"selectionPadding": 5,
|
||||||
|
"showLabel": false,
|
||||||
|
"windows": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"historyLength": 60,
|
||||||
|
"updateInterval": 3100
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"borderColor": "layer0Border",
|
||||||
|
"borderSize": 1,
|
||||||
|
"collapsedSections": [],
|
||||||
|
"style": "default"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"ai": {
|
||||||
|
"textFadeIn": false
|
||||||
|
},
|
||||||
|
"banner": true,
|
||||||
|
"bannerImage": "",
|
||||||
|
"booru": {
|
||||||
|
"allowNsfw": true,
|
||||||
|
"defaultProvider": "yandere",
|
||||||
|
"limit": 20,
|
||||||
|
"zerochan": {
|
||||||
|
"username": "theodorer61"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bottomGroup": false,
|
||||||
|
"cornerOpen": {
|
||||||
|
"bottom": true,
|
||||||
|
"bottomLeftAction": "sidebarLeftOpen",
|
||||||
|
"bottomRightAction": "sidebarRightOpen",
|
||||||
|
"clickless": false,
|
||||||
|
"clicklessCornerEnd": true,
|
||||||
|
"clicklessCornerVerticalOffset": 1,
|
||||||
|
"cornerRegionHeight": 5,
|
||||||
|
"cornerRegionWidth": 250,
|
||||||
|
"enable": true,
|
||||||
|
"valueScroll": true,
|
||||||
|
"visualize": false
|
||||||
|
},
|
||||||
|
"keepRightSidebarLoaded": false,
|
||||||
|
"media": {
|
||||||
|
"artColors": false,
|
||||||
|
"artShape": "Oval",
|
||||||
|
"blurredBackground": false,
|
||||||
|
"enable": true,
|
||||||
|
"shapeArt": false,
|
||||||
|
"showLyrics": true
|
||||||
|
},
|
||||||
|
"mediaPlayer": false,
|
||||||
|
"quickSliders": {
|
||||||
|
"enable": true,
|
||||||
|
"showBrightness": true,
|
||||||
|
"showMic": true,
|
||||||
|
"showVolume": true
|
||||||
|
},
|
||||||
|
"quickToggles": {
|
||||||
|
"android": {
|
||||||
|
"columns": 6,
|
||||||
|
"toggles": [
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "network"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "bluetooth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "audio"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 1,
|
||||||
|
"type": "idleInhibitor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "mic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 1,
|
||||||
|
"type": "nightLight"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 2,
|
||||||
|
"type": "powerProfile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"style": "android"
|
||||||
|
},
|
||||||
|
"translator": {
|
||||||
|
"delay": 300,
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tray": {
|
||||||
|
"filterPassive": true,
|
||||||
|
"invertPinnedItems": true,
|
||||||
|
"monochromeIcons": false,
|
||||||
|
"pinnedItems": [
|
||||||
|
"Fcitx"
|
||||||
|
],
|
||||||
|
"showItemId": false
|
||||||
|
},
|
||||||
|
"wallpaperSelector": {
|
||||||
|
"changeInterval": 0,
|
||||||
|
"closeAfterSelection": true,
|
||||||
|
"columns": 4,
|
||||||
|
"liveWallpapersPath": "",
|
||||||
|
"showBlurBackground": false,
|
||||||
|
"showHomePath": true,
|
||||||
|
"showSearchbar": true,
|
||||||
|
"sortMode": "time",
|
||||||
|
"useSystemFileDialog": false,
|
||||||
|
"userPath": "/home/alvin/Pictures/Wallpapers/"
|
||||||
|
},
|
||||||
|
"windows": {
|
||||||
|
"centerTitle": true,
|
||||||
|
"showTitlebar": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,186 +0,0 @@
|
|||||||
# If you come from bash, you might have to change your $PATH.
|
|
||||||
export PATH=$HOME/bin:/usr/local/bin:$PATH
|
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
|
||||||
export WAYLAND_DISPLAY=$WAYLAND_DISPLAY
|
|
||||||
export XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR
|
|
||||||
|
|
||||||
# Homebrew (If installed)
|
|
||||||
if [[ -f "/home/linusbrew/.linuxbrew/bin/brew" ]]; then
|
|
||||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv zsh)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ghostty (If exists)
|
|
||||||
if [ -n "${GHOSTTY_RESOURCES_DIR}" ]; then
|
|
||||||
builtin source "${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Path to your oh-my-zsh installation.
|
|
||||||
export ZSH=~/.oh-my-zsh
|
|
||||||
|
|
||||||
# Set the name of the theme to load. If you set this to "random"
|
|
||||||
# It'll load a random theme each time that oh-my-zsh is loaded.
|
|
||||||
# See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes
|
|
||||||
ZSH_THEME="gnzh"
|
|
||||||
|
|
||||||
# Set the list of themes to load
|
|
||||||
# Setting this variable when ZSH_THEME=random
|
|
||||||
# cause zsh to load the theme from this variable instead of
|
|
||||||
# looking in ~/.oh-my-zsh/themes/
|
|
||||||
# An empty array has no effect
|
|
||||||
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
|
|
||||||
|
|
||||||
# Uncomment the following line to use case-sensitive completion.
|
|
||||||
CASE_SENSITIVE="true"
|
|
||||||
|
|
||||||
#Zsh autocorrect
|
|
||||||
unsetopt correct_all
|
|
||||||
|
|
||||||
# Uncomment the following line to use hyphen-insensitive completion. Case
|
|
||||||
# sensitive completion must be off. _ and - will be interchangeable.
|
|
||||||
# HYPHEN_INSENSITIVE="true"
|
|
||||||
|
|
||||||
# Uncomment the following line to disable bi-weekly auto-update checks.
|
|
||||||
# DISABLE_AUTO_UPDATE="true"
|
|
||||||
|
|
||||||
# Uncomment the following line to change how often auto-update (in days) is used.
|
|
||||||
# export UPDATE_ZSH_DAYS=13
|
|
||||||
|
|
||||||
# Uncomment the following line to disable colours in ls.
|
|
||||||
# DISABLE_LS_COLORS="true"
|
|
||||||
|
|
||||||
# Uncomment the following line to disable auto-setting the terminal title.
|
|
||||||
# DISABLE_AUTO_TITLE="true"
|
|
||||||
|
|
||||||
# Uncomment the following line to enable command auto-correction.
|
|
||||||
# ENABLE_CORRECTION="true"
|
|
||||||
|
|
||||||
# Uncomment the following line to display red dots whilst waiting for completion.
|
|
||||||
# COMPLETION_WAITING_DOTS="true"
|
|
||||||
|
|
||||||
# Uncomment the following line if you want to disable marking untracked files
|
|
||||||
# under VCS as dirty. This makes repository status checks for large repositories
|
|
||||||
# much, much faster.
|
|
||||||
# DISABLE_UNTRACKED_FILES_DIRTY="true"
|
|
||||||
|
|
||||||
# Uncomment the following line if you want to change the command execution time
|
|
||||||
# stamp shown in the history command output.
|
|
||||||
# The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
|
|
||||||
# HIST_STAMPS="mm/dd/yyyy"
|
|
||||||
|
|
||||||
# Uncomment the following to use another custom folder than $ZSH/custom?
|
|
||||||
# ZSH_CUSTOM=/path/to/new-custom-folder
|
|
||||||
|
|
||||||
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
|
|
||||||
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
|
|
||||||
# Example format: plugins=(rails git textmate ruby lighthouse)
|
|
||||||
# Add wisely, as too many plugins slow down shell startup.
|
|
||||||
plugins=(
|
|
||||||
git
|
|
||||||
zsh-history-substring-search
|
|
||||||
zsh-autosuggestions
|
|
||||||
zsh-autocomplete
|
|
||||||
# zsh-eza
|
|
||||||
fzf-zsh-plugin
|
|
||||||
zsh-syntax-highlighting
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
source $ZSH/oh-my-zsh.sh
|
|
||||||
|
|
||||||
# User configuration
|
|
||||||
|
|
||||||
# export MANPATH="/usr/local/man:$MANPATH"
|
|
||||||
|
|
||||||
# You may need to set your language environment manually
|
|
||||||
# export LANG=en_US.UTF-8
|
|
||||||
|
|
||||||
# Preferred editor for local and remote sessions
|
|
||||||
if [[ -n $SSH_CONNECTION ]]; then
|
|
||||||
export EDITOR='vim'
|
|
||||||
else
|
|
||||||
export EDITOR='nvim'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Compilation flags
|
|
||||||
# export ARCHFLAGS="-arch x86_64"
|
|
||||||
|
|
||||||
# ssh
|
|
||||||
# export SSH_KEY_PATH="~/.ssh/rsa_id"
|
|
||||||
|
|
||||||
update () {
|
|
||||||
# Update arch based systems with yay AUR helper
|
|
||||||
if command -v pacman >/dev/null && command -v yay >/dev/null; then
|
|
||||||
echo "✅ 'pacman' and 'yay' found. Updating."
|
|
||||||
sudo pacman -Syu --noconfirm
|
|
||||||
yay -Syu --sudoloop --save --answerclean None --answerdiff None --noconfirm
|
|
||||||
elif command -v pacman >/dev/null; then
|
|
||||||
echo "✅ 'pacman' found. Updating."
|
|
||||||
sudo pacman -Syu --noconfirm
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v paru >/dev/null; then
|
|
||||||
echo "✅ 'flatpak' found. Updating."
|
|
||||||
paru -Syu
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update on debian based systems
|
|
||||||
if command -v apt >/dev/null; then
|
|
||||||
echo "✅ 'apt' found. Updating."
|
|
||||||
sudo apt update && sudo apt full-upgrade -y
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update Hyprland
|
|
||||||
if command -v hyprpm >/dev/null; then
|
|
||||||
echo "✅ 'hyprpm' found. Updating."
|
|
||||||
hyprpm reload && sleep 2
|
|
||||||
hyprpm update
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update Flatpak
|
|
||||||
if command -v flatpak >/dev/null; then
|
|
||||||
echo "✅ 'flatpak' found. Updating."
|
|
||||||
flatpak update -y
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update npm
|
|
||||||
if command -v npm >/dev/null; then
|
|
||||||
echo "✅ 'npm' found. Updating."
|
|
||||||
sudo npm install -g npm-check-updates
|
|
||||||
fi
|
|
||||||
|
|
||||||
omz update
|
|
||||||
}
|
|
||||||
|
|
||||||
# Sudo last command with control + u
|
|
||||||
|
|
||||||
zle -N sudo-last-command-execute
|
|
||||||
sudo-last-command-execute() {
|
|
||||||
|
|
||||||
zle -U $'sudo !!\n'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bind the widget to Alt+S
|
|
||||||
bindkey '^[S' sudo-last-command-execute
|
|
||||||
|
|
||||||
# Ydotool
|
|
||||||
if [[ -f "/tmp/.ydotool_socket" ]]; then
|
|
||||||
export YDOTOOL_SOCKET=/tmp/.ydotool_socket
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Haven android ssh client
|
|
||||||
precmd() { print -Pn '\e]133;D;%?\a\e]133;A\a' }
|
|
||||||
preexec() { print -Pn '\e]133;B\a\e]133;C\a' }
|
|
||||||
|
|
||||||
# Set personal aliases, overriding those provided by oh-my-zsh libs,
|
|
||||||
# plugins, and themes. Aliases can be placed here, though oh-my-zsh
|
|
||||||
# users are encouraged to define aliases within the ZSH_CUSTOM folder.
|
|
||||||
# For a full list of active aliases, run `alias`.
|
|
||||||
#
|
|
||||||
# Example aliases
|
|
||||||
# alias zshconfig="mate ~/.zshrc"
|
|
||||||
# alias ohmyzsh="mate ~/.oh-my-zsh"
|
|
||||||
|
|
||||||
alias lzd="lazydocker"
|
|
||||||
alias edit="nvim"
|
|
||||||
alias rpi="pkexec /usr/bin/rpi-imager"
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[Match]
|
|
||||||
Type=ether
|
|
||||||
# Exclude virtual Ethernet interfaces
|
|
||||||
Kind=!*
|
|
||||||
|
|
||||||
[Link]
|
|
||||||
RequiredForOnline=routable
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
DHCP=yes
|
|
||||||
MulticastDNS=yes
|
|
||||||
|
|
||||||
# systemd-networkd does not set per-interface-type default route metrics
|
|
||||||
# https://github.com/systemd/systemd/issues/17698
|
|
||||||
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
|
|
||||||
# Use values from NetworkManager. From nm_device_get_route_metric_default in
|
|
||||||
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
|
|
||||||
[DHCPv4]
|
|
||||||
RouteMetric=100
|
|
||||||
|
|
||||||
[IPv6AcceptRA]
|
|
||||||
RouteMetric=100
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
[Match]
|
|
||||||
Type=wlan
|
|
||||||
|
|
||||||
[Link]
|
|
||||||
RequiredForOnline=routable
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
DHCP=yes
|
|
||||||
MulticastDNS=yes
|
|
||||||
|
|
||||||
# systemd-networkd does not set per-interface-type default route metrics
|
|
||||||
# https://github.com/systemd/systemd/issues/17698
|
|
||||||
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
|
|
||||||
# Use values from NetworkManager. From nm_device_get_route_metric_default in
|
|
||||||
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
|
|
||||||
[DHCPv4]
|
|
||||||
RouteMetric=600
|
|
||||||
|
|
||||||
[IPv6AcceptRA]
|
|
||||||
RouteMetric=600
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Match]
|
|
||||||
Type=wwan
|
|
||||||
|
|
||||||
[Link]
|
|
||||||
RequiredForOnline=routable
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
DHCP=yes
|
|
||||||
|
|
||||||
# systemd-networkd does not set per-interface-type default route metrics
|
|
||||||
# https://github.com/systemd/systemd/issues/17698
|
|
||||||
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
|
|
||||||
# Use values from NetworkManager. From nm_device_get_route_metric_default in
|
|
||||||
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
|
|
||||||
[DHCPv4]
|
|
||||||
RouteMetric=700
|
|
||||||
|
|
||||||
[IPv6AcceptRA]
|
|
||||||
RouteMetric=700
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/usr/lib/systemd/system/NetworkManager.service
|
||||||
@@ -1 +0,0 @@
|
|||||||
/usr/lib/systemd/system/systemd-networkd.service
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/usr/lib/systemd/system/systemd-resolved.service
|
|
||||||
@@ -49,3 +49,12 @@ Include = /etc/pacman.d/cachyos-mirrorlist
|
|||||||
[chaotic-aur]
|
[chaotic-aur]
|
||||||
SigLevel = Required DatabaseOptional
|
SigLevel = Required DatabaseOptional
|
||||||
Include = /etc/pacman.d/chaotic-mirrorlist
|
Include = /etc/pacman.d/chaotic-mirrorlist
|
||||||
|
|
||||||
|
[local-aur]
|
||||||
|
# Ships on the medium only: packages built at ISO build time (end-4
|
||||||
|
# dependencies, plus localrepo/). Keeps pacstrap from needing the network for
|
||||||
|
# anything that is not in the official repos. alvin-install strips this whole
|
||||||
|
# section from the target system's pacman.conf, because /opt/localrepo exists
|
||||||
|
# only on the live medium.
|
||||||
|
SigLevel = Optional TrustAll
|
||||||
|
Server = file:///opt/localrepo
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# The chroot's /dev is the kernel's single shared devtmpfs, which only gets the
|
||||||
|
# fd/stdin/stdout/stderr symlinks at boot (from mkinitcpio's init). If the
|
||||||
|
# runner environment lacks them, process substitution (< <(...)) and upstream
|
||||||
|
# tools (pacman-key) fail with "… /dev/fd/63: No such file or directory".
|
||||||
|
# Self-heal here; the CI build-iso workflow does the same before pacstrap so
|
||||||
|
# that mkinitcpio's hook (which pipes through /dev/stdin) works too.
|
||||||
|
for _link in "fd:/proc/self/fd" "stdin:/proc/self/fd/0" \
|
||||||
|
"stdout:/proc/self/fd/1" "stderr:/proc/self/fd/2"; do
|
||||||
|
[[ -e "/dev/${_link%%:*}" || -L "/dev/${_link%%:*}" ]] ||
|
||||||
|
ln -sfn "${_link#*:}" "/dev/${_link%%:*}"
|
||||||
|
done
|
||||||
|
unset _link
|
||||||
|
|
||||||
# Populate the keyring in the built root from the keyring bundles
|
# Populate the keyring in the built root from the keyring bundles
|
||||||
# (/usr/share/pacman/keyrings, incl. the copied cachyos keyring).
|
# (/usr/share/pacman/keyrings, incl. the copied cachyos keyring).
|
||||||
# This mirrors the guide; it runs inside the image you are making.
|
# This mirrors the guide; it runs inside the image you are making.
|
||||||
@@ -14,6 +27,13 @@ pacman-key --populate archlinux cachyos chaotic
|
|||||||
install -m 0644 /root/.live-pacman.conf /etc/pacman.conf
|
install -m 0644 /root/.live-pacman.conf /etc/pacman.conf
|
||||||
rm -f /root/.live-pacman.conf
|
rm -f /root/.live-pacman.conf
|
||||||
|
|
||||||
|
# Build stamp staged by profiledef.sh (absent for non-git, non-CI builds):
|
||||||
|
# keep it where alvin-install looks for it, drop the staging copy.
|
||||||
|
if [[ -f /root/.iso-build-stamp ]]; then
|
||||||
|
install -m 0644 /root/.iso-build-stamp /etc/alvin-build-stamp
|
||||||
|
rm -f /root/.iso-build-stamp
|
||||||
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Pre-install dotfile dependencies into /etc/skel so new users get them
|
# Pre-install dotfile dependencies into /etc/skel so new users get them
|
||||||
# instantly on first login (no network required).
|
# instantly on first login (no network required).
|
||||||
@@ -57,6 +77,263 @@ if [[ ! -d "${NVIM_DATA}/lazy/lazy.nvim" ]]; then
|
|||||||
https://github.com/folke/lazy.nvim.git "${NVIM_DATA}/lazy/lazy.nvim"
|
https://github.com/folke/lazy.nvim.git "${NVIM_DATA}/lazy/lazy.nvim"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── end-4 dots-hyprland, staged for alvin-install (avoids a clone at install) ─
|
||||||
|
DOTS_REPO="/opt/dots-hyprland"
|
||||||
|
if [[ ! -d "${DOTS_REPO}/.git" ]]; then
|
||||||
|
echo "[customize] Cloning end-4 dots-hyprland..."
|
||||||
|
git clone --depth=1 https://github.com/end-4/dots-hyprland.git "${DOTS_REPO}"
|
||||||
|
git -C "${DOTS_REPO}" submodule update --init --depth=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── end4-pC: the default quickshell config, shipped in skel ──────────────────
|
||||||
|
# pctrade/end4-pC is a fork of the ii shell config. It lives next to ii in
|
||||||
|
# ~/.config/quickshell and does not modify it; which one runs is decided by
|
||||||
|
# qsConfig (patched just below). The repo has no submodules.
|
||||||
|
if [[ ! -d "${SKEL}/.config/quickshell/end4-pC" ]]; then
|
||||||
|
echo "[customize] Cloning end4-pC quickshell config into skel..."
|
||||||
|
git clone --depth=1 https://github.com/pctrade/end4-pC.git \
|
||||||
|
"${SKEL}/.config/quickshell/end4-pC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Default quickshell config: ii -> end4-pC ─────────────────────────────────
|
||||||
|
# alvin-install copies this staged repo onto the target and runs `./setup
|
||||||
|
# install`, whose rsync writes hypr/hyprland/variables.lua into the user's
|
||||||
|
# home - so patching the staged copy is what sets qsConfig on the installed
|
||||||
|
# system. Re-running is a no-op; anything other than ii/end4-pC aborts.
|
||||||
|
VARIABLES_LUA="${DOTS_REPO}/dots/.config/hypr/hyprland/variables.lua"
|
||||||
|
if grep -Fq 'hl.env("qsConfig", "ii")' "${VARIABLES_LUA}"; then
|
||||||
|
echo "[customize] Setting qsConfig to end4-pC..."
|
||||||
|
sed -i 's|hl\.env("qsConfig", "ii")|hl.env("qsConfig", "end4-pC")|' "${VARIABLES_LUA}"
|
||||||
|
fi
|
||||||
|
if ! grep -Fq 'hl.env("qsConfig", "end4-pC")' "${VARIABLES_LUA}"; then
|
||||||
|
echo "[customize] qsConfig is neither ii nor end4-pC in ${VARIABLES_LUA}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Pre-install end-4 dependencies into the image (network heavy, once per ISO)
|
||||||
|
# ============================================================================
|
||||||
|
# ./setup install-deps resolves and *builds* every AUR/source dependency the
|
||||||
|
# dotfiles need (quickshell, MicroTeX, theming, fonts, ...). Doing it here lets
|
||||||
|
# alvin-install run its end-4 step with --skip-alldeps, so an install only
|
||||||
|
# copies files - no AUR clones, no makepkg, no dependency resolution.
|
||||||
|
#
|
||||||
|
# The script refuses to run as root, hence the throwaway builder account.
|
||||||
|
# ============================================================================
|
||||||
|
BUILD_USER="ii-builder"
|
||||||
|
|
||||||
|
if ! id -u "${BUILD_USER}" &>/dev/null; then
|
||||||
|
useradd -m -u 1500 "${BUILD_USER}"
|
||||||
|
fi
|
||||||
|
echo "${BUILD_USER} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/99-ii-builder
|
||||||
|
chmod 440 /etc/sudoers.d/99-ii-builder
|
||||||
|
|
||||||
|
# makepkg writes src/, pkg/ and *.pkg.tar.zst into the PKGBUILD directories,
|
||||||
|
# so the tree must be owned by the account that runs it.
|
||||||
|
chown -R "${BUILD_USER}:${BUILD_USER}" "${DOTS_REPO}"
|
||||||
|
|
||||||
|
# -f: never prompt (ask=false); -s: skip "pacman -Syu";
|
||||||
|
# --skip-plasmaintg: optional Firefox widget that pulls 410 pkgs / 526 MiB of
|
||||||
|
# KDE packages onto a non-KDE system;
|
||||||
|
# stdin: answer end-4's x() failure prompt with "e", so a failed command
|
||||||
|
# aborts the build instead of blocking forever without a TTY.
|
||||||
|
# shellcheck disable=SC2024 # the redirect is meant for the child, not sudo
|
||||||
|
if ! sudo -u "${BUILD_USER}" env HOME="/home/${BUILD_USER}" \
|
||||||
|
GIT_TERMINAL_PROMPT=0 \
|
||||||
|
bash -c "cd ${DOTS_REPO} && ./setup install-deps -f -s --skip-plasmaintg" \
|
||||||
|
< <(yes e); then
|
||||||
|
echo "[customize] end-4 ./setup install-deps failed" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Harvest the packages install-deps just built into the in-image local repo ─
|
||||||
|
# The live /etc/pacman.conf points [local-aur] at /opt/localrepo; without the
|
||||||
|
# harvested copies pacstrap cannot resolve these packages at install time and
|
||||||
|
# would silently drop them from the target system.
|
||||||
|
mkdir -p /opt/localrepo
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
# <name> <version> from a package's embedded .PKGINFO (update.sh does the same)
|
||||||
|
pkg_meta() {
|
||||||
|
tar -xOf "$1" .PKGINFO 2>/dev/null |
|
||||||
|
awk -F' = ' '/^pkgname = /{n=$2} /^pkgver = /{v=$2} END{print n, v}'
|
||||||
|
}
|
||||||
|
|
||||||
|
mapfile -d '' -t built_pkgs < <(
|
||||||
|
find "${DOTS_REPO}" "/home/${BUILD_USER}/.cache/yay" \
|
||||||
|
-name '*.pkg.tar.zst' -print0 2>/dev/null
|
||||||
|
)
|
||||||
|
|
||||||
|
declare -A built_file=() built_ver=()
|
||||||
|
for p in "${built_pkgs[@]}"; do
|
||||||
|
read -r n v < <(pkg_meta "$p")
|
||||||
|
[[ -n "${n:-}" && -n "${v:-}" ]] || continue
|
||||||
|
built_file["$n"]="$p"
|
||||||
|
built_ver["$n"]="$v"
|
||||||
|
done
|
||||||
|
|
||||||
|
# One entry per package name, and the entry must be the version the image
|
||||||
|
# actually installed - a stale copy with the same name but another version
|
||||||
|
# would let pacstrap install something else than what was tested.
|
||||||
|
for existing in /opt/localrepo/*.pkg.tar.zst; do
|
||||||
|
[[ -e "$existing" ]] || continue
|
||||||
|
read -r n v < <(pkg_meta "$existing")
|
||||||
|
[[ -n "${n:-}" ]] || continue
|
||||||
|
if [[ -n "${built_ver[$n]:-}" ]]; then
|
||||||
|
echo "[customize] Replacing localrepo ${n} ${v} with built ${built_ver[$n]}"
|
||||||
|
rm -f "$existing"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ((${#built_file[@]} > 0)); then
|
||||||
|
echo "[customize] Harvesting ${#built_file[@]} package(s) into /opt/localrepo"
|
||||||
|
cp -f -- "${built_file[@]}" /opt/localrepo/
|
||||||
|
# makepkg -Afsi leaves its archives next to the PKGBUILD. They are already
|
||||||
|
# harvested (and installed in this image); keeping them in the dots tree
|
||||||
|
# would ship a second copy inside /opt/dots-hyprland, which alvin-install
|
||||||
|
# copies to ~/.dots-hyprland on every installed system.
|
||||||
|
find "${DOTS_REPO}" -type f -name '*.pkg.tar.zst' -delete
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rebuild the repo database (CI/update.sh ship a pre-built one alongside the
|
||||||
|
# packages) and refresh the live system's copy of it. No network needed: the
|
||||||
|
# remote repos were synced during pacstrap.
|
||||||
|
local_pkgs=(/opt/localrepo/*.pkg.tar.zst)
|
||||||
|
if ((${#local_pkgs[@]} > 0)); then
|
||||||
|
echo "[customize] Rebuilding local-aur db (${#local_pkgs[@]} packages)..."
|
||||||
|
repo-add -R /opt/localrepo/local-aur.db.tar.gz "${local_pkgs[@]}"
|
||||||
|
mkdir -p /var/lib/pacman/sync
|
||||||
|
cp -fL /opt/localrepo/local-aur.db /var/lib/pacman/sync/local-aur.db
|
||||||
|
if [[ -f /opt/localrepo/local-aur.files ]]; then
|
||||||
|
cp -fL /opt/localrepo/local-aur.files /var/lib/pacman/sync/local-aur.files
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── makepkg leftovers + throwaway account do not belong in the ISO ──────────
|
||||||
|
if [[ -d "${DOTS_REPO}/sdata/dist-arch" ]]; then
|
||||||
|
find "${DOTS_REPO}/sdata/dist-arch" -mindepth 2 -maxdepth 2 -type d \
|
||||||
|
\( -name src -o -name pkg \) -prune -exec rm -rf {} +
|
||||||
|
fi
|
||||||
|
rm -f /etc/sudoers.d/99-ii-builder
|
||||||
|
|
||||||
|
# Processes still running as BUILD_USER make userdel exit 8 and abort the
|
||||||
|
# build. end-4's ./setup is the usual source: sudo_init_keepalive forks
|
||||||
|
# `(sleep 60; sudo true) &` and its EXIT trap kills only the subshell,
|
||||||
|
# orphaning the sleep child for up to a minute. Mirrors shadow's
|
||||||
|
# user_busy_processes(): match real/effective/saved uid AND require the
|
||||||
|
# process to live inside this build chroot - the runner shares our PID
|
||||||
|
# namespace, and a host process could carry the same uid.
|
||||||
|
#
|
||||||
|
# mkarchiso runs this script via arch-chroot, which mounts proc *before*
|
||||||
|
# `unshare --fork --pid`: /proc entry numbers belong to the outer pid
|
||||||
|
# namespace, while kill(2) resolves pids in our (nested) namespace. Use the
|
||||||
|
# last NSpid field - the pid in our own namespace - for signalling; keep the
|
||||||
|
# /proc entry number for logging, since that is what userdel reports.
|
||||||
|
nspid_fields() {
|
||||||
|
awk -F'\t' '/^NSpid:/{ $1=""; sub(/^ +/, ""); print; exit }' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
builder_procs() {
|
||||||
|
local uid broot st p key real eff saved kpid cmd
|
||||||
|
local -a nsf self_nsf=()
|
||||||
|
uid=$(id -u "${BUILD_USER}") || return 0
|
||||||
|
broot=$(stat -Lc '%d:%i' /)
|
||||||
|
read -r -a self_nsf < <(nspid_fields /proc/self/status)
|
||||||
|
for st in /proc/[0-9]*/status; do
|
||||||
|
[[ -r "$st" ]] || continue
|
||||||
|
real=""; eff=""; saved=""
|
||||||
|
while read -r key real eff saved _; do
|
||||||
|
[[ $key == "Uid:" ]] && break
|
||||||
|
done < "$st" || continue
|
||||||
|
[[ $real == "$uid" || $eff == "$uid" || $saved == "$uid" ]] || continue
|
||||||
|
p=${st#/proc/}; p=${p%/status}
|
||||||
|
# Stat of /proc/<pid>/root needs CAP_SYS_PTRACE (or same-uid): exactly
|
||||||
|
# what shadow's userdel uses, so a process we cannot see here is one
|
||||||
|
# userdel cannot flag either. Compare by device+inode; skip on failure.
|
||||||
|
[[ $(stat -Lc '%d:%i' "/proc/$p/root" 2>/dev/null) == "$broot" ]] || continue
|
||||||
|
# NSpid chain length must equal ours, i.e. the process must live in our
|
||||||
|
# pid namespace - only then is its last field killable from here.
|
||||||
|
nsf=()
|
||||||
|
read -r -a nsf < <(nspid_fields "/proc/$p/status") || continue
|
||||||
|
if ((${#nsf[@]} > 0 && ${#nsf[@]} == ${#self_nsf[@]})); then
|
||||||
|
kpid=${nsf[${#nsf[@]} - 1]}
|
||||||
|
else
|
||||||
|
kpid="-"
|
||||||
|
fi
|
||||||
|
cmd=$(tr '\0' ' ' < "/proc/$p/cmdline" 2>/dev/null)
|
||||||
|
printf '%s\t%s\t%s\n' "$p" "$kpid" "$cmd"
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sweep_builder_procs() {
|
||||||
|
local sig=$1 p kpid cmd kerr
|
||||||
|
local -a pids=()
|
||||||
|
while IFS=$'\t' read -r p kpid cmd; do
|
||||||
|
[[ -n $p ]] || continue
|
||||||
|
if [[ -z $kpid || $kpid == "-" ]]; then
|
||||||
|
echo "[customize] ${BUILD_USER} process outside our pid namespace (cannot signal): pid $p: $cmd"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "[customize] ${BUILD_USER} process ($sig): pid $p: $cmd"
|
||||||
|
pids+=("$kpid")
|
||||||
|
done < <(builder_procs)
|
||||||
|
if ((${#pids[@]} > 0)); then
|
||||||
|
# Surface signal failures (they used to be swallowed, hiding a
|
||||||
|
# pid-namespace mismatch as a silent no-op sweep).
|
||||||
|
if ! kerr=$(kill -"$sig" "${pids[@]}" 2>&1); then
|
||||||
|
[[ -n $kerr ]] && printf '[customize] kill -%s: %s\n' "$sig" "$kerr"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sweep_builder_procs TERM
|
||||||
|
sleep 2
|
||||||
|
sweep_builder_procs KILL
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
if ! userdel -r "${BUILD_USER}"; then
|
||||||
|
rm -rf "/home/${BUILD_USER:?}"
|
||||||
|
if ! userdel "${BUILD_USER}"; then
|
||||||
|
echo "[customize] FATAL: cannot remove user ${BUILD_USER}; leftover processes:" >&2
|
||||||
|
builder_procs >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
chown -R root:root "${DOTS_REPO}"
|
||||||
|
|
||||||
|
# ── Google Sans Flex into skel: install_google_sans_flex() early-returns once
|
||||||
|
# fc-list sees the font, so the install step needs no network ──────────────
|
||||||
|
FONT_DIR="${SKEL}/.local/share/fonts/illogical-impulse-google-sans-flex"
|
||||||
|
if [[ ! -f "${FONT_DIR}/.git/HEAD" ]]; then
|
||||||
|
echo "[customize] Pre-installing Google Sans Flex into skel..."
|
||||||
|
rm -rf "${FONT_DIR}"
|
||||||
|
git clone --depth=1 --recurse-submodules --shallow-submodules \
|
||||||
|
https://github.com/end-4/google-sans-flex "${FONT_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── uv into skel: CPython 3.12 + the end-4 requirements wheel cache ──────────
|
||||||
|
# install-python-packages() runs `uv venv -p 3.12` and `uv pip install -r ...`
|
||||||
|
# during setup. Arch has no python312 package (uv would download one) and the
|
||||||
|
# pinned requirements are ~250 MiB of wheels, so warm both into skel: the venv
|
||||||
|
# is then created and filled straight from the image.
|
||||||
|
if command -v uv &>/dev/null; then
|
||||||
|
echo "[customize] Pre-warming uv (CPython 3.12 + requirements cache)..."
|
||||||
|
warm_venv="/tmp/uv-warm-venv"
|
||||||
|
rm -rf "${warm_venv}"
|
||||||
|
UV_CACHE_DIR="${SKEL}/.cache/uv" \
|
||||||
|
UV_PYTHON_INSTALL_DIR="${SKEL}/.local/share/uv/python" \
|
||||||
|
uv venv -p 3.12 "${warm_venv}"
|
||||||
|
UV_CACHE_DIR="${SKEL}/.cache/uv" \
|
||||||
|
UV_PYTHON_INSTALL_DIR="${SKEL}/.local/share/uv/python" \
|
||||||
|
uv pip install --python "${warm_venv}/bin/python" \
|
||||||
|
-r "${DOTS_REPO}/sdata/uv/requirements.txt"
|
||||||
|
rm -rf "${warm_venv}"
|
||||||
|
else
|
||||||
|
echo "[customize] uv not found - skipping python/wheel pre-warm."
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Fish: ensure default shell is set for the live user ──────────────────────
|
# ── Fish: ensure default shell is set for the live user ──────────────────────
|
||||||
# The live user (usually 'archlinux' or 'root') gets fish as default shell
|
# The live user (usually 'archlinux' or 'root') gets fish as default shell
|
||||||
if command -v fish &>/dev/null; then
|
if command -v fish &>/dev/null; then
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
NAME="Alvin Arch Linux"
|
|
||||||
PRETTY_NAME="Arch Linux"
|
|
||||||
ID_LIKE=arch
|
|
||||||
ID=arch
|
|
||||||
BUILD_ID=rolling
|
|
||||||
ANSI_COLOR="38;2;23;147;209"
|
|
||||||
HOME_URL="https://archlinux.org/"
|
|
||||||
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
|
||||||
SUPPORT_URL="https://bbs.archlinux.org/"
|
|
||||||
BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues"
|
|
||||||
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
|
|
||||||
LOGO=archlinux-logo
|
|
||||||
Executable
+1699
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
882DCFE48E2051D48E2562ABF3B607488DB35A47:4:
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
|
|
||||||
mQGNBGERxNwBDAD1aEVN8rdWBlV2sOwkiW1ddO44xKjdumwuGhoXP1pUzK4SkNUb
|
|
||||||
IrQ1cenckdxzZsS8cbXTvEteC4K8tTYxobZpgzAPhKZNECsyCyDf2DEYv7bS75gy
|
|
||||||
sdl0bh+mOXPjvOe9IK3eFPQWWFd0erYyf9SHjlZ0utOg3qZ2JuVupGOH8W3taKth
|
|
||||||
ijR98RzUqP5rPoMPKcrOdBUiIREHx0y6SwdyX0c2XKm52T3cP8O0MPsvZLbRwGU0
|
|
||||||
DTyr7knzuGhR9tLxsy4PqKz3tSUEGM7PhFcpEoRFvV/4Al8/OpRaPj3zRn6RbL1D
|
|
||||||
9ZAH9OblgHkQlK6MPnLOygoaAvjreMHK3ykjlRugUtnRBmQHhH+o3iXb8Ep5GXjZ
|
|
||||||
XJZazy5ZSTbuJ8+DcjuC/G459ePnQ658od2Sxz5OBRmK3a1taAtgszHio1EHb8Db
|
|
||||||
OZ+Za5E46VOHM/8sl8toGbK4JOqpgdQ3YqIH4R915WqCYnMvfTQbCiHLYzWHrgAA
|
|
||||||
awBu3kaV2MagPnkAEQEAAbQbQ2FjaHlPUyA8YWRtaW5AY2FjaHlvcy5vcmc+iQHO
|
|
||||||
BBMBCAA4AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEiC3P5I4gUdSOJWKr
|
|
||||||
87YHSI2zWkcFAmTUdqcACgkQ87YHSI2zWkc2ygwAknD+O2LQeHp1tEYwplF9Rthq
|
|
||||||
uPN64IxC/8nAc+L92fSOkVJKUfRh0PJcCCZgpTBAa7UV++GsT9SZ8jRtUPDfAy/R
|
|
||||||
0TSwKkEC6b1291xNdV3O83CtkSJRTP39nVCefXrBUpIwmkQJuytBF1qypTuw4jom
|
|
||||||
orcbmE40O7uNDe0FpZOJkUxT1sVJqj+y2h4mJsDuEAYKVQa4809yDwlQOYlLg6i3
|
|
||||||
wEBut7PPh8bEFWycNElKseh3dpQfvFVWMcUBafpQq7Q9zVFDW3nCUkFBMErcLb0y
|
|
||||||
VARQizrO3GqmWSU0zmgs8ruc3HnYjIfLIU68JRDsLdFgzIstEasnOskdUYywdvYw
|
|
||||||
BeGpCQX2ZFcTosLrZc1SRAk/XKioVXeHA92dcQacBClzKCmbat0CcNng5phu9fom
|
|
||||||
xGbNijvV5NWmQITw7j2sco0nLtfx2MiyRlR8s6pgrZ/VgfGq5K2gM306MgshgyMW
|
|
||||||
oIELm7aUTkbY+QH4v0y+U/KUNeHetDZhsMLwZq1DuQGNBGERxNwBDAC1RE2JFOjA
|
|
||||||
Mzqg3f5JsTa51WgApe2zlS/QjD+qr2LbC0CvQK3WO/MseqnEBfnXlUrL+tCzQXG7
|
|
||||||
9+kJk5xHsdaIbblTqdX3xNbT0/+sJkLsUWbfLh1lTgs+NnltsCtg1cIKm/eOBEWy
|
|
||||||
VfnrkKI+uTlQDDGcHW9XGaxLaIMi8FgaitMtrvH3AdajEpvpvdAAUbeIUL/hFs6V
|
|
||||||
TSs74xJRxy0J1eZYlZXo2YQ8EuZCAtyaQuvoDKijybxqj+FKPRiL920UI2emBYL0
|
|
||||||
cwMRq1XylZST7xXEzrEVgQ+xEUTBOUgmbRmIJVsSE/pDy7127dwPVpTglWiwfqnt
|
|
||||||
gdujrl6HM2b0a6lV5/ZoeYL5ucu6bku0ewbkoEKhqTe1JSVYWbStW5hwGFBxCFxG
|
|
||||||
pKQMMsDltmst8Z0Ic1Bhes00gd7LAC0AK8OkWFs4sIbHinNBVXQH/5MINF2ngm9t
|
|
||||||
P9kym17Nr5JterbxOOyNYl+ZOq6HFsrMXMZ1Cx+d4diqK2GnSeCZIvMAEQEAAYkB
|
|
||||||
vAQYAQgAJhYhBIgtz+SOIFHUjiViq/O2B0iNs1pHBQJhEcTcAhsMBQkDwmcAAAoJ
|
|
||||||
EPO2B0iNs1pHmFMMAOuyEJ93J4X5H+Jnf8/pXg2PFVvp0se7weCFha1d9umGSTrQ
|
|
||||||
Ejivm55z1X4R+Jt6D/cL3wN1WnayyNEtVzTD1CiuMDNO4a+qyBmE3/tJRWyIXoZ/
|
|
||||||
wdNu38rRNO/SdNbDWj0dCl6HCokLKSlfpP7996zymNeVX7yCw7T56jb2mTILTszy
|
|
||||||
E0xYPVAKb8cRZt9gUTivxQ3SPw5xVe1OXcF0Dkwx2EAAm7Alo6DMCZlqTii8Xc6K
|
|
||||||
YcaSRHNdlmkkW3RcTMkNja5mRFhzygklh9ViXqQs+9gZB+VHDqB2iNKbHJwO40aL
|
|
||||||
Ro/bta1h9P0HDD8q8mZWkZpGBlzul0x5UMedCeYudk9tOMwFCKRrhZeAyzMRn/+F
|
|
||||||
XUw7oFiWX6RX9ujq0O+Yna6WsWe+YN/vmT0KloTzRb0yqeDc37zc850+woYy+mNp
|
|
||||||
V2+Tq6hBDajk+BohvFyI7T4vvs45e+GwN2fTS6oqVsc9TfO7Q8JTi5y9UqByEbNC
|
|
||||||
bqY/IeIwaapRIqDYsg==
|
|
||||||
=bQDM
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
title Arch Linux install medium (%ARCH%, UEFI)
|
title Arch Linux install medium (%ARCH%, UEFI)
|
||||||
sort-key 01
|
sort-key 01
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
title Arch Linux install medium (%ARCH%, UEFI) with speech
|
title Arch Linux install medium (%ARCH%, UEFI) with speech
|
||||||
sort-key 02
|
sort-key 02
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
options archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
||||||
|
|||||||
+4
-4
@@ -46,14 +46,14 @@ timeout_style=menu
|
|||||||
|
|
||||||
menuentry "Arch Linux install medium (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
menuentry "Arch Linux install medium (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
}
|
}
|
||||||
|
|
||||||
menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -23,14 +23,14 @@ timeout_style=menu
|
|||||||
|
|
||||||
menuentry "Arch Linux install medium (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
menuentry "Arch Linux install medium (%ARCH%, ${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}"
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}"
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
}
|
}
|
||||||
|
|
||||||
menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, ${archiso_platform})" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' {
|
||||||
set gfxpayload=keep
|
set gfxpayload=keep
|
||||||
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}" accessibility=on
|
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}" accessibility=on
|
||||||
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -87,34 +87,36 @@ done
|
|||||||
info "═══ Step 2: Building AUR dependencies ═══"
|
info "═══ Step 2: Building AUR dependencies ═══"
|
||||||
|
|
||||||
# ── Theming & appearance ─────────────────────────────────────────────────────
|
# ── Theming & appearance ─────────────────────────────────────────────────────
|
||||||
|
# Entries in these lists must start at column 0: CI's package check accepts
|
||||||
|
# repo-less packages via `grep -qxF <pkg>` against this file (exact whole-line
|
||||||
|
# match), which silently never matched while the names were indented.
|
||||||
AUR_THEMING=(
|
AUR_THEMING=(
|
||||||
adw-gtk-theme-git
|
adw-gtk-theme-git
|
||||||
darkly-bin
|
darkly-bin
|
||||||
ttf-material-symbols-variable-git
|
ttf-material-symbols-variable-git
|
||||||
ttf-readex-pro
|
ttf-readex-pro
|
||||||
ttf-rubik-vf
|
ttf-rubik-vf
|
||||||
ttf-twemoji
|
ttf-twemoji
|
||||||
otf-space-grotesk
|
otf-space-grotesk
|
||||||
kde-material-you-colors-git
|
kde-material-you-colors-git
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── end-4 specific / build-from-source packages ──────────────────────────────
|
# ── end-4 specific / build-from-source packages ──────────────────────────────
|
||||||
# matugen — material you color generation tool
|
# matugen — material you color generation tool
|
||||||
# speech-dispatcher — may need AUR build on some setups
|
# speech-dispatcher — may need AUR build on some setups
|
||||||
AUR_TOOLS=(
|
AUR_TOOLS=(
|
||||||
matugen
|
matugen
|
||||||
python-rpypostprocess
|
python-rpypostprocess
|
||||||
tts
|
tts
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── Packages not in any standard repo ────────────────────────────────────────
|
# ── Packages not in any standard repo ────────────────────────────────────────
|
||||||
AUR_MISSING=(
|
AUR_MISSING=(
|
||||||
asciinema-agg
|
asciinema-agg
|
||||||
davs2
|
davs2
|
||||||
syncthingtray-qt6
|
varia
|
||||||
varia
|
woeusb-ng
|
||||||
woeusb-ng
|
ttf-ms-fonts
|
||||||
ttf-ms-fonts
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── Large / complex builds (skipped with --quick) ────────────────────────────
|
# ── Large / complex builds (skipped with --quick) ────────────────────────────
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -22,11 +22,26 @@ mapfile -t pkgs < <(find "${repo_dir}" -maxdepth 1 -name '*.pkg.tar.zst' -print
|
|||||||
|
|
||||||
if [[ ${#pkgs[@]} -eq 0 ]]; then
|
if [[ ${#pkgs[@]} -eq 0 ]]; then
|
||||||
echo "No .pkg.tar.zst files in ${repo_dir}" >&2
|
echo "No .pkg.tar.zst files in ${repo_dir}" >&2
|
||||||
|
# keep the medium's copy honest too - an emptied localrepo/ must not
|
||||||
|
# leave the previous packages shipping on the next build
|
||||||
|
rm -rf "${profile_dir}/airootfs/opt/localrepo"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
repo-add -R "${repo_dir}/${repo_name}.db.tar.gz" "${pkgs[@]}"
|
repo-add -R "${repo_dir}/${repo_name}.db.tar.gz" "${pkgs[@]}"
|
||||||
|
|
||||||
|
# Sync the medium's copy: the ISO ships its own [local-aur] at
|
||||||
|
# airootfs/opt/localrepo (pacman.conf on the live system points there, and
|
||||||
|
# pacstrap resolves these packages from it at install time).
|
||||||
|
img_repo="${profile_dir}/airootfs/opt/localrepo"
|
||||||
|
mkdir -p "${img_repo}"
|
||||||
|
rm -f "${img_repo}"/*.pkg.tar.zst "${img_repo}/${repo_name}".db \
|
||||||
|
"${img_repo}/${repo_name}".db.tar.gz "${img_repo}/${repo_name}".files \
|
||||||
|
"${img_repo}/${repo_name}".files.tar.gz
|
||||||
|
cp -f "${pkgs[@]}" "${img_repo}/"
|
||||||
|
cp -fL "${repo_dir}/${repo_name}".db* "${repo_dir}/${repo_name}".files* "${img_repo}/"
|
||||||
|
echo "Medium copy ready: ${img_repo}"
|
||||||
|
|
||||||
new_names=()
|
new_names=()
|
||||||
for p in "${pkgs[@]}"; do
|
for p in "${pkgs[@]}"; do
|
||||||
name=$(tar -xOf "${p}" .PKGINFO | sed -n 's/^pkgname = //p' | head -1)
|
name=$(tar -xOf "${p}" .PKGINFO | sed -n 's/^pkgname = //p' | head -1)
|
||||||
|
|||||||
+3
-3
@@ -46,6 +46,7 @@ cpio
|
|||||||
cronie
|
cronie
|
||||||
cryptsetup
|
cryptsetup
|
||||||
cups
|
cups
|
||||||
|
curl
|
||||||
darkhttpd
|
darkhttpd
|
||||||
davs2
|
davs2
|
||||||
dconf-editor
|
dconf-editor
|
||||||
@@ -176,7 +177,6 @@ libfprint
|
|||||||
libisoburn
|
libisoburn
|
||||||
libtorrent
|
libtorrent
|
||||||
libusb-compat
|
libusb-compat
|
||||||
linux
|
|
||||||
linux-atm
|
linux-atm
|
||||||
linux-cachyos
|
linux-cachyos
|
||||||
linux-cachyos-headers
|
linux-cachyos-headers
|
||||||
@@ -220,6 +220,7 @@ neofetch
|
|||||||
neovim
|
neovim
|
||||||
net-tools
|
net-tools
|
||||||
network-manager-applet
|
network-manager-applet
|
||||||
|
networkmanager
|
||||||
nfs-utils
|
nfs-utils
|
||||||
nikto
|
nikto
|
||||||
nilfs-utils
|
nilfs-utils
|
||||||
@@ -321,7 +322,7 @@ starship
|
|||||||
sudo
|
sudo
|
||||||
swaync
|
swaync
|
||||||
syncthing
|
syncthing
|
||||||
syncthingtray-qt6
|
syncthingtray
|
||||||
syntax-highlighting
|
syntax-highlighting
|
||||||
syslinux
|
syslinux
|
||||||
systemd-resolvconf
|
systemd-resolvconf
|
||||||
@@ -396,7 +397,6 @@ yay
|
|||||||
ydotool
|
ydotool
|
||||||
yt-dlp
|
yt-dlp
|
||||||
zen-browser-bin
|
zen-browser-bin
|
||||||
yq
|
|
||||||
zram-generator
|
zram-generator
|
||||||
zsh
|
zsh
|
||||||
zsh-completions
|
zsh-completions
|
||||||
|
|||||||
+1
-1
@@ -103,7 +103,7 @@ Include = /etc/pacman.d/chaotic-mirrorlist
|
|||||||
|
|
||||||
[local-aur]
|
[local-aur]
|
||||||
SigLevel = Optional TrustAll
|
SigLevel = Optional TrustAll
|
||||||
Server = file:///home/alvin/alvinarch/localrepo
|
Server = file:///home/alvin/AlvinArch/localrepo
|
||||||
|
|
||||||
# An example of a custom package repository. See the pacman manpage for
|
# An example of a custom package repository. See the pacman manpage for
|
||||||
# tips on creating your own repositories.
|
# tips on creating your own repositories.
|
||||||
|
|||||||
+32
-2
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
|
|
||||||
iso_name="archlinux"
|
iso_name="Alvin archlinux"
|
||||||
iso_label="AlvinArch_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)"
|
iso_label="AlvinArch_$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y%m)"
|
||||||
iso_publisher="Arch Linux <https://archlinux.org>"
|
iso_publisher="Arch Linux <https://archlinux.org>"
|
||||||
iso_application="Arch Linux Live ISO"
|
iso_application="Alvin Arch Linux Live ISO"
|
||||||
iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)"
|
iso_version="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y.%m.%d)"
|
||||||
install_dir="arch"
|
install_dir="arch"
|
||||||
buildmodes=('iso')
|
buildmodes=('iso')
|
||||||
@@ -20,6 +20,36 @@ file_permissions=(
|
|||||||
["/root/.automated_script.sh"]="0:0:755"
|
["/root/.automated_script.sh"]="0:0:755"
|
||||||
["/root/.gnupg"]="0:0:700"
|
["/root/.gnupg"]="0:0:700"
|
||||||
["/usr/local/bin/choose-mirror"]="0:0:755"
|
["/usr/local/bin/choose-mirror"]="0:0:755"
|
||||||
|
["/usr/local/bin/alvin-install"]="0:0:755"
|
||||||
["/usr/local/bin/Installation_guide"]="0:0:755"
|
["/usr/local/bin/Installation_guide"]="0:0:755"
|
||||||
["/usr/local/bin/livecd-sound"]="0:0:755"
|
["/usr/local/bin/livecd-sound"]="0:0:755"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ── Build stamp (staged file, never committed) ────────────────────────────────
|
||||||
|
# airootfs/root/.iso-build-stamp lands at /root/.iso-build-stamp on the ISO;
|
||||||
|
# customize_airootfs.sh installs it as /etc/alvin-build-stamp, and alvin-install
|
||||||
|
# appends it to the installed system's /etc/motd. Only stamp builds from a git
|
||||||
|
# checkout or CI — a random source-tarball build would record a bogus commit.
|
||||||
|
# Sourced by mkarchiso under `set -eu`, hence every expansion is defaulted.
|
||||||
|
_stamp_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
_stamp_file="${_stamp_dir}/airootfs/root/.iso-build-stamp"
|
||||||
|
rm -f "${_stamp_file}"
|
||||||
|
if [[ -e "${_stamp_dir}/.git" || -n "${CI:-}" || -n "${GITEA_ACTIONS:-}" ]]; then
|
||||||
|
_stamp_build="$(date --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y-%m-%d)"
|
||||||
|
# git ≥2.46 honours -c safe.directory even when mkarchiso runs as root
|
||||||
|
# over a user-owned checkout; older gits ignore it (protected-config
|
||||||
|
# scope) and fall through to the "unknown" line below instead of failing
|
||||||
|
# the build (`|| true` keeps set -e happy either way).
|
||||||
|
_stamp_commit="$(git -C "${_stamp_dir}" -c safe.directory="${_stamp_dir}" \
|
||||||
|
log -1 --format='%cs|%h' 2>/dev/null || true)"
|
||||||
|
if [[ -n "${_stamp_commit}" && "${_stamp_commit}" == *"|"* ]]; then
|
||||||
|
_stamp_hash="${_stamp_commit##*|}"
|
||||||
|
printf 'AlvinArch build %s | commit %s | %s\n' \
|
||||||
|
"${_stamp_build}" "${_stamp_commit%%|*}" "${_stamp_hash:0:4}" \
|
||||||
|
> "${_stamp_file}"
|
||||||
|
else
|
||||||
|
printf 'AlvinArch build %s | commit unknown\n' \
|
||||||
|
"${_stamp_build}" > "${_stamp_file}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
unset _stamp_dir _stamp_file _stamp_build _stamp_commit _stamp_hash
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ Boot the Arch Linux install medium using NBD.
|
|||||||
It allows you to install Arch Linux or perform system maintenance.
|
It allows you to install Arch Linux or perform system maintenance.
|
||||||
ENDTEXT
|
ENDTEXT
|
||||||
MENU LABEL Arch Linux install medium (%ARCH%, NBD)
|
MENU LABEL Arch Linux install medium (%ARCH%, NBD)
|
||||||
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% archiso_nbd_srv=${pxeserver} cms_verify=y
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% archiso_nbd_srv=${pxeserver} cms_verify=y
|
||||||
SYSAPPEND 3
|
SYSAPPEND 3
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@ Boot the Arch Linux live medium using NFS.
|
|||||||
It allows you to install Arch Linux or perform system maintenance.
|
It allows you to install Arch Linux or perform system maintenance.
|
||||||
ENDTEXT
|
ENDTEXT
|
||||||
MENU LABEL Arch Linux install medium (%ARCH%, NFS)
|
MENU LABEL Arch Linux install medium (%ARCH%, NFS)
|
||||||
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt cms_verify=y
|
APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt cms_verify=y
|
||||||
SYSAPPEND 3
|
SYSAPPEND 3
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ Boot the Arch Linux live medium using HTTP.
|
|||||||
It allows you to install Arch Linux or perform system maintenance.
|
It allows you to install Arch Linux or perform system maintenance.
|
||||||
ENDTEXT
|
ENDTEXT
|
||||||
MENU LABEL Arch Linux install medium (%ARCH%, HTTP)
|
MENU LABEL Arch Linux install medium (%ARCH%, HTTP)
|
||||||
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
INITRD ::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ cms_verify=y
|
APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ cms_verify=y
|
||||||
SYSAPPEND 3
|
SYSAPPEND 3
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ Boot the Arch Linux install medium on BIOS.
|
|||||||
It allows you to install Arch Linux or perform system maintenance.
|
It allows you to install Arch Linux or perform system maintenance.
|
||||||
ENDTEXT
|
ENDTEXT
|
||||||
MENU LABEL Arch Linux install medium (%ARCH%, BIOS)
|
MENU LABEL Arch Linux install medium (%ARCH%, BIOS)
|
||||||
LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID%
|
||||||
|
|
||||||
# Accessibility boot option
|
# Accessibility boot option
|
||||||
@@ -15,6 +15,6 @@ Boot the Arch Linux install medium on BIOS with speakup screen reader.
|
|||||||
It allows you to install Arch Linux or perform system maintenance with speech feedback.
|
It allows you to install Arch Linux or perform system maintenance with speech feedback.
|
||||||
ENDTEXT
|
ENDTEXT
|
||||||
MENU LABEL Arch Linux install medium (%ARCH%, BIOS) with ^speech
|
MENU LABEL Arch Linux install medium (%ARCH%, BIOS) with ^speech
|
||||||
LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
|
LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux-cachyos
|
||||||
INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
|
INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux-cachyos.img
|
||||||
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
APPEND archisobasedir=%INSTALL_DIR% archisosearchuuid=%ARCHISO_UUID% accessibility=on
|
||||||
|
|||||||
Reference in New Issue
Block a user