fix: Single-file build for curl, published by GitHub Actions

tools/bundle.sh inlines lib/ into one script; the workflow builds and
checks it on every push and PR, and on main publishes it to the rolling
"latest" release. Piped in via curl, it reattaches the terminal so the
menu keeps working.
This commit is contained in:
theupriser committed 2026-09-23 15:37:06 +02:00
1 parent 3d7f3764d6
commit d654d44b6a
5 files changed
+131 -3

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
# Builds the single-file wizard (tools/bundle.sh) and publishes it as the
# asset of the rolling "latest" release, for:
# bash <(curl -fsSL https://github.com/theupriser/cachyos-gamescope-boot/releases/download/latest/setup-gamescope-boot.sh)
# Pull requests only build and check it.
name: Single-file build
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: write
jobs:
bundle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # for the version in the bundle's header
- name: Build
run: tools/bundle.sh dist/setup-gamescope-boot.sh
- name: Check
run: |
bash -n dist/setup-gamescope-boot.sh
# SC2034/SC2154: variables used across the inlined modules.
shellcheck -S warning -e SC2034,SC2154 dist/setup-gamescope-boot.sh
- uses: actions/upload-artifact@v4
with:
name: setup-gamescope-boot
path: dist/setup-gamescope-boot.sh
- name: Publish to the "latest" release
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
env:
GH_TOKEN: ${{ github.token }}
run: |
notes="Single-file build of $(git describe --always) ($(git log -1 --format=%cs)).
Run it with:
bash <(curl -fsSL https://github.com/${{ github.repository }}/releases/download/latest/setup-gamescope-boot.sh)"
if gh release view latest >/dev/null 2>&1; then
gh release edit latest --notes "$notes"
else
gh release create latest --title "Latest single-file build" --notes "$notes" --latest
fi
# Move the tag to this commit and replace the asset.
git tag -f latest && git push -f origin latest
gh release upload latest dist/setup-gamescope-boot.sh --clobber
+1
View File
@@ -0,0 +1 @@
dist/
+6
View File
@@ -31,6 +31,12 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
`krevert <component>`. Never call `kwriteconfig6` directly for settings a `krevert <component>`. Never call `kwriteconfig6` directly for settings a
component owns. System files are backed up with `backup_file` and restored component owns. System files are backed up with `backup_file` and restored
on disable. on disable.
- **Single-file build.** `tools/bundle.sh` inlines `lib/*.sh` in the order of
the entry point's `for lib in ...; do` source loop and wraps everything
after that loop in `main()`. Keep that loop on one line, keep all logic in
functions, and don't rely on `SCRIPT_DIR` for anything but sourcing.
CI (`.github/workflows/bundle.yml`) publishes the bundle to the `latest`
release on pushes to `main`.
## Conventions ## Conventions
+21 -3
View File
@@ -38,8 +38,16 @@ Everything you turn off is put back the way it was.
Open **Konsole** on your Plasma desktop and run: Open **Konsole** on your Plasma desktop and run:
```bash ```bash
git clone <this-repo-url> bash <(curl -fsSL https://github.com/theupriser/cachyos-gamescope-boot/releases/download/latest/setup-gamescope-boot.sh)
cd <this-repo> ```
That downloads and runs the latest single-file version. `curl -fsSL ... | bash`
works too. Prefer to keep a copy, or to look at the script first? Clone the
repository instead:
```bash
git clone https://github.com/theupriser/cachyos-gamescope-boot.git
cd cachyos-gamescope-boot
./setup-gamescope-boot.sh ./setup-gamescope-boot.sh
``` ```
@@ -63,7 +71,8 @@ Run it again whenever you like - to change your choices, to turn things off
again, or after a CachyOS update (press `a` in the menu to re-apply again, or after a CachyOS update (press `a` in the menu to re-apply
everything that's on). everything that's on).
Keep the whole folder: the script needs the files in `lib/` next to it. If you cloned the repository, keep the whole folder: the script needs the
files in `lib/` next to it.
## Using it ## Using it
@@ -312,6 +321,15 @@ gamescope-session, ...) stay installed.
| `lib/vapor-theme.sh` | SteamOS theme: Vapor, Valve's defaults, panel, dark mode | | `lib/vapor-theme.sh` | SteamOS theme: Vapor, Valve's defaults, panel, dark mode |
| `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out | | `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out |
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager | | `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager |
| `tools/bundle.sh` | Builds the single-file version (`dist/setup-gamescope-boot.sh`) |
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
The single-file version is generated: on every push to `main`, GitHub
Actions runs `tools/bundle.sh`, checks the result with `bash -n` and
shellcheck, and uploads it to the rolling `latest` release. It inlines
`lib/*.sh` and wraps the entry point in `main()`, so bash has read the whole
file before anything runs; when stdin is a pipe (`curl | bash`) it reattaches
the terminal for the menu (set `WIZARD_KEEP_STDIN=1` to keep piped input).
Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md). Notes for contributors and AI coding agents are in [`AGENTS.md`](AGENTS.md).
+49
View File
@@ -0,0 +1,49 @@
#!/bin/bash
# Build a single-file version of the wizard for `curl | bash` use:
# tools/bundle.sh [output] (default: dist/setup-gamescope-boot.sh)
#
# Inlines lib/*.sh in the order setup-gamescope-boot.sh sources them and
# wraps the entry point's body in main(), so bash has read the whole file
# before anything runs. That lets the bundle reattach stdin to the terminal
# when it was piped in by curl, so the interactive menu still works.
set -euo pipefail
cd "$(dirname "$0")/.."
out="${1:-dist/setup-gamescope-boot.sh}"
entry=setup-gamescope-boot.sh
mkdir -p "$(dirname "$out")"
# Library order, taken from the entry point's source loop.
libs=$(grep -oP '^for lib in \K.*(?=; do$)' "$entry")
[[ -n "$libs" ]] || { echo "bundle: can't find the lib source loop in $entry" >&2; exit 1; }
version="$(git describe --always --dirty 2>/dev/null || echo unknown)"
{
# Header comment and `set` line of the entry point, up to the source loop.
sed -n '1,/^SCRIPT_DIR=/p' "$entry" | sed '$d'
echo "# Single-file build ($version), generated by tools/bundle.sh - edit the"
echo "# sources in the repository instead: https://github.com/theupriser/cachyos-gamescope-boot"
echo
for lib in $libs; do
echo "# ----- lib/$lib.sh -----"
# Drop each module's shebang and its "Sourced by ..." boilerplate.
sed -e '1{/^#!/d}' -e '/^# Sourced by setup-gamescope-boot.sh/d' "lib/$lib.sh"
echo
done
echo "# ----- setup-gamescope-boot.sh -----"
echo "main() {"
# Everything after the source loop is the entry point's body.
sed -n '/^for lib in /,$p' "$entry" | sed '1,/^done$/d' | sed 's/^/ /; s/^ $//'
echo "}"
echo
echo "# Piped in via curl, bash reads this very file from stdin. Give the menu"
echo "# the terminal instead - on the same line as main and exit: bash has read"
echo "# this line in full, so it never reads further script from the terminal."
echo 'reattach_tty() { if [[ ! -t 0 && -z "${WIZARD_KEEP_STDIN:-}" ]]; then { exec </dev/tty; } 2>/dev/null || true; fi; }'
echo 'reattach_tty; main "$@"; exit $?'
} > "$out"
chmod +x "$out"
bash -n "$out"
echo "Wrote $out ($version)"