Skip to content

Instantly share code, notes, and snippets.

@FalconNL93
Last active January 22, 2026 13:33
Show Gist options
  • Select an option

  • Save FalconNL93/fd54cc7f553902743d99d03c744ce5ec to your computer and use it in GitHub Desktop.

Select an option

Save FalconNL93/fd54cc7f553902743d99d03c744ce5ec to your computer and use it in GitHub Desktop.
fedora-setup
fd54cc7f553902743d99d03c744ce5ec
# Flatpak applications to install system-wide
# One application ID per line.
# Browser
io.gitlab.librewolf-community
# Office / docs / mail
org.libreoffice.LibreOffice
org.kde.okular
org.mozilla.Thunderbird
org.gnome.Calculator
# Archives
io.github.peazip.PeaZip
# Media
org.videolan.VLC
com.spotify.Client
# Password manager
com.bitwarden.desktop
# Flatpak permissions manager
com.github.tchx84.Flatseal
# GTK theme runtimes (light/dark sync)
org.gtk.Gtk3theme.adw-gtk3
org.gtk.Gtk3theme.adw-gtk3-dark
# Flatpak remotes (system-wide)
# Format: name|url
flathub|https://flathub.org/repo/flathub.flatpakrepo
# Host-layer packages to install via rpm-ostree
# Keep this list low-churn (system tools, drivers, services)
# Core utilities / diagnostics
wireguard-tools
rsync
tmux
htop
pciutils
usbutils
lm_sensors
glibc-langpack-nl
glibc-langpack-en
NetworkManager-wireguard
# Requested basics
git
openssl
unzip
zip
lsof
# NVIDIA + CUDA runtime (RPM Fusion)
akmod-nvidia
xorg-x11-drv-nvidia
xorg-x11-drv-nvidia-cuda
# Vulkan
vulkan
vulkan-tools
# Networking
nmap
bind-utils
# Virtualization
libvirt
virt-install
virt-viewer
#!/usr/bin/env bash
set -euo pipefail
# Runs after post-reboot steps (as root).
# Put your personalization here (clone repos, toolbox setup, etc).
exit 0
#!/usr/bin/env bash
set -euo pipefail
# Timezone + NTP
sudo timedatectl set-timezone Europe/Amsterdam
sudo timedatectl set-ntp true
# System language: English
sudo localectl set-locale LANG=en_US.UTF-8
# Time/date formatting: Dutch (fixes 14.08 -> 14:08)
sudo localectl set-locale LC_TIME=nl_NL.UTF-8
sudo groupadd -f printeradmins
sudo tee /etc/polkit-1/rules.d/50-printeradmins.rules >/dev/null <<'EOF'
polkit.addRule(function(action, subject) {
if (
subject.isInGroup("printeradmins") &&
(
action.id == "org.opensuse.cupspkhelper.mechanism.all-edit" ||
action.id == "org.opensuse.cupspkhelper.mechanism.printer-add" ||
action.id == "org.opensuse.cupspkhelper.mechanism.printer-remove" ||
action.id == "org.opensuse.cupspkhelper.mechanism.printer-modify"
)
) {
return polkit.Result.YES;
}
});
EOF
exit 0
# Repository release RPMs (installed via rpm-ostree)
# Token supported: {{FEDORA}} -> rpm -E %fedora
https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-{{FEDORA}}.noarch.rpm
https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-{{FEDORA}}.noarch.rpm
#!/usr/bin/env bash
set -euo pipefail
# Unattended Fedora Atomic (Kinoite/Silverblue) setup:
# - Updates base OS to latest (rpm-ostree upgrade)
# - Installs repo RPMs from repositories.txt (rpm-ostree)
# - Layers host packages from ostree-packages.txt (rpm-ostree)
# - Adds Flatpak remotes from flatpak-remotes.txt (system-wide)
# - Prefers Flathub (priority + install-from-flathub-first) to avoid prompts
# - Installs Flatpaks from flatpak-packages.txt (system-wide), unattended
# - Configures Flatpak theming (GTK config RO) for light/dark sync
# - If NVIDIA is in ostree-packages.txt, applies kargs (nouveau blacklist + nvidia-drm modeset)
# - Creates a one-shot systemd service to run post-reboot steps automatically
# - Reboots automatically if rpm-ostree staged changes
# - Supports optional hook scripts:
# pre-install.sh (runs once before any installs; as root)
# post-install.sh (runs once after post-reboot steps; as root)
# - Sets LibreWolf as default browser system-wide (and best-effort for primary user) if installed
# - Sets PeaZip as default archive manager system-wide if installed
#
# Files expected next to this script (all optional):
# - repositories.txt
# - ostree-packages.txt
# - flatpak-remotes.txt
# - flatpak-packages.txt
# - pre-install.sh
# - post-install.sh
#
# List file format:
# - One entry per line
# - Blank lines ok
# - Comments supported with leading '#'
#
# repositories.txt tokens:
# - {{FEDORA}} is replaced with `rpm -E %fedora`
log() { printf "\n==> %s\n" "$*"; }
warn() { printf "\nWARNING: %s\n" "$*" >&2; }
die() { printf "\nERROR: %s\n" "$*" >&2; exit 1; }
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
}
script_dir() {
cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1
pwd
}
read_list_file_if_exists() {
local file_path="$1"
local -n out_arr="$2"
out_arr=()
[[ -f "$file_path" ]] || return 0
while IFS= read -r line || [[ -n "$line" ]]; do
line="${line#"${line%%[![:space:]]*}"}"
line="${line%"${line##*[![:space:]]}"}"
[[ -z "$line" ]] && continue
[[ "$line" == \#* ]] && continue
out_arr+=("$line")
done < "$file_path"
}
apply_repo_tokens() {
local -n arr="$1"
local fedora_ver
fedora_ver="$(rpm -E %fedora)"
local i
for i in "${!arr[@]}"; do
arr[$i]="${arr[$i]//\{\{FEDORA\}\}/$fedora_ver}"
done
}
is_secure_boot_enabled() {
if command -v mokutil >/dev/null 2>&1; then
mokutil --sb-state 2>/dev/null | grep -qi "enabled"
return $?
fi
return 1
}
flatpak_remote_exists() {
local name="$1"
flatpak remotes --system --columns=name 2>/dev/null | awk '{print $1}' | grep -qx "$name"
}
flatpak_app_installed() {
local app_id="$1"
flatpak list --system --app --columns=application 2>/dev/null | awk '{print $1}' | grep -qx "$app_id"
}
ostree_has_pending() {
rpm-ostree status --json 2>/dev/null | grep -q '"pending":true'
}
kargs_contains() {
local needle="$1"
rpm-ostree kargs 2>/dev/null | tr ' ' '\n' | grep -qx -- "$needle"
}
append_karg_if_missing() {
local arg="$1"
if kargs_contains "$arg"; then
log "Kernel arg already present: $arg"
return 0
fi
log "Appending kernel arg: $arg"
rpm-ostree kargs --append="$arg"
}
list_contains() {
local wanted="$1"; shift
local item
for item in "$@"; do
if [[ "$item" == "$wanted" ]]; then
return 0
fi
done
return 1
}
detect_primary_user() {
awk -F: '$3>=1000 && $1!="nobody" {print $1; exit}' /etc/passwd || true
}
run_hook_if_present() {
local hook_path="$1"
local hook_name="$2"
if [[ -f "$hook_path" ]]; then
if [[ ! -x "$hook_path" ]]; then
log "Making hook executable: $hook_name"
chmod +x "$hook_path" || die "Failed to chmod +x $hook_name"
fi
log "Running hook: $hook_name"
"$hook_path"
else
log "Hook not found (skipping): $hook_name"
fi
}
update_base_os() {
log "Updating base OS to latest (rpm-ostree upgrade)"
rpm-ostree upgrade
}
install_repositories() {
local -a repos=()
read_list_file_if_exists "$REPOS_FILE" repos
apply_repo_tokens repos
if [[ "${#repos[@]}" -eq 0 ]]; then
log "No repositories.txt (or empty). Skipping repo install."
return 0
fi
log "Installing repository release RPMs (rpm-ostree)"
printf " - %s\n" "${repos[@]}"
rpm-ostree install --idempotent --allow-inactive "${repos[@]}"
}
install_ostree_packages() {
local -a pkgs=()
read_list_file_if_exists "$PKGS_FILE" pkgs
if [[ "${#pkgs[@]}" -eq 0 ]]; then
log "No ostree-packages.txt (or empty). Skipping host package layering."
return 0
fi
log "Layering host packages (rpm-ostree)"
printf " - %s\n" "${pkgs[@]}"
rpm-ostree install --idempotent --allow-inactive "${pkgs[@]}"
OSTREE_PACKAGES=("${pkgs[@]}")
}
apply_nvidia_kargs_if_needed() {
if [[ "${#OSTREE_PACKAGES[@]}" -eq 0 ]]; then
return 0
fi
if ! list_contains "akmod-nvidia" "${OSTREE_PACKAGES[@]}"; then
log "akmod-nvidia not in ostree-packages.txt. Skipping NVIDIA kernel args."
return 0
fi
log "NVIDIA detected in package list; applying kernel args (nouveau blacklist + modeset)."
append_karg_if_missing "rd.driver.blacklist=nouveau,nova_core"
append_karg_if_missing "modprobe.blacklist=nouveau,nova_core"
append_karg_if_missing "nvidia-drm.modeset=1"
}
add_flatpak_remotes() {
local -a remotes=()
read_list_file_if_exists "$FLATPAK_REMOTES_FILE" remotes
if [[ "${#remotes[@]}" -eq 0 ]]; then
log "No flatpak-remotes.txt (or empty). Skipping Flatpak remotes."
return 0
fi
require_cmd flatpak
log "Ensuring Flatpak remotes exist (system-wide)"
local entry name url
for entry in "${remotes[@]}"; do
name="${entry%%|*}"
url="${entry#*|}"
if [[ -z "$name" || -z "$url" || "$name" == "$entry" ]]; then
die "Invalid remote entry: '$entry' (expected: name|url)"
fi
if flatpak_remote_exists "$name"; then
log "Flatpak remote already exists: $name"
continue
fi
log "Adding Flatpak remote: $name"
flatpak remote-add --system --if-not-exists "$name" "$url"
done
}
prefer_flathub() {
require_cmd flatpak
if flatpak_remote_exists "flathub"; then
log "Setting Flatpak remote priority: flathub preferred"
flatpak remote-modify --system --prio=1 flathub
else
warn "Flathub remote not found; cannot set priority."
fi
if flatpak_remote_exists "fedora"; then
flatpak remote-modify --system --prio=2 fedora || true
fi
}
install_flatpak_from_preferred_remote() {
local app="$1"
if [[ "$app" == */* ]]; then
flatpak install --system -y "$app"
return 0
fi
if flatpak_remote_exists "flathub"; then
if flatpak install --system -y flathub "$app" >/dev/null 2>&1; then
return 0
fi
fi
if flatpak_remote_exists "fedora"; then
if flatpak install --system -y fedora "$app" >/dev/null 2>&1; then
return 0
fi
fi
die "Failed to install Flatpak '$app' from flathub or fedora."
}
install_flatpak_packages() {
local -a apps=()
read_list_file_if_exists "$FLATPAK_PACKAGES_FILE" apps
if [[ "${#apps[@]}" -eq 0 ]]; then
log "No flatpak-packages.txt (or empty). Skipping Flatpak installs."
return 0
fi
require_cmd flatpak
log "Installing Flatpak apps system-wide (prefer flathub, fallback fedora)"
local app
for app in "${apps[@]}"; do
if flatpak_app_installed "$app"; then
log "Flatpak already installed: $app"
continue
fi
log "Installing Flatpak: $app"
install_flatpak_from_preferred_remote "$app"
done
}
configure_flatpak_theming() {
require_cmd flatpak
log "Configuring Flatpak theming (GTK config RO access)"
flatpak override --system \
--filesystem=xdg-config/gtkrc:ro \
--filesystem=xdg-config/gtkrc-2.0:ro \
--filesystem=xdg-config/gtk-3.0:ro \
--filesystem=xdg-config/gtk-4.0:ro \
--filesystem=xdg-data/icons:ro \
--filesystem=xdg-data/themes:ro
}
create_post_reboot_service() {
local unit_path="/etc/systemd/system/fedora-atomic-firstboot-setup.service"
local script_path
script_path="$(realpath "$0")"
log "Creating one-shot post-reboot service: fedora-atomic-firstboot-setup.service"
cat > "$unit_path" <<EOF
[Unit]
Description=Fedora Atomic first-boot setup (post-reboot steps)
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=${script_path} --post-reboot-internal
RemainAfterExit=no
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable fedora-atomic-firstboot-setup.service
}
ensure_mimeapps_default() {
local key="$1"
local value="$2"
local file="/etc/xdg/mimeapps.list"
mkdir -p /etc/xdg
if [[ ! -f "$file" ]]; then
cat > "$file" <<EOF
[Default Applications]
${key}=${value}
EOF
return 0
fi
if ! grep -q '^\[Default Applications\]$' "$file"; then
printf "\n[Default Applications]\n" >> "$file"
fi
sed -i -E "s|^${key}=.*$||g" "$file"
awk -v k="$key" -v v="$value" '
BEGIN { added=0 }
/^\[Default Applications\]$/ {
print
if (!added) { print k "=" v; added=1 }
next
}
{ print }
END {
if (!added) {
print "[Default Applications]"
print k "=" v
}
}
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
}
set_librewolf_system_default_browser() {
local desktop_id="io.gitlab.librewolf-community.desktop"
log "Setting LibreWolf as system-wide default browser via /etc/xdg/mimeapps.list"
ensure_mimeapps_default "x-scheme-handler/http" "$desktop_id"
ensure_mimeapps_default "x-scheme-handler/https" "$desktop_id"
ensure_mimeapps_default "text/html" "$desktop_id"
}
set_peazip_system_default_archives() {
# NOTE: Desktop ID may vary by Flatpak packaging. This is the common one.
# If it doesn't work for you, run:
# flatpak info --show-metadata io.github.peazip.PeaZip | grep -i desktop
local desktop_id="io.github.peazip.PeaZip.desktop"
log "Setting PeaZip as system-wide default archive manager via /etc/xdg/mimeapps.list"
ensure_mimeapps_default "application/zip" "$desktop_id"
ensure_mimeapps_default "application/x-zip-compressed" "$desktop_id"
ensure_mimeapps_default "application/x-7z-compressed" "$desktop_id"
ensure_mimeapps_default "application/x-rar" "$desktop_id"
ensure_mimeapps_default "application/vnd.rar" "$desktop_id"
ensure_mimeapps_default "application/x-rar-compressed" "$desktop_id"
ensure_mimeapps_default "application/x-tar" "$desktop_id"
ensure_mimeapps_default "application/gzip" "$desktop_id"
ensure_mimeapps_default "application/x-gzip" "$desktop_id"
ensure_mimeapps_default "application/x-bzip2" "$desktop_id"
ensure_mimeapps_default "application/x-xz" "$desktop_id"
ensure_mimeapps_default "application/x-gtar" "$desktop_id"
ensure_mimeapps_default "application/x-compressed-tar" "$desktop_id"
}
set_librewolf_default_browser_for_user() {
local user="$1"
local desktop_id="io.gitlab.librewolf-community.desktop"
if [[ -z "$user" ]]; then
warn "No primary user detected; skipping per-user default browser configuration."
return 0
fi
log "Setting LibreWolf as default browser for user: $user"
runuser -l "$user" -c "command -v xdg-settings >/dev/null 2>&1 && xdg-settings set default-web-browser '$desktop_id' || true"
runuser -l "$user" -c "command -v xdg-mime >/dev/null 2>&1 && xdg-mime default '$desktop_id' x-scheme-handler/http x-scheme-handler/https text/html || true"
}
post_reboot_internal() {
require_cmd systemctl
log "Post-reboot: enabling services (non-fatal if already enabled)"
if systemctl list-unit-files | grep -q '^libvirtd\.service'; then
systemctl enable --now libvirtd || true
else
warn "libvirtd.service not found. If libvirt wasn't layered, that's expected."
fi
log "Post-reboot: optional libvirt group assignment"
local primary_user
primary_user="$(detect_primary_user)"
if getent group libvirt >/dev/null 2>&1; then
if [[ -n "$primary_user" ]]; then
usermod -aG libvirt "$primary_user" || true
log "Added user '$primary_user' to libvirt group. Log out/in to apply group changes."
else
warn "Could not determine a primary user to add to libvirt group."
fi
else
warn "Group 'libvirt' not found (may vary). Skipping."
fi
if command -v flatpak >/dev/null 2>&1; then
if flatpak list --system --app --columns=application 2>/dev/null | awk '{print $1}' | grep -qx "io.gitlab.librewolf-community"; then
set_librewolf_system_default_browser
set_librewolf_default_browser_for_user "$primary_user"
else
log "LibreWolf Flatpak not installed; skipping default browser configuration."
fi
if flatpak list --system --app --columns=application 2>/dev/null | awk '{print $1}' | grep -qx "io.github.peazip.PeaZip"; then
set_peazip_system_default_archives
else
log "PeaZip Flatpak not installed; skipping default archive manager configuration."
fi
fi
run_hook_if_present "$POST_HOOK" "post-install.sh"
log "Disabling one-shot service so it won't run again"
systemctl disable fedora-atomic-firstboot-setup.service || true
rm -f /etc/systemd/system/fedora-atomic-firstboot-setup.service || true
systemctl daemon-reload
log "Post-reboot steps complete."
}
main() {
require_cmd rpm-ostree
require_cmd rpm
if [[ $EUID -ne 0 ]]; then
die "Run as root (use: sudo $0)"
fi
local dir
dir="$(script_dir)"
REPOS_FILE="${dir}/repositories.txt"
PKGS_FILE="${dir}/ostree-packages.txt"
FLATPAK_REMOTES_FILE="${dir}/flatpak-remotes.txt"
FLATPAK_PACKAGES_FILE="${dir}/flatpak-packages.txt"
PRE_HOOK="${dir}/pre-install.sh"
POST_HOOK="${dir}/post-install.sh"
OSTREE_PACKAGES=()
log "Unattended setup starting (Fedora Atomic)"
log "Using files (if present):"
log " ${REPOS_FILE}"
log " ${PKGS_FILE}"
log " ${FLATPAK_REMOTES_FILE}"
log " ${FLATPAK_PACKAGES_FILE}"
log "Hooks (if present):"
log " ${PRE_HOOK}"
log " ${POST_HOOK}"
log "Checking Secure Boot"
if is_secure_boot_enabled; then
warn "Secure Boot appears ENABLED. NVIDIA modules may not load unless you sign them (MOK) or disable Secure Boot in BIOS."
else
log "Secure Boot not detected as enabled (or mokutil not installed)."
fi
run_hook_if_present "$PRE_HOOK" "pre-install.sh"
update_base_os
install_repositories
install_ostree_packages
apply_nvidia_kargs_if_needed
add_flatpak_remotes
prefer_flathub
install_flatpak_packages
configure_flatpak_theming
if ostree_has_pending; then
log "rpm-ostree staged a pending deployment -> reboot is required."
create_post_reboot_service
log "Rebooting automatically in 5 seconds..."
sleep 5
systemctl reboot
else
log "No pending rpm-ostree deployment detected. No reboot required."
log "Running post-install hook now (since no reboot is happening)."
run_hook_if_present "$POST_HOOK" "post-install.sh"
log "Setup complete."
fi
}
if [[ "${1:-}" == "--post-reboot-internal" ]]; then
post_reboot_internal
else
main
fi
#!/usr/bin/env bash
set -euo pipefail
die() { echo "ERROR: $*" >&2; exit 1; }
log() { printf "\n==> %s\n" "$*"; }
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
}
script_basename="$(basename "$0")"
gist_ref_file=".gist"
SELF_UPDATE="false"
while [[ $# -gt 0 ]]; do
case "$1" in
--self)
SELF_UPDATE="true"
shift
;;
-h|--help)
cat <<'EOF'
Usage:
./update.sh [--self]
Behavior:
- Downloads all files from the gist referenced by .gist into the current directory.
- Prefers GitHub CLI (gh) if available/authenticated (avoids API rate limits).
- If gh is missing, installs the official gh binary to ~/.local/bin (no sudo).
- Falls back to curl + GitHub API if gh isn't authenticated.
- By default, does NOT overwrite update.sh itself; use --self to allow.
Notes:
- Public/unlisted gists work without auth.
- If you hit rate limits in fallback mode, authenticate gh: `gh auth login`
EOF
exit 0
;;
*)
die "Unknown argument: $1"
;;
esac
done
require_cmd curl
require_cmd python3
require_cmd grep
require_cmd head
require_cmd tr
require_cmd tar
require_cmd uname
require_cmd mktemp
install_gh_if_missing() {
if command -v gh >/dev/null 2>&1; then
return 0
fi
log "gh not found. Installing GitHub CLI (official binary) to ~/.local/bin"
mkdir -p "$HOME/.local/bin"
export PATH="$HOME/.local/bin:$PATH"
arch="$(uname -m)"
case "$arch" in
x86_64|amd64) gh_arch="amd64" ;;
aarch64|arm64) gh_arch="arm64" ;;
*) die "Unsupported architecture for gh binary install: $arch" ;;
esac
# Get latest release tag (e.g., v2.XX.X)
latest_tag="$(
curl -fsSL -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/cli/cli/releases/latest" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])'
)" || die "Failed to query latest gh release"
ver="${latest_tag#v}"
asset="gh_${ver}_linux_${gh_arch}.tar.gz"
url="https://github.com/cli/cli/releases/download/${latest_tag}/${asset}"
tmpdir="$(mktemp -d)"
cleanup_install() { rm -rf "$tmpdir"; }
trap cleanup_install EXIT
log "Downloading: $asset"
curl -fsSL "$url" -o "$tmpdir/$asset" || die "Failed to download gh asset: $url"
tar -xzf "$tmpdir/$asset" -C "$tmpdir" || die "Failed to extract gh tarball"
src="$tmpdir/gh_${ver}_linux_${gh_arch}/bin/gh"
[[ -f "$src" ]] || die "gh binary not found after extraction"
install -m 0755 "$src" "$HOME/.local/bin/gh" || die "Failed to install gh to ~/.local/bin/gh"
log "Installed gh: $HOME/.local/bin/gh"
}
extract_gist_id() {
local ref="$1"
printf "%s" "$ref" | grep -Eo '[0-9a-fA-F]{20,40}' | head -n 1 || true
}
fetch_gist_json() {
local id="$1"
# Prefer gh (authenticated) if available
if command -v gh >/dev/null 2>&1; then
if gh auth status >/dev/null 2>&1; then
log "Using gh (authenticated) to fetch gist metadata"
gh api -H "Accept: application/vnd.github+json" "/gists/$id"
return 0
fi
log "gh found but not authenticated; falling back to curl"
else
log "gh not found; falling back to curl"
fi
# Fallback: unauthenticated GitHub API
curl -fsSL -H "Accept: application/vnd.github+json" "https://api.github.com/gists/$id"
}
download_one() {
local filename="$1"
local raw_url="$2"
# Self-update behavior
if [[ "$filename" == "$script_basename" && "$SELF_UPDATE" != "true" ]]; then
log "Skipping self: $filename (use --self to update it)"
return 0
fi
tmp="${filename}.tmp.$$"
log "Downloading: $filename"
curl -fsSL "$raw_url" -o "$tmp" || die "Failed downloading: $filename"
# If self-update, basic sanity check to avoid bricking the script
if [[ "$filename" == "$script_basename" ]]; then
head_line="$(head -n 1 "$tmp" || true)"
[[ "$head_line" == \#!* ]] || die "Self-update sanity check failed: $filename has no shebang"
fi
mv -f "$tmp" "$filename"
case "$filename" in
*.sh) chmod +x "$filename" 2>/dev/null || true ;;
esac
}
# Main
[[ -f "$gist_ref_file" ]] || die "No .gist file found in $(pwd)."
gist_ref="$(tr -d ' \t\r\n' < "$gist_ref_file")"
[[ -n "$gist_ref" ]] || die ".gist is empty"
gist_id="$(extract_gist_id "$gist_ref")"
[[ -n "$gist_id" ]] || die "Could not extract gist id from .gist value: $gist_ref"
log "Updating from gist: $gist_id"
if [[ "$SELF_UPDATE" == "true" ]]; then
log "Self-update: enabled (--self)"
else
log "Self-update: disabled (won't overwrite $script_basename)"
fi
# Try to ensure gh exists (no sudo). If install fails, we still can curl fallback.
if ! command -v gh >/dev/null 2>&1; then
install_gh_if_missing || log "gh install failed; continuing with curl fallback"
fi
json="$(fetch_gist_json "$gist_id")" || die "Failed to fetch gist metadata."
# Parse JSON -> "<filename>\t<raw_url>"
file_list="$(python3 - <<'PY'
import json, sys
data = json.loads(sys.stdin.read())
files = data.get("files", {})
for name, info in files.items():
raw = info.get("raw_url")
if raw:
print(f"{name}\t{raw}")
PY
<<<"$json")" || die "Failed to parse gist JSON (rate limit / invalid response?)"
[[ -n "$file_list" ]] || die "No files found in gist."
log "Downloading files into: $(pwd)"
count_total=0
count_written=0
count_skipped=0
while IFS=$'\t' read -r filename raw_url; do
[[ -n "${filename:-}" ]] || continue
[[ -n "${raw_url:-}" ]] || continue
count_total=$((count_total + 1))
if [[ "$filename" == "$script_basename" && "$SELF_UPDATE" != "true" ]]; then
count_skipped=$((count_skipped + 1))
download_one "$filename" "$raw_url" || true
continue
fi
download_one "$filename" "$raw_url"
count_written=$((count_written + 1))
done <<< "$file_list"
log "Done."
log "Files in gist: $count_total"
log "Written/updated: $count_written"
log "Skipped: $count_skipped"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment