From 0cd92555d24be88cb14187208b1a8606a758eb03 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Sat, 3 Oct 2026 11:13:04 +0200 Subject: [PATCH] refactor: Valve mirror module, golden menu test, local and CI checks Co-Authored-By: Claude Sonnet 5.5 --- .editorconfig | 15 +++++++++++ .github/workflows/bundle.yml | 2 +- .shellcheckrc | 2 ++ CHANGELOG.md | 6 +++++ Makefile | 24 ++++++++++++++++++ lib/bios.sh | 12 ++++----- lib/cec.sh | 20 ++------------- lib/login-manager.sh | 2 +- lib/steamos-extras.sh | 26 +++++-------------- lib/valve-mirror.sh | 49 ++++++++++++++++++++++++++++++++++++ steamify.sh | 2 +- 11 files changed, 113 insertions(+), 47 deletions(-) create mode 100644 .editorconfig create mode 100644 .shellcheckrc create mode 100644 Makefile create mode 100644 lib/valve-mirror.sh diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..90a3af8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{yml,yaml,qml}] +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/.github/workflows/bundle.yml b/.github/workflows/bundle.yml index 99a4132..276e679 100644 --- a/.github/workflows/bundle.yml +++ b/.github/workflows/bundle.yml @@ -40,7 +40,7 @@ jobs: - name: Check run: | bash -n dist/steamify.sh - python3 -m py_compile ui/steamify-ui + python3 -m py_compile ui/steamify-ui patches/*.py # shellcheck through an action that brings its own binary: GitHub's runner has it installed, # Gitea's act_runner image doesn't. One file per run, as before (the exceptions are the bundle's). diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..4f310dd --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +# The modules share variables across files once bundled (see AGENTS.md). +disable=SC2034,SC2154 diff --git a/CHANGELOG.md b/CHANGELOG.md index a821bcf..3a88835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes, per version and per commit. Versions follow `steamify.sh`. Versions before 0.7.0 were numbered afterwards, one per merged pull request. +## Unreleased + +- **refactor: Valve's package mirror in one module (`lib/valve-mirror.sh`: newest repo, package database fields, checksummed download); the SteamOS extras, CEC driver, BIOS lookup and os-release version used four copies** +- **test: the menu rules, the plan and the app's and installer's JSON are checked against a golden file (`tests/menu-test.sh` in steamify-cachyos-dev); `make check`, `.editorconfig`, `.shellcheckrc`** +- **docs: README lists the sources and projects Steamify builds on, with licences and thanks** + ## 2.11.1 - 2026-10-02 - `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion** diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1796693 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +# Local checks, the same as CI's: make check +SH := steamify.sh $(wildcard lib/*.sh) ui/steamify-app.sh .github/tools/bundle.sh +# The unit tests live in ../steamify-cachyos-dev/tests (REPO points at this checkout). +DEV ?= ../steamify-cachyos-dev +TESTS := $(wildcard $(DEV)/tests/*-test.sh) + +.PHONY: check syntax lint test bundle fmt-check +check: syntax lint test bundle + +syntax: + @for f in $(SH); do bash -n "$$f" || exit 1; done + python3 -m py_compile ui/steamify-ui patches/*.py + +lint: + @command -v shellcheck >/dev/null && shellcheck -S warning $(SH) || echo "shellcheck not installed: skipped" + +test: + @for t in $(TESTS); do echo "== $$t"; REPO="$(CURDIR)" bash "$$t" || exit 1; done + +bundle: + .github/tools/bundle.sh dist/steamify.sh + +fmt-check: + @command -v shfmt >/dev/null && shfmt -d -i 4 -ci $(SH) || echo "shfmt not installed: skipped" diff --git a/lib/bios.sh b/lib/bios.sh index ce91d84..e9090f3 100644 --- a/lib/bios.sh +++ b/lib/bios.sh @@ -30,16 +30,16 @@ bios_lookup_newest() { [[ -n "${BIOS_LOOKED_UP:-}" ]] && return 0 BIOS_LOOKED_UP=1; BIOS_NEWEST="" local tmp desc - BIOS_REPO="$(curl -fsL --max-time 10 "$VALVE_MIRROR/" | grep -oE "$BIOS_REPO_PREFIX-[0-9]+\.[0-9]+/" | tr -d / | sort -uV | tail -n 1)" + BIOS_REPO="$(valve_newest_repo "$BIOS_REPO_PREFIX" 10)" [[ -n "$BIOS_REPO" ]] || return 1 tmp="$(mktemp -d)" - if curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.files" -o "$tmp/files" && - curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.db" -o "$tmp/db"; then + if curl -fsL --max-time 30 "$(valve_repo_url "$BIOS_REPO")/$BIOS_REPO.files" -o "$tmp/files" && + curl -fsL --max-time 30 "$(valve_repo_url "$BIOS_REPO")/$BIOS_REPO.db" -o "$tmp/db"; then desc="$(tar -tf "$tmp/files" 2>/dev/null | grep -E '^fremont-hw-support-[0-9][^/]*/files$' | head -n 1)" [[ -n "$desc" ]] && BIOS_CAB="$(tar -xOf "$tmp/files" "$desc" | grep -E '^usr/share/fwupd/.*\.cab$' | head -n 1)" desc="${desc%/files}/desc" - BIOS_PKG="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%FILENAME%$/ { getline; print }')" - BIOS_SHA256="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%SHA256SUM%$/ { getline; print }')" + BIOS_PKG="$(valve_desc_field "$tmp/db" "$desc" FILENAME)" + BIOS_SHA256="$(valve_desc_field "$tmp/db" "$desc" SHA256SUM)" [[ -n "${BIOS_CAB:-}" && -n "$BIOS_PKG" && -n "$BIOS_SHA256" ]] && BIOS_NEWEST="$(basename "$BIOS_CAB" .cab)" fi rm -rf "$tmp" @@ -143,7 +143,7 @@ bios_prepare() { { err "Installing fwupd failed."; return 1; } rm -rf "$BIOS_STAGE_DIR"; mkdir -p "$BIOS_STAGE_DIR"; chmod 700 "$BIOS_STAGE_DIR" info "Downloading $BIOS_PKG ($BIOS_REPO)..." - if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$BIOS_STAGE_DIR/pkg.tar.zst" || + if ! curl -fsSL "$(valve_repo_url "$BIOS_REPO")/$BIOS_PKG" -o "$BIOS_STAGE_DIR/pkg.tar.zst" || ! echo "$BIOS_SHA256 $BIOS_STAGE_DIR/pkg.tar.zst" | sha256sum -c --quiet - || ! tar -I unzstd -xf "$BIOS_STAGE_DIR/pkg.tar.zst" -C "$BIOS_STAGE_DIR" "$BIOS_CAB"; then err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched." diff --git a/lib/cec.sh b/lib/cec.sh index 0171646..41ecd26 100644 --- a/lib/cec.sh +++ b/lib/cec.sh @@ -113,24 +113,8 @@ cec_repair() { cec_installed && ! cec_status; } fetch_holo_pkg() { # fetch_holo_pkg : download the newest from - # Valve's newest holo repository into and print its path. The - # SHA-256 comes from Valve's package index and is verified. - local dir="$1" name="$2" repo desc file_name sha256 - repo="$(curl -fsL "$VALVE_MIRROR/" | grep -oE 'holo-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)" - if [[ ! -f "$dir/holo.db" ]]; then - [[ -n "$repo" ]] && curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$repo.db" -o "$dir/holo.db" || - { err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; } - fi - desc="$(tar -tf "$dir/holo.db" 2>/dev/null | grep -E "^$name-[0-9][^/]*/desc$" | head -n 1)" - [[ -n "$desc" ]] || { err "No $name in Valve's $repo repository."; return 1; } - file_name="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%FILENAME%$/ { getline; print }')" - sha256="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%SHA256SUM%$/ { getline; print }')" - info "Downloading $file_name ($repo)..." >&2 - curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$file_name" -o "$dir/$file_name" || - { err "Downloading $file_name failed."; return 1; } - echo "$sha256 $dir/$file_name" | sha256sum -c --quiet - >&2 || - { err "Checksum mismatch for $file_name; not using it."; return 1; } - echo "$dir/$file_name" + # Valve's newest holo repository into and print its path. + valve_fetch_pkg holo "$2" "$1" } cec_enable() { diff --git a/lib/login-manager.sh b/lib/login-manager.sh index 7cef57f..6e8cc5b 100644 --- a/lib/login-manager.sh +++ b/lib/login-manager.sh @@ -35,7 +35,7 @@ steamos_release() { # capitals: steamos-3.9). Offline (e.g. in the installer): the one set # before, if any. local v - v="$(curl -fsL --max-time 15 "$VALVE_MIRROR/" 2>/dev/null | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)" + v="$(valve_newest_repo jupiter 15)" if [[ -n "$v" ]]; then echo "steamos-${v#jupiter-}" else sed -n 's/^VERSION_ID=\(steamos-.*\)$/\1/p' /etc/os-release 2>/dev/null; fi } diff --git a/lib/steamos-extras.sh b/lib/steamos-extras.sh index ca40c3e..c7bba9b 100644 --- a/lib/steamos-extras.sh +++ b/lib/steamos-extras.sh @@ -8,7 +8,6 @@ # package-owned); per-user settings go through the undo journal. # Sourced by steamify.sh; not meant to be run on its own. -VALVE_MIRROR="https://steamdeck-packages.steamos.cloud/archlinux-mirror" NESTED_DIR=/usr/local/share/applications/steam/holo-nested-desktop EXTRAS_FILES=( /usr/local/bin/holo-add-to-steam @@ -23,25 +22,12 @@ STEAM_KEYBOARD_RULE=cachyos-gamescope-boot-steam-keyboard fetch_valve_presets() { # fetch_valve_presets : download and extract the newest - # steamdeck-kde-presets into . The newest SteamOS release repo - # (jupiter-3.9, jupiter-3.10, ...) is found on the mirror; its pacman - # database gives the exact file name and SHA-256, which is verified. - local dir="$1" repo desc file_name sha256 - repo="$(curl -fsL "$VALVE_MIRROR/" | grep -oE 'jupiter-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)" - [[ -n "$repo" ]] && curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$repo.db" -o "$dir/repo.db" || - { err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; } - desc="$(tar -tf "$dir/repo.db" 2>/dev/null | grep -E '^steamdeck-kde-presets-[0-9][^/]*/desc$' | head -n 1)" - [[ -n "$desc" ]] || { err "No steamdeck-kde-presets in Valve's $repo repository."; return 1; } - file_name="$(tar -xOf "$dir/repo.db" "$desc" | awk '/^%FILENAME%$/ { getline; print }')" - sha256="$(tar -xOf "$dir/repo.db" "$desc" | awk '/^%SHA256SUM%$/ { getline; print }')" - - info "Downloading $file_name ($repo)..." - curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$file_name" -o "$dir/presets.pkg.tar.zst" || - { err "Downloading $file_name failed."; return 1; } - echo "$sha256 $dir/presets.pkg.tar.zst" | sha256sum -c --quiet - || - { err "Checksum mismatch for $file_name; not using it."; return 1; } - tar -I unzstd -xf "$dir/presets.pkg.tar.zst" -C "$dir" usr/bin usr/share || - { err "Extracting $file_name failed."; return 1; } + # steamdeck-kde-presets (from the newest SteamOS release repo, jupiter-3.9, + # jupiter-3.10, ...) into . + local dir="$1" pkg + pkg="$(valve_fetch_pkg jupiter steamdeck-kde-presets "$dir")" || return 1 + tar -I unzstd -xf "$pkg" -C "$dir" usr/bin usr/share || + { err "Extracting $(basename "$pkg") failed."; return 1; } } extras_enable() { diff --git a/lib/valve-mirror.sh b/lib/valve-mirror.sh new file mode 100644 index 0000000..c3f3dbf --- /dev/null +++ b/lib/valve-mirror.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Valve's SteamOS package mirror: finding its newest repository and fetching a +# verified package from it. Used by the SteamOS extras, the Steam Machine CEC +# driver, the BIOS update and the os-release version. +# Sourced by steamify.sh; not meant to be run on its own. + +VALVE_MIRROR="https://steamdeck-packages.steamos.cloud/archlinux-mirror" + +valve_newest_repo() { + # valve_newest_repo [max-seconds]: the newest -X.Y repo + # (jupiter, holo), compared as versions: 3.10 is newer than 3.9. Prints + # nothing when the mirror can't be reached. + local -a limit=() + [[ -n "${2:-}" ]] && limit=(--max-time "$2") + curl -fsL "${limit[@]}" "$VALVE_MIRROR/" 2>/dev/null | grep -oE "$1-[0-9]+\.[0-9]+/" | tr -d / | sort -uV | tail -n 1 +} + +valve_repo_url() { echo "$VALVE_MIRROR/$1/os/x86_64"; } + +valve_desc_field() { + # valve_desc_field : one value from a package's + # entry in a pacman database (FILENAME, SHA256SUM). + tar -xOf "$1" "$2" 2>/dev/null | awk -v f="%$3%" '$0 == f { getline; print }' +} + +valve_fetch_pkg() { + # valve_fetch_pkg : download the newest + # from the newest repository into and print its + # path. The file name and SHA-256 come from the repository's database and + # the checksum is verified; the database is kept in for more calls. + local prefix="$1" name="$2" dir="$3" repo db desc file_name sha256 + repo="$(valve_newest_repo "$prefix")" + db="$dir/$prefix.db" + if [[ ! -f "$db" ]]; then + [[ -n "$repo" ]] && curl -fsL "$(valve_repo_url "$repo")/$repo.db" -o "$db" || + { err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; } + fi + desc="$(tar -tf "$db" 2>/dev/null | grep -E "^$name-[0-9][^/]*/desc$" | head -n 1)" + [[ -n "$desc" ]] || { err "No $name in Valve's $repo repository."; return 1; } + file_name="$(valve_desc_field "$db" "$desc" FILENAME)" + sha256="$(valve_desc_field "$db" "$desc" SHA256SUM)" + + info "Downloading $file_name ($repo)..." >&2 + curl -fsL "$(valve_repo_url "$repo")/$file_name" -o "$dir/$file_name" || + { err "Downloading $file_name failed."; return 1; } + echo "$sha256 $dir/$file_name" | sha256sum -c --quiet - >&2 || + { err "Checksum mismatch for $file_name; not using it."; return 1; } + echo "$dir/$file_name" +} diff --git a/steamify.sh b/steamify.sh index dcfa49a..bcebe23 100755 --- a/steamify.sh +++ b/steamify.sh @@ -19,7 +19,7 @@ VERSION=2.11.1 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do +for lib in common valve-mirror state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do # shellcheck source=/dev/null source "$SCRIPT_DIR/lib/$lib.sh" done