mirror of
https://github.com/theupriser/steamify-cachyos-dev.git
synced 2026-10-14 15:48:49 +02:00
Compare commits
105
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
737882c213 | ||
|
|
0e63b931ea | ||
|
|
3bcbdf3d98 | ||
|
|
9dbf05ab9c | ||
|
|
86a44d7e68 | ||
|
|
d540dd2310 | ||
|
|
f7625f5882 | ||
|
|
b4d6c23129 | ||
|
|
7a313a96ee | ||
|
|
9e8e05e99b | ||
|
|
b95ccb686d | ||
|
|
dabc43ded6 | ||
|
|
a253ff15cd | ||
|
|
c8a6a2cef5 | ||
|
|
1aff67612d | ||
|
|
b2fc992745 | ||
|
|
90fe42da5f | ||
|
|
5146dd1109 | ||
|
|
b840eb3697 | ||
|
|
5ea436efc5 | ||
|
|
f33d3bf491 | ||
|
|
32db035e9b | ||
|
|
cfba222439 | ||
|
|
76b162d7e1 | ||
|
|
da263529e9 | ||
|
|
f604e10b3e | ||
|
|
19ea677cf7 | ||
|
|
ca0cf43919 | ||
|
|
7b7715ab07 | ||
|
|
8ef247e596 | ||
|
|
1db4693e3c | ||
|
|
6190abadfc | ||
|
|
4cb253b41c | ||
|
|
7b0147f065 | ||
|
|
f35df9c4d3 | ||
|
|
85657a3183 | ||
|
|
92bf3f0b19 | ||
|
|
b07ff5f99b | ||
|
|
2daf83b013 | ||
|
|
d8c7670c53 | ||
|
|
58b233c20b | ||
|
|
b6e801664a | ||
|
|
fa01c19ba1 | ||
|
|
f356cc3f74 | ||
|
|
0824e78249 | ||
|
|
48edfc53c5 | ||
|
|
36bd85cce6 | ||
|
|
4670b296dc | ||
|
|
b6082c0322 | ||
|
|
ebf9e3c267 | ||
|
|
ade5566174 | ||
|
|
6729d61ea8 | ||
|
|
5f97f1334c | ||
|
|
c6578103a3 | ||
|
|
97f68a8065 | ||
|
|
3a0d9f98d8 | ||
|
|
fd1b916023 | ||
|
|
b6a7b30092 | ||
|
|
314bac87e7 | ||
|
|
dea5f9d715 | ||
|
|
a576b734c7 | ||
|
|
105ac638ee | ||
|
|
d231aec125 | ||
|
|
5b3e246629 | ||
|
|
f24ff3927e | ||
|
|
b895e28181 | ||
|
|
0a12c0e4c6 | ||
|
|
fcffceb941 | ||
|
|
ea1207580f | ||
|
|
38a50ab57d | ||
|
|
ed12ecb57d | ||
|
|
8ea75424b0 | ||
|
|
e435577b5c | ||
|
|
104d1dac44 | ||
|
|
8b0c168711 | ||
|
|
d0c551d23a | ||
|
|
728f329ebc | ||
|
|
332fdca4c2 | ||
|
|
92c1e58f55 | ||
|
|
36d1e6d326 | ||
|
|
c5ac00faf6 | ||
|
|
107f8f4076 | ||
|
|
1c1bc55a62 | ||
|
|
6df107d578 | ||
|
|
6840044038 | ||
|
|
32499b1c01 | ||
|
|
b1e9a273a3 | ||
|
|
9706066269 | ||
|
|
7a0a216327 | ||
|
|
4adc018654 | ||
|
|
ac8f77cf4a | ||
|
|
0f57d86bae | ||
|
|
46e039809e | ||
|
|
379f1c7f7f | ||
|
|
471332e20f | ||
|
|
8ce2917c0f | ||
|
|
9a4653b6d3 | ||
|
|
3b7b685667 | ||
|
|
7a0443e131 | ||
|
|
8d5a659c89 | ||
|
|
6d992c83c7 | ||
|
|
974cea7cf4 | ||
|
|
19b6ba4d97 | ||
|
|
788d345a9d | ||
|
|
10357b2d52 |
No files matched your search
@@ -116,7 +116,7 @@ VM: note what differs here. In the VM (`vm_ssh`, visibly in a Konsole there):
|
||||
sudo pacman -S --needed --noconfirm podman git
|
||||
git clone https://github.com/theupriser/steamify-cachyos-live-iso ~/projects/steamify-cachyos-live-iso
|
||||
sudo mount -t 9p -o trans=virtio,version=9p2000.L repo /mnt # the Steamify checkout (REPO)
|
||||
cd ~/projects/steamify-cachyos-live-iso && git checkout feat/steamify && ./steamify-prepare.sh /mnt
|
||||
cd ~/projects/steamify-cachyos-live-iso && git checkout master && ./steamify-prepare.sh /mnt
|
||||
```
|
||||
|
||||
then the same `podman run` as below (paths in the VM; `~/projects/iso-build.log`).
|
||||
@@ -134,7 +134,7 @@ not a rootless podman GUI. Clone: `~/projects/steamify-cachyos-live-iso`.
|
||||
|
||||
```bash
|
||||
cd ~/projects/steamify-cachyos-live-iso
|
||||
git checkout feat/steamify && ./steamify-prepare.sh ~/projects/steamify-cachyos
|
||||
git checkout master && ./steamify-prepare.sh ~/projects/steamify-cachyos
|
||||
sudo rm -rf build out
|
||||
systemd-run --user --collect -q -u isobuild-$(date +%s) --working-directory=$PWD bash -c \
|
||||
"sudo podman run --rm -t --pids-limit=-1 --ulimit nofile=65536:65536 --privileged --network=host \
|
||||
|
||||
@@ -6,16 +6,15 @@ description: Clean up git branches in steamify-cachyos (and sibling steamify rep
|
||||
# Steamify branch cleanup
|
||||
|
||||
Rules:
|
||||
- ALWAYS keep `main` and every `release/X.Y.Z` branch (local and remote). Never delete them.
|
||||
- ALWAYS keep `main`. A `release/X.Y.Z` branch is deleted (local and remote) once its release is published and its tip is contained in a tag or in `main` (the user said so on 2026-10-02: the tags keep the history). Check each one first (`git tag --contains <tip>`, `git merge-base --is-ancestor`): a release branch with a commit that is in no tag and not in `main` (`release/2.9.2`: a docs commit) is kept and reported. The open release's branch stays until its PR is merged.
|
||||
- Delete `feature/*` and `bugfix/*` branches (local and remote) only when merged into `origin/main` or the current `origin/release/*` branch.
|
||||
- Delete local branches whose remote is gone (`[origin/...: gone]`) only if they are `feature/*` or `bugfix/*`; local stale `release/*` branches are kept unless the user says otherwise.
|
||||
- Never touch unmerged branches; list them and report instead.
|
||||
- Never commit or merge to main.
|
||||
|
||||
Merging a feature/bugfix PR yourself (into a release branch, or `feat/steamify` in the ISO repo): delete the
|
||||
Merging a feature/bugfix PR yourself (into a release branch, or `master` in the ISO repo): delete the
|
||||
branch at once, remote and local (`gh pr merge N --merge --delete-branch`, then `git branch -D`, `git fetch
|
||||
--prune`); the user asked for this on 2026-09-29. Release branches are never deleted (kept as history next to
|
||||
their tags). Unmerged old branches (`feat/vram-booster`, `refactor/qml-screens`, `backup/*`) are reported, not
|
||||
--prune`); the user asked for this on 2026-09-29. Release branches are deleted after their release (see the rules above; the tag keeps the history). Unmerged old branches (`feat/vram-booster`, `refactor/qml-screens`, `backup/*`) are reported, not
|
||||
touched. The GitHub-side `release delete <tag> --cleanup-tag` is how test ISO releases go.
|
||||
|
||||
Steps:
|
||||
|
||||
@@ -5,32 +5,57 @@ description: Use when releasing, debugging or changing how the Steamify ISO is b
|
||||
|
||||
# Steamify ISO release pipeline (set up 2026-09-29, first ISO out the same night)
|
||||
|
||||
Tested end to end: release `v2.9.3-dev.2026.09.29-2044` -> `steamify-cachyos-2.9.3-dev.2026.09.29-2044-x86_64.iso`
|
||||
on git.upriser.nl, GitHub's link to it answers 200.
|
||||
Tested end to end with the first naming (`v2.9.3-dev.2026.09.29-2044`); since 2026-09-30 the names are by the day, like
|
||||
CachyOS (below; workflow changes in ISO repo PR #15, steamify-cachyos PR #69). The workflows always run from the ISO
|
||||
repo's `master`; `feat/steamify` is no longer needed.
|
||||
|
||||
## The flow (one tag names everything)
|
||||
|
||||
1. **GitHub, `iso-1-github-tag.yml`** (ISO repo `theupriser/steamify-cachyos-live-iso`, `workflow_dispatch` only):
|
||||
takes Steamify's newest release (`X.Y.Z`), the time **now in UTC** and makes an **annotated tag**
|
||||
`vX.Y.Z-[dev.]YYYY.MM.DD-HHMM` plus a GitHub release with the changelog notes and the *direct* download link
|
||||
on Gitea. `dev.` and a pre-release on `feat/steamify` (test build), none on `master` (a release).
|
||||
GitHub is the only place that reads a clock.
|
||||
2. **The mirror syncs** (git.upriser.nl is a pull mirror of GitHub, every 10 minutes): the tag arrives.
|
||||
3. **Gitea, `iso-2-gitea-build.yml`** (`on: push: tags: ['v*']`, skipped on GitHub by `github.server_url`): parses the
|
||||
1. **GitHub, `iso-1-github-tag.yml`** (ISO repo `theupriser/steamify-cachyos-live-iso`, `workflow_dispatch` only, input
|
||||
`kind`: `release`, `dev` or `auto` = release on master, dev elsewhere): takes Steamify's newest release (`X.Y.Z`),
|
||||
the day **now in UTC** and makes an **annotated tag** plus a GitHub release with the changelog notes and the
|
||||
*direct* download link on Gitea. Like CachyOS by the day, no time: real `vX.Y.Z-YYMMDD`, dev (pre-release)
|
||||
`vX.Y.Z-dev-YYMMDD`. GitHub is the only place that reads a clock.
|
||||
- **One ISO per day and kind** (space): a second build the same day deletes the earlier GitHub release and tag,
|
||||
syncs the mirror and waits until the mirror dropped the tag (it drops tag, release and ISO together), then tags
|
||||
again (else the new tag is only an update there and starts no build).
|
||||
- **Retention:** at most 10 dev and 10 real releases (`gh release delete --cleanup-tag`); the mirror follows.
|
||||
2. **The mirror syncs** (git.upriser.nl is a pull mirror of GitHub with **no interval of its own**: every repo's
|
||||
`git-upriser-sync.yml` calls its mirror-sync API on every branch and tag push, and iso-1's last step after the tag;
|
||||
secrets `GIT_UPRISER_URL`, `GIT_UPRISER_TOKEN`): the tag arrives.
|
||||
3. **Gitea, `iso-2-gitea-build.yml`** (`workflow_dispatch` only, started by iso-1's last step through Gitea's dispatch API with
|
||||
`{"ref": "refs/tags/<tag>"}` (the **full** ref: a bare tag name answers 404) and the input `steamify_ref`; a tag push
|
||||
starts nothing; skipped on GitHub by `github.server_url`): parses the
|
||||
tag, builds the ISO on the runner with exactly that Steamify (`STEAMIFY_VERSION`), the tag's time (label) and
|
||||
the tag without its `v` (`STEAMIFY_ISO_VERSION`: file name, boot menu, `/etc/steammachine-iso-build`), then
|
||||
attaches ISO + `.sha256` + `.sha1` + `.pkgs.txt` to the mirror's release for that tag
|
||||
(`akkuman/gitea-release-action`, the run's own token). Never overwrites a release that already has its ISO.
|
||||
(`akkuman/gitea-release-action`, the run's own token). A leftover release of the same tag is replaced. Two jobs,
|
||||
build and release; no tests there (the runner is small): VM tests run locally, `scripts/vmtest.sh`.
|
||||
4. **Trigger:** by hand (*Actions -> ISO 1/2 · Tag and release (GitHub) -> Run workflow*, or
|
||||
`gh workflow run iso-1-github-tag.yml -R theupriser/steamify-cachyos-live-iso --ref feat/steamify`), or by a
|
||||
new Steamify release: `steamify-cachyos`' `bundle.yml` step "Start the Steamify ISO's release" (secret
|
||||
`gh workflow run iso-1-github-tag.yml -R theupriser/steamify-cachyos-live-iso --ref master -f kind=dev|release`), or
|
||||
by a new version: `steamify-cachyos`' `bundle.yml` step "Start the Steamify ISO's release" (a version published
|
||||
from `main` -> `kind=release`, an unreleased version pushed to `release/**` -> `kind=dev`; secret
|
||||
`ISO_DISPATCH_TOKEN` there: fine-grained token, only the ISO repo, *Actions: read and write*; without it the
|
||||
step is skipped). A push does **not** release (a build is 20 minutes and 3.2 GB).
|
||||
5. Names, for tag `v2.9.3-dev.2026.09.29-2044`: file `steamify-cachyos-2.9.3-dev.2026.09.29-2044-x86_64.iso`,
|
||||
label `STEAMIFY_2_9_3_20260929_2044` (ISO 9660: 32 chars, `A-Z 0-9 _`). By hand, without a tag: `local`
|
||||
5. Names, for tag `v2.9.6-dev-260930`: file `steamify-cachyos-2.9.6-dev-260930-x86_64.iso`,
|
||||
label `STEAMIFY_2_9_6_260930` (ISO 9660: 32 chars, `A-Z 0-9 _`). By hand, without a tag: `local`
|
||||
(`steamify-cachyos-local-x86_64.iso`, `STEAMIFY_<version>_LOCAL`). The build reads no clock.
|
||||
|
||||
Total from a Steamify release to the ISO on Gitea: about 30 minutes (release, tag, sync <=10 min, build 15-20).
|
||||
Total from a Steamify release to the ISO on Gitea: about 20 minutes (release, tag, sync in seconds, build ~18).
|
||||
|
||||
## Which Steamify goes on the ISO, and the build badge
|
||||
|
||||
- `iso-1` input **`steamify_ref`** (a Steamify branch or tag; empty = the newest *published* release). A dev ISO from a
|
||||
release branch passes the branch (`bundle.yml` does), so `release/2.9.6` gives a 2.9.6 ISO before `v2.9.6` exists;
|
||||
without it every dev ISO carries the last published version (it kept producing 2.9.5). iso-1 reads `VERSION` from
|
||||
that ref's `steamify.sh`; iso-2 clones the ref and runs `steamify-prepare.sh <checkout>`.
|
||||
- **Build badge in the GitHub release:** iso-1 writes `` at the top of the notes; iso-2's
|
||||
last job `report` (`if: always()`) turns it into succeeded / failed / cancelled (shields.io static badge, linked to the
|
||||
Gitea run) through the GitHub API. Secret **`GH_RELEASE_TOKEN`** on the Gitea repo (Settings -> Actions -> Secrets):
|
||||
fine-grained GitHub token, only `steamify-cachyos-live-iso`, *Contents: read and write*; expires, so renew it. Without
|
||||
it the badge stays "running". Gitea's own `badge.svg` says "no status" for these runs (they run on a tag ref).
|
||||
- Secrets in all: GitHub `steamify-cachyos`: `ISO_DISPATCH_TOKEN`, `GIT_UPRISER_URL`, `GIT_UPRISER_TOKEN`; GitHub ISO
|
||||
repo: `GIT_UPRISER_URL`, `GIT_UPRISER_TOKEN`; Gitea ISO repo: `GH_RELEASE_TOKEN`.
|
||||
|
||||
## Why it is split like this (learned the hard way)
|
||||
|
||||
@@ -39,6 +64,14 @@ Total from a Steamify release to the ISO on Gitea: about 30 minutes (release, ta
|
||||
release on a tag that **comes from GitHub survives** every sync, files included (tested with a 0-byte asset).
|
||||
Hence: GitHub makes the tag, Gitea only attaches the file. You can't delete a tag on a mirror by hand either.
|
||||
- GitHub releases take **2 GB per file**; the ISO is 3.2 GB. So GitHub gets notes and a link, Gitea the file.
|
||||
- **A replaced tag starts no run on the mirror.** One ISO per day and kind: iso-1 deletes the day's GitHub release and
|
||||
tag and tags again; the mirror takes the new tag object (same name) but Gitea starts nothing and keeps the old release
|
||||
(same id, new creation time) with the old ISO. So the build is started by dispatch, after the mirror has the new tag
|
||||
object (`GET .../tags/<tag>` id == `git rev-parse refs/tags/<tag>`); iso-2 deletes a leftover release of the tag before
|
||||
it publishes. Retention: at most 10 dev + 10 real releases.
|
||||
- **Gitea runner and parallel jobs:** it ignores `max-parallel`, and jobs that start in the same second clone the same
|
||||
action into one shared folder and break each other (`actions/cache` failed): keep parallel jobs free of `uses:`.
|
||||
(The VM tests no longer run there at all: they run locally, `scripts/vmtest.sh`.)
|
||||
- **Annotated tags**: a lightweight tag has only its commit's date, so tags on the same commit sort randomly
|
||||
on Gitea. UTC is fine (the release name says "UTC"; it is 2 h behind Dutch summer time, and nobody cared).
|
||||
- The GitHub release's link is built from the tag alone (`.../releases/download/<tag>/steamify-cachyos-<tag
|
||||
@@ -94,8 +127,8 @@ if it ever vanishes, ship the file with Steamify.
|
||||
## Checklist for a release
|
||||
|
||||
1. Steamify released? (`gh release list -R theupriser/steamify-cachyos`). The ISO gets the newest.
|
||||
2. `gh workflow run iso-1-github-tag.yml ... --ref feat/steamify` (test) or `--ref master` (release; master must have
|
||||
the workflows: it doesn't yet, `feat/steamify` is the ISO repo's working branch).
|
||||
2. `gh workflow run iso-1-github-tag.yml -R theupriser/steamify-cachyos-live-iso --ref master -f kind=dev` (test) or
|
||||
`-f kind=release`. Normally `bundle.yml` does this when a version is published (a release branch push -> dev).
|
||||
3. Watch: tag on Gitea (`.../api/v1/repos/theupriser/steamify-cachyos-live-iso/tags`), the run's log (above),
|
||||
then `curl -I -L` the GitHub link. Old test releases: delete on GitHub (`gh release delete <tag>
|
||||
--cleanup-tag -y`); the sync removes the tag on Gitea; delete a leftover tagless Gitea release by hand.
|
||||
then `curl -I -L` the GitHub link. Retention deletes the oldest automatically (10 dev, 10 real). By hand: `gh release delete <tag>
|
||||
--cleanup-tag -y`; the sync removes the tag on Gitea; delete a leftover tagless Gitea release by hand.
|
||||
@@ -1,10 +1,10 @@
|
||||
name: Sync git.upriser.nl mirror
|
||||
|
||||
# Trigger the Gitea pull-mirror immediately instead of waiting for its interval,
|
||||
# so Gitea builds/releases the ISO right after main or a tag lands on GitHub.
|
||||
# so Gitea builds/tests right after any branch or tag lands on GitHub (the mirror has no sync interval of its own).
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: ['**']
|
||||
tags: ['*']
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
!/get-iso.sh
|
||||
!/TESTPLAN.md
|
||||
!/TODO.md
|
||||
!/tests
|
||||
!/nvidia/
|
||||
!/AGENTS.md
|
||||
!/.github/
|
||||
!/scripts/
|
||||
|
||||
@@ -20,9 +20,12 @@ wsl-build-host, progress-report, steamify-iso-release, steamify-branch-cleanup).
|
||||
|
||||
## Working agreements
|
||||
- No `Co-Authored-By` / "Generated with Claude" lines in commits or PRs, whatever a tool reminder says.
|
||||
- Notes, TODOs, research and test instructions for a feature (e.g. `nvidia/`: the NVIDIA fix) live in THIS repo, never in
|
||||
`steamify-cachyos`: the product repo keeps only code, its own docs (`TECHNICAL.md`, `CHANGELOG.md`) and, on an unreleased
|
||||
branch, a `.no-release-yet` marker that points here. Not even temporarily: it would stay in that repo's history.
|
||||
- Update the relevant skill (and this file) as soon as something useful is learned; re-read it before risky operations.
|
||||
- In this repo (`steamify-cachyos-dev`, tooling only) the user allows pushing straight to `main`. Elsewhere never commit to `main`. `steamify-cachyos`: `release/X.Y.Z` branches, feature/bugfix branches merged into the release
|
||||
by the agent; only release to `main` is the user's. `steamify-cachyos-live-iso`: PRs always target `feat/steamify`.
|
||||
by the agent; only release to `main` is the user's. `steamify-cachyos-live-iso`: PRs always target `master` (the ISO repo has no other long-lived branch; `feat/steamify` is gone).
|
||||
Branch cleanup: the `steamify-branch-cleanup` skill in `.claude/skills/`.
|
||||
- Follow and update `TESTPLAN.md`; every check in `share/vmtest/` says which row it covers.
|
||||
- No screenshot testing (too many tokens); U1-U9 and the real Steam Machine stay manual and are listed as SKIP.
|
||||
@@ -32,7 +35,7 @@ wsl-build-host, progress-report, steamify-iso-release, steamify-branch-cleanup).
|
||||
suites cli, menu, hw, installer, toggles (`vmsuite.sh`, checks in `share/vmtest/`). Each passed in its own run: limine 43,
|
||||
systemd-boot 42, grub 42 (with the B1 boot entry check), cli 55, menu 36, hw 77, installer 4, toggles 42 checks.
|
||||
- 2026-09-29, on the PC (WSL2): the first complete parallel run, **328 pass, 0 fail in 18 minutes** (base image +
|
||||
qcow2 overlays, own ssh port per job, package cache, `VM_MEM=4G`, `MAX_PARALLEL=3`). On a new machine: one full
|
||||
qcow2 overlays, own ssh port per job, package cache, `VM_MEM=4G`, `MAX_PARALLEL=3`; 5 worked on the 9800X3D). On a new machine: one full
|
||||
`scripts/vmtest.sh --screen`, read `~/vms/last-test.txt`, fix what fails.
|
||||
- Open work: `TODO.md` (the CEC driver download, the GitHub Actions workflow, P3).
|
||||
|
||||
@@ -51,7 +54,7 @@ The tests run on the user's PC (Ryzen 9800X3D, 64 GB, **WSL2**), started from a
|
||||
down, syncing from the laptop, the podman ISO build, VM windows through WSLg, output in the user's WSL terminal, no GPU
|
||||
passthrough): `.claude/skills/wsl-build-host/SKILL.md`. `vminstall.sh` works there without udisks (losetup as root).
|
||||
|
||||
## Problems found in the Steamify ISO (fix in `steamify-cachyos-live-iso`, PRs into `feat/steamify`)
|
||||
## Problems found in the Steamify ISO (fix in `steamify-cachyos-live-iso`, PRs into `master`)
|
||||
- Fixed (PR #2): cachyos-installer's `bootctl install` runs in a chroot and writes no EFI boot entry, so systemd-boot
|
||||
only booted through the disk's fallback path (in OVMF after 4-5 minutes of network boot, every boot).
|
||||
`steamify-install` now registers it with efibootmgr from the live system.
|
||||
|
||||
@@ -4,6 +4,26 @@ All notable changes, per version and per commit. Versions follow
|
||||
[Semantic Versioning](https://semver.org/) and were numbered from the start
|
||||
of the history.
|
||||
|
||||
## 0.5.0 - 2026-10-02
|
||||
|
||||
The whole automated test (boot loaders plus suites), the Steamify ISO pipeline,
|
||||
the NVIDIA notes, and the Steamify unit tests and hardware test moved here.
|
||||
|
||||
- **feat: `scripts/vmtest.sh` runs everything: the boot loader test for every loader the ISO advertises, the plain-PC install check and the `cli`, `menu`, `hw`, `installer`, `toggles` and `nvidia` suites** (`ee20bd9`, `c91277a`, `fe5251f`, `b91ef91`, `6d264ac`, `343ff1e`, `5d168ea`)
|
||||
- `vmbootloadertest.sh --quick [--generic]`: only what the ISO's install must get right, a Steam Machine gets all its items and modules, a plain PC none (`fafa38f`, `459832c`)
|
||||
- faster and parallel runs (`MAX_PARALLEL`), a remote runner, progress lines while the tests run (`0c84b8b`, `540139b`)
|
||||
- the boot entry check (BootCurrent) after every reboot (`27b7445`), the CEC driver cache blocks (`e6119ca`), `vmview.py` (`4cc4046`)
|
||||
- **feat: `scripts/vminstall.sh` installs any boot loader and runs the Steamify ISO's Steamify step, with a package cache** (`8646b3c`)
|
||||
- parallel installs under a lock, never root as the guest user, headless in CI, stops at once when the live system reports a failed install (`9d53740`, `d5cfadf`, `e929444`, `a34efb0`)
|
||||
- **feat: `scripts/vmisobuild.sh` builds the Steamify ISO in the test VM** (`bc06bc2`)
|
||||
- **feat: the `progress-report` skill and `scripts/vmprogress.sh`** (`fd9ecf4`)
|
||||
- **docs: skills and AGENTS.md: the ISO release pipeline, the WSL build host, the VM tests, token-cheap ISO-VM testing** (`0d0279b`, `a1f8089`, `cb247b9`, `0052f1b`)
|
||||
- **docs: `nvidia/`: TODO, research and test instructions for the NVIDIA fix, with the results of the hardware test on the RTX 5080 PC** (`d045b82`, `0052566`, `fa67d65`)
|
||||
- **test: the Steamify unit tests (`controllers-test.sh`, `nvidia-test.sh`) and the NVIDIA hardware test move here from steamify-cachyos, in `tests/`; `REPO` points at the checkout** (`899e9af`)
|
||||
- **test: `vmstate.sh` reports Steam's autostart entry (silent, plain, none) instead of the old systemd unit** (`66ec27d`)
|
||||
- Steamify 2.11.0 tested here before its release: three ISO installs (defaults, everything on, Fremont everything on) and the full suite on a plain CachyOS VM, 269 checks passed, 0 failed, 1 known skip. Found on the way: the first-login skip failed in a bundle (`SCRIPT_DIR` unbound) and the Steam Machine serial step failed in the installer's chroot (read-only `/sys`); both fixed in Steamify.
|
||||
- Known: `vmtest.sh` and `vmsuite.sh` write fixed files in `/tmp` (`/tmp/vmtest-*.out`, `/tmp/vmsuite-*-reset.out`, `/tmp/vminstall-iso.lock`): a second user on the same host gets "Permission denied" on files the first one left.
|
||||
|
||||
## 0.4.0 - 2026-09-28
|
||||
|
||||
An unattended VM install, a test plan, and the lessons from testing
|
||||
|
||||
+30
@@ -64,6 +64,34 @@ change only shows right after Enter).
|
||||
|
||||
## F. Features per release
|
||||
|
||||
### F2.10.0 Gaming on NVIDIA (`feature/nvidia-gaming-fix`; suite `nvidia`, fake NVIDIA PC)
|
||||
|
||||
gamescope's session is broken on NVIDIA (see `nvidia/HARDWARE-RESULTS.md`), so on an NVIDIA PC the conversion is replaced by
|
||||
"Gaming on NVIDIA" (Steam on the Plasma desktop, started at login, optionally in Big Picture) and single user mode logs in to Plasma.
|
||||
The VM has no NVIDIA GPU: `fake_nvidia` (`share/vmtest/prelude.sh`) fakes one through Steamify's `NVIDIA_DRM_DIR` test hook and installs
|
||||
fake NVIDIA modules for every kernel. What no VM can show (real driver, the picture, Big Picture on a real GPU) is checked on the real PC.
|
||||
|
||||
| # | Step | Expect |
|
||||
|---|---|---|
|
||||
| N1 | `--defaults --list` and `--backend status` with the fake GPU (`nvidia/10-n1-menu.sh`) | `nvidia`, `bigpicture` (parent `nvidia`), `single` offered and preselected; `gaming`, `boot`, `glyphs` hidden; without the fake GPU the conversion is offered and `nvidia` is not |
|
||||
| N2 | `--defaults --options nvidia,bigpicture,single` (`nvidia/20-n2-n5-lifecycle.host.sh`) | exit 0; Steam installed; unit with `-gamepadui` enabled; `loginMode=emptySession`; parameters in `/etc/default/limine` and `/boot/limine.conf`; early-load file, hook and script; modules in the initramfs; SDDM enabled and `zzz-steamify-autologin.conf` (Plasma session) |
|
||||
| N3 | reboot | Plasma straight in (no greeter), parameters on `/proc/cmdline`, the Steam unit started, `loginMode` kept |
|
||||
| N4 | `--defaults --options notify` | exit 0; Steam removed (Steamify installed it), unit and autologin file gone, `loginMode` back to not set, parameters/early-load/hook gone, plasma-login-manager the login manager again |
|
||||
| N5 | reboot | Plasma up through the test autologin, no NVIDIA parameters |
|
||||
| N6 | real RTX 5080 PC | **done by hand 2026-10-01** (earlier prototype): Big Picture on the Plasma desktop smooth and clean; the apply/boot of the final component is the user's next step |
|
||||
|
||||
### F2.10.0 Extended controller support (`feature/extended-controller-support`; suite `cli`, block `60-c1-controllers.sh`)
|
||||
|
||||
Opt-in item: `xpadneo-dkms`, `xone-dkms` and `xone-dongle-firmware` from the CachyOS repo, DKMS-built for every kernel. The VM has no
|
||||
dongle or controller: it covers the packages, the headers and the builds, not the hardware.
|
||||
|
||||
| # | Step | Expect |
|
||||
|---|---|---|
|
||||
| C1 | `--defaults --options extended_controller_support` | exit 0; the three packages installed; `dkms status` shows xone and xpadneo installed for every kernel; the modules (`xone_dongle`, `hid_xpadneo`) exist for each |
|
||||
| C2 | the same again | quiet, nothing installed again |
|
||||
| C3 | `--defaults --options notify` | exit 0; the three packages removed again |
|
||||
| C4 | real PC with the Xbox dongle | **by hand, 2026-10-01 earlier**: the dongle works with the AUR `xone-dkms-git` (modules `xone_dongle`, `xone_gip_gamepad` loaded); status counts `xone-dkms-git` as on |
|
||||
|
||||
### F2.7.0 `--defaults --options` / `--boot`
|
||||
|
||||
| # | Step | Expect |
|
||||
@@ -142,3 +170,5 @@ and started with `--fremont`. Automated: `scripts/vmtest.sh` (see the vm-install
|
||||
| 2026-09-29 | Steamify 2.9.0 (`steamify-cachyos` main), ISO `feat/steamify` with PR #2 (2026.09.29), dev `main` 5b867f8; on the PC (WSL2) | everything automated: B1-B8 (3 loaders), cli, menu, hw, installer, toggles (`scripts/vmtest.sh`, parallel, `MAX_PARALLEL=3`) | **328 pass, 0 fail** (toggles 42 +1 expected skip, hw 70, cli 55, menu 36, installer 4, Limine 41, systemd-boot 40, GRUB 40) in 18 minutes: the first complete parallel run. Found on the way: systemd-boot had no EFI boot entry (installer's `bootctl` in a chroot), fixed in the ISO (PR #2); `vminstall.sh` fixes for parallel installs and a root host user |
|
||||
| 2026-09-29 | ISO `feat/steamify` + PR #3 (`/var/log`), dev `main` with the B1 boot entry check | B1-B8 | Limine 43 / GRUB 42 pass (boot entry check passes: `Limine`, `cachyos`). systemd-boot (reinstalled): 36 pass, 8 fail, all CEC: the driver download got HTTP 429 from GitHub (rate limit); boot entry check passes (`Linux Boot Manager`); `/var/log/steamify-install.log` and `steamify-bootentry.log` readable after boot |
|
||||
| 2026-09-29 | Steamify `release/2.9.1` (CEC driver cache), ISO `feat/steamify` (PRs #2, #3), dev `main` | everything automated incl. hw block 50 (CEC cache) and the B1 boot entry check | **341 pass, 0 fail** in 19 minutes (toggles 42 +1 expected skip, hw 77, cli 55, menu 36, installer 4, Limine 43, systemd-boot 42, GRUB 42) |
|
||||
| 2026-09-30 | Steamify 2.9.6 (`steamify-cachyos` main `d93f9ea`), the official ISO `steamify-cachyos-2.9.6-260930-x86_64.iso` from git.upriser.nl (sha256 `4a94f308…aec41`), dev `main`; on the PC, headless (`CI=1`/`VM_HEADLESS=1`), `MAX_PARALLEL=5` | everything automated: B1-B8 (3 loaders, `--install` from the new ISO), cli, menu, hw, installer, toggles (base VM from the same ISO with `VM_STEAMIFY=skip`) | **341 pass, 0 fail** (toggles 42 +1 expected skip, hw 77, cli 55, menu 36, installer 4, Limine 43, systemd-boot 42, GRUB 42). Found on the way (test setup, not Steamify or the ISO): with five VMs at once the loaders' first boot took longer than `waitssh` waited (5 min), so all three stopped with `FAIL no SSH` although the VMs were up; `waitssh` now waits up to 15 minutes and the loaders were run again (install kept) |
|
||||
| 2026-10-01 | Steamify `feature/extended-controller-support` (7dae14c; on top of `feature/nvidia-gaming-fix` d0e4d8c, 2.9.7), plain CachyOS ISO 260809 (VM `~/vms/steamify-vm`, `vminstall.sh --iso`), dev `main` + the nvidia suite; on the PC (native CachyOS, KVM), headless | N1-N5 (new suite `nvidia`), C1-C3 (cli block 60), R1.1-R1.6/R1.10, H1-H5 and the CEC/CEC cache blocks, R2.1, toggles | **269 pass, 0 fail**: cli 65, nvidia 43, menu 37, hw 78, installer 4, toggles 42. Found on the way (test side, not Steamify): R1.1 and H3 pressed menu rows by number and the new Extended controller support row shifted them (now by name); the N4 check for the parameter in `/boot/limine.conf` must ignore snapper's snapshot entries, which keep the command line of their time. The kernel part (parameters, early-load file, hook, initramfs) behaves in a real Limine VM; the real driver and picture are only checked on the RTX 5080 PC |
|
||||
@@ -1,28 +1,20 @@
|
||||
# TODO
|
||||
|
||||
## GitHub Actions: run the boot loader test in CI
|
||||
## Tests in CI: dropped 2026-09-30, the VM tests run locally
|
||||
|
||||
Goal: every push/PR (and on demand) runs the whole automated test (`scripts/vmtest.sh`, see the next
|
||||
section: boot loaders plus every suite) on runners, one job per suite or loader, and fails on any `FAIL` line.
|
||||
Public repos, so the free Linux runners with KVM apply. Work on `feature/ci-bootloader-test`,
|
||||
PR into the release branch. Tick items off as they're done.
|
||||
Decision: `scripts/vmtest.sh` runs on the PC before the release PR, not on GitHub or Gitea runners (too slow, too heavy, and
|
||||
not reliable: some GitHub runners had no `/dev/kvm`, nested virtualization made installs slow, the 3 GB ISO had to come
|
||||
from the mirror on every run; the Gitea machine has 8 threads). The attempt (steamify-cachyos PR #66, closed, branch
|
||||
`feature/vmtest-ci`) left these behind: `vminstall.sh` reads the ISO with `bsdtar` (no loop devices), `CI=1` makes it
|
||||
headless, the VM's ssh key is looked up at every call, an aborted test counts as a failure, progress lines while a test runs.
|
||||
|
||||
- [x] 1. `run.sh`: headless mode (`VM_HEADLESS=1` -> `-display none`, plain virtio-vga); still to do: make `vmtest.sh` and `vmbootloadertest.sh` headless by default (`--window` opts out, a log Konsole opens on a desktop, CI opens none) and copy the repo's run.sh into `$VM_DIR` before starting
|
||||
- [ ] 2. `vminstall.sh`: read the ISO's kernel/initramfs without `udisksctl` (bsdtar/7z when there is no session)
|
||||
- [ ] 3. `vminstall.sh` / `vmbootloadertest.sh`: no `/dev/tty` prompts and no `pgrep` on the whole host in CI (`CI=1`)
|
||||
- [ ] 4. Where the ISO comes from: the newest ISO release on git.upriser.nl (the Gitea mirror of
|
||||
`theupriser/steamify-cachyos-live-iso` builds it and attaches it to the tag's release, see the
|
||||
`steamify-iso-release` skill; GitHub's release links to it), or a `workflow_dispatch` input (release tag / URL)
|
||||
- [ ] 5. `.github/workflows/bootloader-test.yml`: matrix over `limine, systemd-boot, grub`; steps: install
|
||||
qemu + ovmf, enable /dev/kvm, fetch the ISO, run the script, upload `~/vms/bl-<loader>.test.log` as an artifact
|
||||
- [ ] 6. Runner limits: disk (sparse 60 GB qcow2, free space check), RAM (8 GB VM on a 16 GB runner), timeout (60 min)
|
||||
- [ ] 7. Cache the pacman packages between runs (`actions/cache` on `~/vms/pkg-cache`, `VM_CACHE`)
|
||||
- [ ] 8. Trigger it once on the branch, fix what the runner shows; note the run time in the skill
|
||||
- [ ] 8b. Second job, `--fremont` hardware tests from TESTPLAN.md section H (LED driver, CEC with vivid,
|
||||
BIOS dry-run, boot into desktop/gaming and reboot, power-off module): guest-side, so they run on a runner too;
|
||||
needs a way to check without screenshots (gaming mode doesn't render)
|
||||
- [ ] 9. `vm-install` skill + `vmtest.sh` header: mention the workflow, and that the advertised-loader check fails CI when a loader has no test
|
||||
- [x] 10. TESTPLAN.md: section B for the boot loader test (B1-B8), pointing at `scripts/vmtest.sh`
|
||||
- [x] TESTPLAN.md: section B for the boot loader test (B1-B8), pointing at `scripts/vmtest.sh`
|
||||
- [x] `vmbootloadertest.sh --quick [--generic]`: only what the ISO's install must get right (B1-B5) on a Steam Machine VM
|
||||
(`--fremont`) or a plain PC (`--generic`: the Steam Machine items and modules must be absent)
|
||||
- [ ] A helper that fetches the newest ISO release of the mirror (git.upriser.nl) into
|
||||
`../steamify-cachyos-live-iso/out/desktop/`, for `vmtest.sh --install` (the ISO is no longer kept locally)
|
||||
- [ ] Document `--quick` / `--generic` in the `vm-install` skill and TESTPLAN.md (which B rows it covers)
|
||||
- [ ] Steamify `AGENTS.md`: "run `scripts/vmtest.sh` before the release PR into main" (decided 2026-09-30)
|
||||
|
||||
## Full automated test: everything in TESTPLAN.md that needs no person
|
||||
|
||||
@@ -71,7 +63,8 @@ Where the time goes: boot loader VMs ~3 min each, every suite block restores a s
|
||||
(`view_start` returns early; watch with `screen -r vmtest` or `tail -f ~/vms/test.log`), a VM for the user gets a
|
||||
window through WSLg (see the wsl-build-host skill). Still to do: a first full `vmtest.sh` run there
|
||||
- [x] R1c. `vminstall.sh` without udisks (WSL): `losetup -P` + `mount` when `udisksctl` is missing and it runs as root
|
||||
- [ ] R2. With 64 GB and 8c/16t: try `MAX_PARALLEL=4` and 8 GB VMs (`VM_MEM=8G`)
|
||||
- [x] R2. `MAX_PARALLEL=5` ran fine on the PC (9800X3D, 8c/16t, 64 GB; reported 2026-09-30). The default stays 3 for smaller
|
||||
machines. Not tried: 8 GB VMs (`VM_MEM=8G`).
|
||||
|
||||
## Found 2026-09-29 (first full run on the PC)
|
||||
|
||||
|
||||
+4
-2
@@ -4,7 +4,8 @@
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
mirror="${MIRROR:-https://nl.mirror.cx/cachyos}"
|
||||
# CachyOS's own mirror: nl.mirror.cx gave about 1 MB/s here, this one 80 MB/s (MIRROR=... to use another).
|
||||
mirror="${MIRROR:-https://mirror.cachyos.org}"
|
||||
|
||||
# The download page embeds the current ISO URL; take the release from it.
|
||||
release="$(curl -fsL https://cachyos.org/download/ |
|
||||
@@ -22,8 +23,9 @@ if [[ -f cachyos.iso && "$(cat cachyos.iso.version 2>/dev/null)" != "$name" ]];
|
||||
rm -f cachyos.iso
|
||||
fi
|
||||
|
||||
curl -fL -C - -o cachyos.iso "$url"
|
||||
# The version is written before the download: a partial file of this release is resumed, not deleted as "an older release".
|
||||
echo "$name" > cachyos.iso.version
|
||||
curl -fL -C - -o cachyos.iso "$url"
|
||||
|
||||
echo "Verifying checksum..."
|
||||
curl -fsL "$url.sha256" | awk '{print $1" cachyos.iso"}' | sha256sum -c
|
||||
@@ -0,0 +1,70 @@
|
||||
# NVIDIA fix: results on the RTX 5080 PC (2026-10-01)
|
||||
|
||||
PC: RTX 5080 (GB203, 10de:2c02) + AMD Granite Ridge iGPU, MSI MAG 341C OLED on the NVIDIA DP-1 (3440x1440, 175 Hz),
|
||||
CachyOS, Limine, kernel 7.2.8-1-cachyos, nvidia-open 615.71.09, gamescope 3.16.31-1, gamescope-session-cachyos 1.1.6-1.
|
||||
|
||||
## Result: the kernel-parameter fix does not cure the picture
|
||||
- Baseline (before): gaming mode corrupted without HDR; with HDR it worked but not at 175 Hz and not full screen.
|
||||
- After `apply` + reboot (`modeset = Y`, `fbdev = Y`, NVIDIA modules in the initramfs): flickers heavily, artifacts, still no 175 Hz.
|
||||
`modeset`/`fbdev` were already `Y` live before the fix (driver 615), so the fix changed little.
|
||||
- Cause is not the parameters: NVIDIA's open bug "display modes above 2560x1440@120 with HDR cause flickering/corruption within
|
||||
gamescope-session" (internal bug 5240452, April 2025, no fix as of March 2026; 555 up to 595+, RTX 3070 Ti/4090/5090; corruption is
|
||||
display-side only):
|
||||
https://forums.developer.nvidia.com/t/display-modes-above-2560x1440p-120hz-with-hdr-enabled-cause-flickering-corruption-within-gamescope-session/295314
|
||||
|
||||
## Bugs found in the fix on this PC (fixed in commit a5e9015 on feature/nvidia-gaming-fix)
|
||||
- CachyOS writes Limine's line as `KERNEL_CMDLINE[default]+="..."`; the sed only matched `=`, so apply stopped with "Couldn't add the NVIDIA parameters".
|
||||
- The kernel treats `nvidia_drm.modeset=1` and `nvidia-drm.modeset=1` alike; the check only knew the hyphen.
|
||||
- tests/nvidia-hardware-test.sh did not set `SCRIPT_DIR`, so patch_file read `/patches/...`.
|
||||
|
||||
## What gamescope did (journal, gaming mode)
|
||||
- Picks the RTX 5080 (card1), DP-1, mode list has 3440x1440@175/144/100. It selected @60 by default; with
|
||||
`-W 3440 -H 1440 -r 175` added (a copy of /usr/lib/steamos/gamescope-session, whose last line is `-O ... \` so args need a copy)
|
||||
it selected @175 and did not crash, but the picture was the same. Steam then sets the Xwayland size to 1920x1080 (not full screen).
|
||||
- `vkGetPhysicalDeviceFormatProperties2 returned zero modifiers` for 2 16-bit formats: harmless here.
|
||||
- A gamescope SIGABRT (`double free or corruption`) at session exit, backtrace through libnvidia-eglcore and libvulkan_radeon.
|
||||
- The PC froze once and was reset after a gaming-mode session (no kernel error logged).
|
||||
|
||||
## What works: nested gamescope inside KDE (Wayland), borderless
|
||||
- `gamescope -W 3440 -H 1440 -r 175 -f ...`: artifacts once the window is focused and fullscreen (unfocused it is fine).
|
||||
Hypothesis, not proven: KWin's direct scanout of the fullscreen window.
|
||||
- `gamescope -W 3440 -H 1440 -r 175 -b -e --hdr-enabled -- steam -gamepadui` (borderless): clean, full screen, about 175 Hz.
|
||||
- So on NVIDIA the separate gamescope session (the SteamOS conversion) is blocked by the driver bug; a nested borderless gamescope works.
|
||||
Whether Steamify gets a nested option for NVIDIA is the user's decision.
|
||||
|
||||
## Cause confirmed: KWin's direct scanout; a session without Plasma works (2026-10-01, later)
|
||||
- A TTY session of only `kwin_wayland --drm` + `gamescope -b` + `steam -gamepadui` (no Plasma shell, no panel) artifacted too
|
||||
(KWin hands the covering window straight to the display).
|
||||
- Same session with `KWIN_DRM_NO_DIRECT_SCANOUT=1` (exists in KWin 6.7.5's libkwin; not in the kwin_wayland binary's strings):
|
||||
NO artifacts, full screen, about 175 Hz (gamescope logs `Changed refresh to: 174.962hz`). Animations felt a bit clunky (cause unknown:
|
||||
an extra composition step without scanout, no CAP_SYS_NICE for gamescope, no VRR, nested frame pacing; other switches to try:
|
||||
`KWIN_DRM_DISABLE_TRIPLE_BUFFERING`, `KWIN_DRM_PREFER_COLOR_DEPTH`).
|
||||
- Launcher used for the test: `~/.local/bin/steamify-nvidia-session-test` (run from a free TTY; KWin as the compositor,
|
||||
`gamescope -W 3440 -H 1440 -r 175 -b -e --hdr-enabled -- steam -gamepadui`, a watchdog ends it after 90 s).
|
||||
Lesson: the first version's timeout left KWin/gamescope/Steam running (the cleanup came after a pipeline that waits for them);
|
||||
`pkill -f '<pattern>'` in a command that contains the pattern kills the caller.
|
||||
- Open: a real session entry (`/usr/share/wayland-sessions/`, needs sudo) and the product decision: an NVIDIA session mode in Steamify
|
||||
instead of the gamescope DRM session. Not built, not in the product repo.
|
||||
|
||||
## Smoothness: the TTY-only KWin session stutters, Plasma does not; Big Picture in Plasma is perfect (2026-10-01, evening)
|
||||
- TTY session (`kwin_wayland --drm` under `dbus-run-session`, no Plasma): the mouse and windows stutter every 1-2 s, with gamescope
|
||||
(clunky) and without it (`steam -gamepadui` as KWin's only client). Same in both: not gamescope, not Steam. Plasma's own KWin is smooth.
|
||||
- Tried without effect: `KWIN_DRM_DISABLE_TRIPLE_BUFFERING=1`. Measured: the test KWin used about 2% CPU, no spikes, but its main thread
|
||||
dropped to 0% about every 2 s (blocked, not busy); scheduling (RR main thread, nice -12) and capabilities equal to Plasma's KWin;
|
||||
NVIDIA is boot_vga; no relevant environment differences found. Cause of the stutter not found.
|
||||
- Plain `steam -gamepadui` (Big Picture, no gamescope) in the normal Plasma session: **perfect** (smooth, no artifacts, no env var needed).
|
||||
- Direction: for NVIDIA PCs a Plasma session that shows only Steam's Big Picture (no desktop, no panel) instead of the gamescope
|
||||
session. Gives up gamescope's features (HDR handling, FSR, overlay; most `-steamos3` menus need gamescope).
|
||||
|
||||
## Plasma session with Big Picture started at login: works (2026-10-01, night)
|
||||
- `~/.config/autostart/steamify-bigpicture.desktop` (`Exec=steam -gamepadui`) in the normal Plasma Wayland session, SDDM autologin set to
|
||||
`plasma.desktop` (`pkexec /usr/lib/steamos/steam-set-session plasma.desktop`): Big Picture opens by itself, smooth, no artifacts, no
|
||||
KWin environment variables needed. Exiting Steam leaves the Plasma desktop, no relogin.
|
||||
- A separate session entry (prototype in the scratchpad, not installed: `steamify-bigpicture-session` marker + autostart helper, session
|
||||
file in `/usr/share/wayland-sessions`) only decides WHEN Big Picture starts; the plain autostart gave the same result.
|
||||
|
||||
## State of the PC after the test (to undo)
|
||||
- The fix is applied (Limine file backup `/etc/default/limine.bak-gamescope-wizard`, early-load file, pacman hook): undo in INSTRUCTIONS.md.
|
||||
- Test launcher `~/.local/bin/steamify-nvidia-session-test`, log `~/steamify-nvidia-session-test.log`.
|
||||
- User override of the gaming session: `~/.config/systemd/user/gamescope-session.service.d/steamify-nvidia-test.conf` and
|
||||
`~/.local/share/steamify/nvidia-test/`.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Testing the NVIDIA fix on a real PC
|
||||
|
||||
For the PC with an RTX 5080 (or any RTX 20 series or newer card) that shows a corrupted picture when
|
||||
gaming mode (gamescope) starts. Product branch: `feature/nvidia-gaming-fix` in steamify-cachyos, not released.
|
||||
This file lives in steamify-cachyos-dev (`nvidia/INSTRUCTIONS.md`); background and open work: `nvidia/TODO.md`; research
|
||||
with sources: `nvidia/RESEARCH.md` (github.com/theupriser/steamify-cachyos-dev).
|
||||
|
||||
## What the fix does
|
||||
With a supported NVIDIA GPU (RTX 20 series or newer, same check as the VRAM booster) and its driver installed it
|
||||
- adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the kernel command line (Limine, systemd-boot or GRUB;
|
||||
the file is backed up as `<file>.bak-gamescope-wizard`),
|
||||
- loads the NVIDIA modules in the initramfs, but only while every installed kernel has them (a pacman hook,
|
||||
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, decides again at every kernel change),
|
||||
- rebuilds the initramfs and boot entries and checks that the parameters really are in them.
|
||||
It takes effect after a reboot. Older cards (GTX 10 series and older) are left alone.
|
||||
|
||||
## Before you start
|
||||
- CachyOS with the NVIDIA driver installed (`nvidia-open`), a user with sudo, `git`.
|
||||
- Be at the PC and able to see the screen: the last step needs your eyes.
|
||||
- Know the way back (below) in case the PC doesn't boot to a picture: a TTY (Ctrl+Alt+F3) or the boot menu's
|
||||
other kernel entry.
|
||||
|
||||
## Steps
|
||||
1. Get the code:
|
||||
```
|
||||
git clone -b feature/nvidia-gaming-fix https://github.com/theupriser/steamify-cachyos
|
||||
cd steamify-cachyos
|
||||
```
|
||||
(An existing checkout: `git fetch && git checkout feature/nvidia-gaming-fix && git pull`.)
|
||||
2. Look first, change nothing:
|
||||
```
|
||||
bash tests/nvidia-hardware-test.sh check
|
||||
```
|
||||
3. Apply the fix (asks for your sudo password), then **reboot**:
|
||||
```
|
||||
bash tests/nvidia-hardware-test.sh apply
|
||||
```
|
||||
4. After the reboot, check again:
|
||||
```
|
||||
bash tests/nvidia-hardware-test.sh check
|
||||
```
|
||||
5. Start gaming mode, look at the screen, then (from the desktop or a TTY):
|
||||
```
|
||||
bash tests/nvidia-hardware-test.sh visual
|
||||
```
|
||||
It asks whether the picture was clean and for one line on what you saw.
|
||||
6. Send back `~/steamify-nvidia-report.txt` (every run adds to it), or start a new session in the checkout and
|
||||
say "read nvidia/TODO.md in steamify-cachyos-dev and the report".
|
||||
|
||||
(`./steamify.sh` from the same checkout also applies the fix, automatically, as part of the SteamOS conversion:
|
||||
there is no menu option for it yet. The script above shows more.)
|
||||
|
||||
## Reading `check`
|
||||
| Line | Good result | If not |
|
||||
|---|---|---|
|
||||
| `PASS a supported NVIDIA GPU ... is detected` | your 5080 | `FAIL ... older than RTX 20`: the card is skipped on purpose. `FAIL no NVIDIA GPU with its driver`: driver not installed (nouveau?) |
|
||||
| `NVIDIA PCI device id 0x... (not on a legacy list ...)` | RTX 20 or newer | on a legacy list: older card |
|
||||
| `no chwd legacy lists found` | (note only) | the check cannot tell old from new cards; every card counts as supported. Tell me, it's open item 4 in `nvidia/TODO.md` |
|
||||
| `PASS nvidia-drm.modeset=1 is on the running kernel's command line` (and `fbdev=1`) | after step 3 and the reboot | "in the boot loader's file but not booted yet": reboot, or the boot entry used is another one |
|
||||
| `PASS nvidia_drm modeset = Y` (and `fbdev = Y`) | after the reboot | `unreadable`: it needs sudo, enter the password |
|
||||
| `... early-load drop-in is used / skipped` | note only: skipped means a kernel without the NVIDIA modules is installed | nothing to do |
|
||||
|
||||
## Reading the result
|
||||
- Parameters on, `modeset = Y`, `fbdev = Y`, picture clean: the fix works.
|
||||
- Parameters on and `Y`, picture still corrupted: not this fix. The report has the gamescope and NVIDIA log lines and
|
||||
the versions of `nvidia-open`, `nvidia-utils`, `gamescope` and `gamescope-session-cachyos`: the cause is probably the
|
||||
gamescope/driver combination for Blackwell (see `nvidia/RESEARCH.md`).
|
||||
- No picture at all after the reboot: undo it (next section) from a TTY or the other kernel entry, and send the report.
|
||||
|
||||
## Undo
|
||||
Turning the SteamOS conversion off in the wizard removes the fix too. On its own, from the checkout:
|
||||
```
|
||||
SCRIPT_DIR=$PWD bash -c 'source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; nvidia_disable'
|
||||
```
|
||||
It removes the parameters, the early-load file, the pacman hook and its script, and rebuilds the boot entries (reboot after).
|
||||
By hand: delete ` nvidia-drm.modeset=1 nvidia-drm.fbdev=1` from `/etc/default/limine` (`KERNEL_CMDLINE[default]`),
|
||||
`/etc/sdboot-manage.conf` (`LINUX_OPTIONS`) or `/etc/default/grub` (`GRUB_CMDLINE_LINUX_DEFAULT`), or restore the
|
||||
`.bak-gamescope-wizard` copy next to it; remove `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`,
|
||||
`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook` and `/usr/local/libexec/steamify-nvidia-initramfs`; then
|
||||
`sudo limine-mkinitcpio` (Limine) or `sudo mkinitcpio -P` and `sudo sdboot-manage gen` / `sudo grub-mkconfig -o /boot/grub/grub.cfg`.
|
||||
|
||||
## What is and isn't proven
|
||||
Proven in VMs (QEMU/KVM, CachyOS ISO 260809): the parameters land and survive a reboot on Limine, systemd-boot and GRUB;
|
||||
disabling restores the original; on Limine the pacman hook keeps the early-load file right across kernel reinstalls
|
||||
(with fake NVIDIA modules). Not proven: that the fix cures the 5080's picture, the real NVIDIA modules in the
|
||||
initramfs, DKMS hook order, systemd-boot/GRUB with a pacman transaction, and the RTX 20+ check against a real chwd list.
|
||||
Unit test (no hardware): `bash tests/nvidia-test.sh`.
|
||||
@@ -0,0 +1,64 @@
|
||||
# NVIDIA and gamescope: research notes (for steamify-cachyos branch `feature/nvidia-gaming-fix`)
|
||||
|
||||
Written 2026-10-01 for the NVIDIA fix (`lib/nvidia.sh`). Delete the `nvidia/` folder when the feature is released, or move what is still useful to steamify-cachyos' `TECHNICAL.md`.
|
||||
"Verified" means seen in this session (a VM run or a fetched page); the rest is from search results or memory.
|
||||
|
||||
## The user's PC
|
||||
RTX 5080 (Blackwell). Blackwell only works with NVIDIA's open kernel modules (`nvidia-open`), driver 570+.
|
||||
The corrupted picture at gaming mode start is not diagnosed yet: the fix adds kernel parameters, the real cause
|
||||
may be the gamescope/driver combination. `tests/nvidia-hardware-test.sh` collects the facts.
|
||||
|
||||
## What the fix changes and why (reasoning, not proven for gamescope)
|
||||
- gamescope runs the display itself through DRM/KMS. With NVIDIA that needs `nvidia-drm.modeset=1`; `nvidia-drm.fbdev=1`
|
||||
gives the console a framebuffer from `nvidia-drm`, so the hand-off from the console to gamescope is clean.
|
||||
- Loading the NVIDIA modules in the initramfs (early KMS) only changes how early boot looks (native resolution,
|
||||
splash, passphrase prompt), not speed. It is not needed for gamescope, which starts after login (believed, not proven).
|
||||
- No source found that mentions these parameters for gamescope; the fix is a standard NVIDIA/Wayland setup, applied
|
||||
automatically. Whether it cures the 5080's picture is only known after `tests/nvidia-hardware-test.sh`.
|
||||
|
||||
## Which cards (decision 2026-10-01: RTX 20 series or newer only, same check as the VRAM booster)
|
||||
The code skips a card whose PCI id is on chwd's legacy lists (`vram_nvidia_legacy_id`); the notes below are why older
|
||||
cards are not promised.
|
||||
- Open kernel modules: Turing (RTX 20, GTX 16) and newer only; they need the GSP processor first built into Turing.
|
||||
Maxwell, Pascal and Volta (GTX 900/10 series, Titan V) only work with the proprietary driver, whose legacy branch
|
||||
is 580. Source: [NVIDIA README, open kernel modules](https://download.nvidia.com/XFree86/Linux-x86_64/560.35.03/README/kernel_open.html),
|
||||
[NVIDIA datacenter driver guide, kernel modules](https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/kernel-modules.html).
|
||||
- `nvidia-drm.modeset` and `fbdev` are options of the `nvidia-drm` module in both flavours, so the fix applies to
|
||||
any card whose driver provides `nvidia_drm` (what `nvidia_present` tests: GPU vendor 0x10de + `modinfo nvidia_drm`).
|
||||
Whether gamescope then works on an older card is a different question, and no source says the fix helps there.
|
||||
- Not NVIDIA's proprietary driver: nouveau has no `nvidia_drm`, so the fix does nothing. The CachyOS handheld ISO boots
|
||||
GTX 10xx and older with nouveau until the NVIDIA driver is installed
|
||||
([CachyOS forum](https://discuss.cachyos.org/t/information-experimental-cachyos-handheld-edition/203)).
|
||||
|
||||
## Known gamescope problems that are not this fix
|
||||
- **GTX 1050 Ti (Pascal), driver 580.119.02, gamescope newer than 3.16.16:** the CachyOS handheld session fails to start when
|
||||
a display is on the GPU's HDMI port (back to the TTY, loop). Workarounds: downgrade `gamescope` and `lib32-gamescope`
|
||||
to 3.16.16, or use the motherboard's video port. Fixed upstream? unknown.
|
||||
[CachyOS forum](https://discuss.cachyos.org/t/no-display-on-cachyos-handheld-edition-on-nvidia-with-gamescope-3-16-16/20935)
|
||||
- **VRS on PCs:** CachyOS' gamescope-session enables variable rate shading (`STEAM_USE_DYNAMIC_VRS=1`,
|
||||
`RADV_FORCE_VRS_CONFIG_FILE`, `echo 1x1 > ...` in `/usr/lib/steamos/gamescope-session`). It broke rendering (missing
|
||||
floors/lighting, bad post-processing) on a PC with an AMD RX 6800 XT. RADV is AMD's driver: not the NVIDIA corruption.
|
||||
Workaround: comment those three lines, or per game `env -u RADV_FORCE_VRS_CONFIG_FILE STEAM_USE_DYNAMIC_VRS=0 %command%`.
|
||||
[CachyOS forum](https://discuss.cachyos.org/t/cachyos-gamescope-session-asset-missing-vrs-fix/34971)
|
||||
- gamescope's DRM backend needs Vulkan DRM format modifiers; with the open Mesa driver NVK that came in Mesa 24.1
|
||||
([GamingOnLinux](https://www.gamingonlinux.com/2024/05/nvk-driver-gets-drm-format-modifiers-to-work-with-gamescope-in-mesa-24-1)).
|
||||
The proprietary driver had format-modifier trouble with gamescope too (GitHub issues
|
||||
[ValveSoftware/gamescope#1662](https://github.com/ValveSoftware/gamescope/issues/1662),
|
||||
[#1516](https://github.com/ValveSoftware/gamescope/issues/1516): titles seen only, not read).
|
||||
|
||||
## What was verified in VMs (QEMU/KVM, CachyOS ISO 260809)
|
||||
- Kernel parameters land and survive a reboot on Limine, systemd-boot and GRUB; disable restores the original.
|
||||
- Limine's tool is a compiled program: an appended `KERNEL_CMDLINE[default]+=" ..."` line was pasted into the kernel
|
||||
command line as text; the fix edits the existing `KERNEL_CMDLINE[default]="..."` line.
|
||||
- `mkinitcpio` fails on a MODULES entry a kernel lacks; `limine-mkinitcpio` then skips that kernel's initramfs and boot
|
||||
entry (parameters included); systemd-boot/GRUB image: "may not be complete" (not run with failing modules).
|
||||
- Real CachyOS/Limine pacman hooks: `10-limine-snapper-lock`, `60-limine-mkinitcpio-remove-pre`, `60-mkinitcpio-remove`,
|
||||
`80-limine-efi-deploy`, `90-limine-mkinitcpio-remove-post`, `90-mkinitcpio-install`; Steamify's hook is `85-`
|
||||
(DKMS's is `71-dkms-install`, not installed in the VM). A mirror older than the ISO "downgrades" kernels on reinstall.
|
||||
- The hook keeps the early-load drop-in right across kernel changes (see `nvidia/TODO.md`).
|
||||
|
||||
## Still unknown (needs the hardware)
|
||||
- Does the fix cure the 5080's corrupted picture? Which gamescope/driver versions does the PC have?
|
||||
- Does it help, harm or do nothing on Maxwell/Pascal/Volta cards? No older card available yet.
|
||||
- Real NVIDIA modules in the initramfs (VMs only had renamed fake modules); DKMS hook order on a PC with
|
||||
`nvidia-open-dkms`.
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
# TODO: NVIDIA (status 2026-10-01, evening: READ THIS FIRST, the sections below are the older plan)
|
||||
|
||||
Version: bumped to **2.10.0** (2026-10-01, "chore: Version 2.10.0" on `feature/nvidia-gaming-fix`; `feature/extended-controller-support` is stacked on it).
|
||||
The old plan below says 2.9.7 / `release/2.9.7`: read that as 2.10.0 / `release/2.10.0`, which doesn't exist yet (create it from `main` when releasing).
|
||||
|
||||
The kernel-parameter fix did not cure gamescope's picture; the cause is NVIDIA's own bug (see `HARDWARE-RESULTS.md`). The product now does this
|
||||
instead (branch `feature/nvidia-gaming-fix`, 2.10.0, still behind `.no-release-yet`):
|
||||
- On an NVIDIA PC the SteamOS conversion (`gaming`, `boot`, `glyphs`) is hidden (shown only while already on, so it can be turned off).
|
||||
- `nvidia` "Gaming on NVIDIA": Steam installed when missing, started at login on the Plasma desktop (user unit); sub-option `bigpicture`
|
||||
(a checkbox, not yet the choice row "How should Steam start up: Normal / Big Picture"): `-gamepadui` + Plasma starts with an empty session.
|
||||
RTX 20+ also keeps the old kernel parameters and early-load initramfs (user asked for it: "it may need it").
|
||||
- `single` (single user mode) also works there: its own SDDM autologin into the Plasma session (`zzz-steamify-autologin.conf`).
|
||||
- Tested in VMs (QEMU/KVM, fake NVIDIA GPU through `NVIDIA_DRM_DIR`, fake modules): suite `nvidia`, TESTPLAN N1-N5, 43 pass; regression suites green.
|
||||
- Tested by hand on the RTX 5080 (earlier prototypes): Big Picture in the normal Plasma session smooth and clean; autologin and the final component NOT yet run there.
|
||||
Open: run the final wizard on the RTX 5080 PC (turn the conversion off, tick Gaming on NVIDIA + Single user mode, reboot); the real choice row
|
||||
instead of the checkbox (the choice row is hard-wired to `boot` in the TUI, the app and `--boot`); games don't start fullscreen under Plasma
|
||||
(idea: a KWin rule forcing fullscreen for `steam_app_*`, may bring the direct-scanout artifacts back: test on the PC); apps that start later
|
||||
(CachyOS Hello) may still cover Big Picture; hint in the menu on why the item is missing while the conversion is on; changelog hashes;
|
||||
screenshot retake and the ISO's installer page for the new rows before a release. Separate branch `feature/extended-controller-support`
|
||||
(xone dongle + xpadneo, opt-in) is stacked on this one.
|
||||
|
||||
# TODO: NVIDIA fix for gaming mode
|
||||
|
||||
Product code: branch `feature/nvidia-gaming-fix` in steamify-cachyos (github.com/theupriser/steamify-cachyos). These notes live here, in
|
||||
steamify-cachyos-dev, on purpose: they are not part of the product and must not be in its history. The branch only has
|
||||
a `.no-release-yet` marker pointing here.
|
||||
|
||||
When the feature is released, move what is still useful to steamify-cachyos' `TECHNICAL.md` and delete this folder (`nvidia/`).
|
||||
Written 2026-10-01 so a new session can pick this up.
|
||||
|
||||
## Problem
|
||||
A PC with an NVIDIA RTX 5080 (Blackwell, open kernel modules) shows a corrupted
|
||||
image when gaming mode (gamescope) starts. Cause not confirmed. Steamify had no
|
||||
NVIDIA handling at all. Likely: `nvidia-drm.modeset=1` / `nvidia-drm.fbdev=1`
|
||||
missing, or a gamescope/driver mismatch.
|
||||
|
||||
## What is built (all on the product branch, pushed)
|
||||
- `lib/nvidia.sh`: part of the SteamOS conversion (`gaming_enable` / `gaming_disable`).
|
||||
With an NVIDIA GPU + driver it adds `nvidia-drm.modeset=1 nvidia-drm.fbdev=1` to the
|
||||
kernel command line (Limine, systemd-boot, GRUB; backup first) and, only when every
|
||||
installed kernel has `nvidia_drm`, `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf`.
|
||||
Rebuilds initramfs + boot entries, verifies the config and the generated entries
|
||||
have the parameters (error otherwise). Undone on disable. Description: `TECHNICAL.md`.
|
||||
- `FEATURE_VERSION[gaming]=2.9.7` so installs that already have the conversion re-apply it.
|
||||
- Test hooks `NVIDIA_DRM_DIR`, `NVIDIA_MODULES_DIR`, `NVIDIA_LIMINE_CONF`,
|
||||
`NVIDIA_SDBOOT_DIR`, `NVIDIA_GRUB_CFG`: only set by tests; defaults are the real paths.
|
||||
|
||||
## Tested
|
||||
- `bash tests/nvidia-test.sh`: 22 checks against a fake RTX 5080 beside an iGPU, a stub
|
||||
`modinfo`, temp boot loader files. All pass.
|
||||
- Real VMs (QEMU/KVM, Limine, systemd-boot, GRUB): enable, reboot, kernel command line
|
||||
has the parameters; disable, reboot, original command line. All pass. Found and fixed:
|
||||
Limine pasted an appended `+=` line as text into the cmdline; a kernel without the
|
||||
NVIDIA modules made limine-mkinitcpio skip its boot entry.
|
||||
|
||||
## Kernel changes (done, VM-tested 2026-10-01, Limine)
|
||||
The early-load drop-in is kept right by a pacman hook (`patches/steamify-nvidia-initramfs.{sh,hook}`,
|
||||
installed by `nvidia_enable`, `/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`). Real pacman
|
||||
transactions in a Limine VM: the hook runs between "Updating module dependencies" and "Updating
|
||||
linux initcpios" (real hook names there: 60-*-remove, 80-limine-efi-deploy, 90-limine-mkinitcpio-remove-post,
|
||||
90-mkinitcpio-install; DKMS would be 71-): the drop-in is present while every kernel has the modules, removed
|
||||
when the LTS kernel loses them, back when they return; initramfs nvidia files 1 -> 5 -> 1 -> 5 -> 1
|
||||
(1 = baseline, 4 modules added); no ERROR/skipping in any rebuild; cmdline kept the parameters after a reboot;
|
||||
disable removes hook, script and drop-in. Found on the way: an empty hook/script was installed when
|
||||
`patch_file` failed (now an error). Only tested with fake modules (renamed copies of a small module), on
|
||||
Limine; systemd-boot and GRUB use the same hook but were not run with pacman transactions.
|
||||
|
||||
## Opt-out toggle (new request, 2026-10-01: not built yet)
|
||||
When a compatible NVIDIA card is listed there should be a menu option, on by default (opt-out), named
|
||||
"NVIDIA compatibility", as a sub-option of the SteamOS conversion, directly under "Boot into" (`boot`).
|
||||
Today the fix runs unconditionally inside `gaming_enable`/`gaming_disable`.
|
||||
- [ ] New component `nvidia` in `lib/menu.sh`: `COMPONENTS` right after `boot`, `PARENT[nvidia]=gaming`, `LABEL`,
|
||||
`FEATURE_VERSION[nvidia]`, `component_available` -> `nvidia_available` (= `nvidia_present`); not in
|
||||
`NO_PRESELECT` (ticked by default, `feature_new` ticks it for installs that already have the conversion).
|
||||
`nvidia_status` from the system (hook + parameters present), `nvidia_enable`/`nvidia_disable` = the code now
|
||||
called from `gaming_enable`/`gaming_disable` (remove those calls). Check `toggle_component` dependencies,
|
||||
`feature_record_unticked`, the plan texts ("This will: ...").
|
||||
- [ ] The app: `ui/qml/Texts.qml` item texts, `AppState.qml`, the screen rows, `lib/backend.sh` if it lists ids;
|
||||
`--defaults [--options <ids>]` (the Steam Machine ISO's installer pages: it names the ids) and `--skip`.
|
||||
- [ ] README rows/screenshot rule (a release that adds a menu row retakes `assets/screenshot-menu.png`), TECHNICAL.md,
|
||||
CHANGELOG, `tests/nvidia-test.sh` (status/enable/disable through the component), VM menu test in
|
||||
steamify-cachyos-dev (`share/vmtest/menu`, TESTPLAN.md row).
|
||||
- [x] What "compatible" means (decided 2026-10-01): RTX 20 series or newer, the same check as the VRAM booster
|
||||
(`vram_nvidia_legacy_id`: a card on chwd's legacy lists `/var/lib/chwd/ids/nvidia-*.ids` is older; without the
|
||||
lists every card counts). `nvidia_present` = such a card + `nvidia_drm` available; the toggle's `nvidia_available`
|
||||
is the same function. Older cards (GTX 10/9 series) are left alone: no promise they work with gamescope.
|
||||
|
||||
## Older cards and other research
|
||||
Decision 2026-10-01: support RTX 20 series or newer only, with the VRAM booster's check (done in `lib/nvidia.sh`).
|
||||
The user had hoped older GPUs would work too; not promised. Full notes with sources: **`nvidia/RESEARCH.md`**.
|
||||
Short version: open kernel modules need Turing+, Maxwell/Pascal/Volta need the proprietary driver (580 legacy branch);
|
||||
`nvidia-drm.modeset/fbdev` exist in both, so the fix applies to any card with `nvidia_drm`, but nothing found says gamescope
|
||||
works better or worse there (a GTX 1050 Ti has a known gamescope>3.16.16 start problem on HDMI, not ours). Cannot be promised:
|
||||
needs a test on a real older card. Design for the toggle: on by default for any card with `nvidia_drm`, the label says
|
||||
what it does, `tests/nvidia-hardware-test.sh` reports GPU and driver so results can be compared.
|
||||
|
||||
## Still to do
|
||||
1. [ ] **On the NVIDIA PC** (only place the real fix can be judged; the full steps, how to read the results and the undo
|
||||
are in `nvidia/INSTRUCTIONS.md`), from the steamify-cachyos checkout on that branch:
|
||||
`bash tests/nvidia-hardware-test.sh check` (before), `... apply` (asks sudo), reboot,
|
||||
`... check` (after: `nvidia_drm modeset/fbdev = Y`), boot gaming mode, then
|
||||
`... visual` (was the picture clean?). Everything goes to `~/steamify-nvidia-report.txt`:
|
||||
paste it into the session.
|
||||
2. [ ] If the parameters apply but the picture is still corrupted: look at the report's
|
||||
gamescope/NVIDIA log lines and the versions (`nvidia-open`, `nvidia-utils`, `gamescope`,
|
||||
`gamescope-session-cachyos`); the cause is then probably a gamescope/driver mismatch
|
||||
for Blackwell, not this fix.
|
||||
3. [ ] Not covered by any test: the early-load drop-in with the REAL NVIDIA modules (the VMs only have renamed
|
||||
fake ones), and systemd-boot/GRUB with a pacman transaction (only Limine was run).
|
||||
4. [ ] **Verify the RTX 20+ check on the PC** (decided 2026-10-01, only unit-tested with a fake chwd list; this laptop and the VMs
|
||||
have no `/var/lib/chwd/ids`): `bash tests/nvidia-hardware-test.sh check` prints the NVIDIA PCI id, whether it is on a chwd legacy
|
||||
list, and whether the lists exist at all. Expect for the RTX 5080: "supported", "not on a legacy list". If it says "no chwd
|
||||
legacy lists found" the check cannot tell old from new there (every card then counts as supported, like the VRAM booster):
|
||||
look at what `chwd`/`/var/lib/chwd/ids` provide on CachyOS and whether another source (the open-driver device list, the
|
||||
`nvidia-open` package) would be better for both the VRAM booster and this fix. Also try `check` on any older NVIDIA card
|
||||
that turns up (GTX 10/9 series): it must say "older than RTX 20 ... not applied" and `apply` must change nothing.
|
||||
5. [ ] Changelog: fill in the commit hashes of this feature's lines (next commit, per AGENTS.md).
|
||||
6. [ ] Build the opt-out toggle (section above) before release.
|
||||
7. [ ] When complete and tested: ask the user whether it may be released. On a yes delete
|
||||
`.no-release-yet` (and this folder in the dev repo), open the PR into `release/2.9.7` (local branch only so
|
||||
far, one commit `chore: Version 2.9.7`; push it then) and merge it. The user merges
|
||||
`release/2.9.7` into `main`.
|
||||
|
||||
## Working rules (steamify-cachyos `AGENTS.md` and this repo's `AGENTS.md`)
|
||||
- Never work on `main` or a `release/*` branch; no `Co-Authored-By` / "Generated with
|
||||
Claude" lines in commits or PRs. No git identity on the dev laptop: use
|
||||
`git -c user.name="Rick Peters" -c user.email="rickpeters@upriser.nl" commit`.
|
||||
- Don't push `release/2.9.7` before the PR (a push can start a dev ISO build).
|
||||
|
||||
## If the VM tests need repeating (dev laptop, Ubuntu)
|
||||
- `scripts/vminstall.sh` (steamify-cachyos-dev) with `VM_BOOTLOADER=limine|systemd-boot|grub`,
|
||||
`CI=1`, a short `VM_DIR` (`~/vms/...`: socket paths over 108 bytes fail) and `VM_SSH_KEY`.
|
||||
- This session's shell lacked the `kvm` group: run QEMU steps as `sg kvm -c "..."`.
|
||||
- `/tmp/vminstall-iso.lock` belongs to another user and there is no `bsdtar`: use a copy of
|
||||
`vminstall.sh` with another lock path and a `bsdtar` shim (Python `pycdlib` in a venv).
|
||||
- Delete everything afterwards (`~/vms` incl. `pkg-cache`, the 3 GB ISO, keys).
|
||||
+9
-2
@@ -17,8 +17,15 @@ VM_USER="${VM_USER:-theupriser}"
|
||||
VM_SSH_OPTS=(-o BatchMode=yes -o "UserKnownHostsFile=$VM_DIR/known_hosts" -o StrictHostKeyChecking=accept-new)
|
||||
if [[ -z "${VM_SSH_KEY:-}" && -f "$VM_DIR/ssh-key" ]]; then VM_SSH_KEY="$(cat "$VM_DIR/ssh-key")"; fi
|
||||
[[ -n "${VM_SSH_KEY:-}" ]] && VM_SSH_OPTS+=(-i "$VM_SSH_KEY" -o IdentitiesOnly=yes)
|
||||
vm_ssh() { ssh -p "$VM_PORT" "${VM_SSH_OPTS[@]}" "$VM_USER@$VM_HOST" "$@"; }
|
||||
vm_scp() { scp -q -P "$VM_PORT" "${VM_SSH_OPTS[@]}" "$@"; }
|
||||
# The VM's key, looked up at every call: vminstall.sh and vmbootloadertest.sh source this file before the key
|
||||
# exists or is chosen (a clean host has no other key the VM would accept).
|
||||
vm_key() {
|
||||
if [[ -n "${VM_SSH_KEY:-}" ]]; then printf '%s\n' "$VM_SSH_KEY"
|
||||
elif [[ -f "$VM_DIR/ssh-key" ]]; then cat "$VM_DIR/ssh-key"; fi
|
||||
}
|
||||
_vm_key_opts() { local k; k="$(vm_key)"; [[ -n "$k" ]] && printf '%s\n' -i "$k" -o IdentitiesOnly=yes; }
|
||||
vm_ssh() { local -a k; mapfile -t k < <(_vm_key_opts); ssh -p "$VM_PORT" "${VM_SSH_OPTS[@]}" "${k[@]}" "$VM_USER@$VM_HOST" "$@"; }
|
||||
vm_scp() { local -a k; mapfile -t k < <(_vm_key_opts); scp -q -P "$VM_PORT" "${VM_SSH_OPTS[@]}" "${k[@]}" "$@"; }
|
||||
|
||||
# One Konsole for every test run: it follows $TEST_LOG, which the test scripts append to.
|
||||
# Started only when there is a desktop, the run is headless and no such window exists.
|
||||
|
||||
+42
-14
@@ -5,8 +5,11 @@
|
||||
# the old drm.edid_firmware parameter), a kernel update, and a reboot into
|
||||
# each of the two kernels. Guest checks: share/bootloader-test/*.sh.
|
||||
# All loaders in one go: scripts/vmtest.sh.
|
||||
# scripts/vmbootloadertest.sh <limine|systemd-boot|grub> [--install] [--window]
|
||||
# scripts/vmbootloadertest.sh <limine|systemd-boot|grub> [--install] [--quick [--generic]] [--window]
|
||||
# --install first install the VM (scripts/vminstall.sh, from the Steamify ISO)
|
||||
# --quick only what the ISO's install must get right (B1-B5: boots through its own entry, OS name, loader,
|
||||
# Steamify's state and modules as the install left them): no steamify.sh run, kernel update or reboots
|
||||
# --generic with --quick: a plain PC, not a Steam Machine (no --fremont): its Steam Machine items must stay off
|
||||
# --window show the VM's window (default: headless, with a Konsole on the log when there is a desktop)
|
||||
# Env: VM_DIR (default ~/vms/bl-<loader>), VM_ISO (default: the newest ISO in
|
||||
# ../steamify-cachyos-live-iso/out/desktop), REPO (steamify-cachyos, 9p `repo`).
|
||||
@@ -15,35 +18,41 @@ set -uo pipefail
|
||||
here="$(cd "$(dirname "$0")" && pwd)"
|
||||
repo="$(cd "$here/.." && pwd)"
|
||||
loader="${1:?usage: $0 <limine|systemd-boot|grub> [--install]}"
|
||||
install=false; window=false
|
||||
install=false; window=false; quick=false; generic=false
|
||||
for a in "${@:2}"; do
|
||||
case "$a" in --install) install=true ;; --window) window=true ;; *) echo "Unknown argument: $a" >&2; exit 2 ;; esac
|
||||
case "$a" in --install) install=true ;; --quick) quick=true ;; --generic) generic=true ;; --window) window=true ;; *) echo "Unknown argument: $a" >&2; exit 2 ;; esac
|
||||
done
|
||||
# No human is needed: headless (no VM window) unless --window. On a desktop a Konsole follows the log.
|
||||
$window || export VM_HEADLESS=1
|
||||
case "$loader" in limine|systemd-boot|grub) ;; *) echo "Unknown boot loader: $loader" >&2; exit 2 ;; esac
|
||||
export VM_DIR="${VM_DIR:-$HOME/vms/bl-$loader}"
|
||||
$generic && ! $quick && { echo "--generic needs --quick" >&2; exit 2; }
|
||||
hw=fremont; $generic && hw=generic
|
||||
suffix=""; $generic && suffix="-generic"
|
||||
export VM_DIR="${VM_DIR:-$HOME/vms/bl-$loader$suffix}"
|
||||
hwflags=(--fremont); $generic && hwflags=()
|
||||
# Own ssh port per loader, so the loaders can run side by side (vmtest.sh).
|
||||
case "$loader" in limine) export VM_PORT="${VM_PORT:-2401}" ;; systemd-boot) export VM_PORT="${VM_PORT:-2402}" ;; grub) export VM_PORT="${VM_PORT:-2403}" ;; esac
|
||||
off=0; $generic && off=10
|
||||
case "$loader" in limine) export VM_PORT="${VM_PORT:-$((2401 + off))}" ;; systemd-boot) export VM_PORT="${VM_PORT:-$((2402 + off))}" ;; grub) export VM_PORT="${VM_PORT:-$((2403 + off))}" ;; esac
|
||||
. "$here/common.sh"
|
||||
guest="$repo/share/bootloader-test"
|
||||
log="$VM_DIR.test.log"
|
||||
|
||||
step() { printf '\n##### %s %s\n' "$(date +%T)" "$*"; }
|
||||
gssh() { vm_ssh -o ConnectTimeout=6 -o LogLevel=ERROR "$@"; }
|
||||
gscript() { gssh env "LOADER=$loader" bash -s < "$guest/$1"; } # the guest's login shell is fish
|
||||
waitssh() { local _; for _ in $(seq 60); do gssh 'uptime -p' 2>/dev/null | grep -q '^up' && return 0; sleep 5; done; echo "FAIL no SSH"; return 1; }
|
||||
gscript() { gssh env "LOADER=$loader" "HARDWARE=$hw" bash -s < "$guest/$1"; } # the guest's login shell is fish
|
||||
# Up to ~15 minutes for the first ssh: a first boot is slow when several VMs run at once.
|
||||
waitssh() { local _; for _ in $(seq 180); do gssh 'uptime -p' 2>/dev/null | grep -q '^up' && return 0; sleep 5; done; echo "FAIL no SSH"; return 1; }
|
||||
running() { pgrep -f "[h]ostfwd=tcp::$VM_PORT-" >/dev/null; }
|
||||
stop_vm() {
|
||||
running || return 0
|
||||
# Whichever VM runs: its key and host key are not this VM's.
|
||||
ssh -p "$VM_PORT" -i "$VM_SSH_KEY" -o BatchMode=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR \
|
||||
ssh -p "$VM_PORT" -i "$(vm_key)" -o BatchMode=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR \
|
||||
"$VM_USER@$VM_HOST" 'sudo systemctl poweroff' >/dev/null 2>&1
|
||||
local _; for _ in $(seq 30); do running || return 0; sleep 2; done
|
||||
pkill -f "[h]ostfwd=tcp::$VM_PORT-"; sleep 2
|
||||
}
|
||||
export VM_CACHE="${VM_CACHE-$HOME/vms/pkg-cache}" # 9p tag `cache`: Steamify's downloads once for every VM
|
||||
start_vm() { stop_vm; cp "$repo/run.sh" "$VM_DIR/run.sh"; (cd "$VM_DIR" && VM_MEM="${VM_MEM:-4G}" REPO="${REPO:-$repo/../steamify-cachyos}" setsid nohup ./run.sh --fremont > vm.log 2>&1 &); }
|
||||
start_vm() { stop_vm; cp "$repo/run.sh" "$VM_DIR/run.sh"; (cd "$VM_DIR" && VM_MEM="${VM_MEM:-4G}" REPO="${REPO:-$repo/../steamify-cachyos}" setsid nohup ./run.sh "${hwflags[@]}" > vm.log 2>&1 &); }
|
||||
reboot_vm() { gssh 'sudo systemctl reboot' >/dev/null 2>&1; sleep 25; waitssh; }
|
||||
view_start # one shared Konsole (common.sh)
|
||||
# The guest checks print PASS/FAIL lines; the summary at the end counts them in the log.
|
||||
@@ -62,19 +71,32 @@ if $install; then
|
||||
[[ "$a" == YES ]] || exit 1
|
||||
rm -f "$VM_DIR/disk.qcow2"
|
||||
fi
|
||||
VM_BOOTLOADER="$loader" "$here/vminstall.sh" --iso "$iso" < /dev/null || exit 1
|
||||
# --quick checks what the ISO's install leaves on a Steam Machine: install on a VM that reports Fremont hardware
|
||||
# (a generic PC rightly gets no poweroff/CEC items and no DKMS modules).
|
||||
fremont=(); $quick && ! $generic && fremont=(--fremont)
|
||||
VM_BOOTLOADER="$loader" "$here/vminstall.sh" --iso "$iso" "${fremont[@]}" < /dev/null || exit 1
|
||||
fi
|
||||
|
||||
step "start $loader as a Steam Machine"
|
||||
step "start $loader as a $($generic && echo plain PC || echo Steam Machine)"
|
||||
start_vm; waitssh || exit 1
|
||||
gssh 'sudo cat /sys/class/dmi/id/product_name' 2>/dev/null
|
||||
|
||||
if $quick; then
|
||||
step "the installed system: Steamify's state, OS name, boot loader"; gscript steamify-state.sh | check
|
||||
step "Steamify's modules"; gscript modules.sh | check
|
||||
step "boot and its boot entry"; gscript boot-check.sh | check
|
||||
else
|
||||
step "Steamify's Steam Machine options"
|
||||
gssh 'sudo mkdir -p /var/cache/steamify-pkg /var/cache/steamify; sudo mountpoint -q /var/cache/steamify-pkg || sudo mount -t 9p -o trans=virtio,version=9p2000.L cache /var/cache/steamify-pkg && { sudo mkdir -p /var/cache/steamify-pkg/steamify; sudo mount --bind /var/cache/steamify-pkg/steamify /var/cache/steamify; }' 2>/dev/null
|
||||
gssh 'sudo mountpoint -q /mnt || sudo mount -t 9p -o trans=virtio,version=9p2000.L repo /mnt; cd /mnt && nohup bash steamify.sh --defaults --options gaming,theme,glyphs,single,launcher,notify,vram,cec,machine,poweroff --boot gamescope > /tmp/steamify.log 2>&1 < /dev/null &'
|
||||
sleep 20
|
||||
# [s]: the pattern must not match this ssh command itself.
|
||||
for _ in $(seq 90); do gssh 'pgrep -f "[s]teamify.sh --defaults" >/dev/null && echo R || echo D' 2>/dev/null | grep -q D && break; sleep 10; done
|
||||
n=0
|
||||
for _ in $(seq 90); do
|
||||
gssh 'pgrep -f "[s]teamify.sh --defaults" >/dev/null && echo R || echo D' 2>/dev/null | grep -q D && break
|
||||
(( n++ % 6 == 0 )) && echo " .. steamify.sh running: $(gssh 'tail -n 1 /tmp/steamify.log' 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g' | cut -c1-110)"
|
||||
sleep 10
|
||||
done
|
||||
gssh 'sed "s/\x1b\[[0-9;]*m//g" /tmp/steamify.log | grep -E "^\[(WARN|ERROR)\]" | cut -c1-140'
|
||||
gssh 'tail -n 1 /tmp/steamify.log | sed "s/\x1b\[[0-9;]*m//g"' | grep -q '^\[OK\] Done' && echo "PASS Steamify finished" || { echo "FAIL Steamify did not finish"; }
|
||||
|
||||
@@ -112,10 +134,16 @@ b="$(gssh uname -r)"
|
||||
[[ "$loader" == grub ]] && gssh "sudo sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT=$gg/' /etc/default/grub && sudo grub-mkconfig -o /boot/grub/grub.cfg >/dev/null 2>&1"
|
||||
[[ "$loader" == limine ]] && gssh "sudo sed -i -e 's/^default_entry: .*/default_entry: $cur/' -e 's/^remember_last_entry: .*/remember_last_entry: ${rem:-yes}/' /boot/limine.conf"
|
||||
|
||||
fi
|
||||
|
||||
step "DONE"
|
||||
stop_vm
|
||||
} 2>&1 | tee "$log" | tee >(sed -u "s/^/[$loader] /" >> "$TEST_LOG") | sed 's/\x1b\[[0-9;]*m//g'
|
||||
} 2>&1 | tee "$log" | tee >(sed -u "s/^/[$loader] /" >> "$TEST_LOG") | sed -u 's/\x1b\[[0-9;]*m//g'
|
||||
rc=${PIPESTATUS[0]} # the test itself: an abort (exit inside the braces) must not pass as 0 failed checks
|
||||
fails="$(grep -c '^FAIL' "$log")"
|
||||
echo; echo "== $loader: $(grep -c '^PASS' "$log") passed, $fails failed (log: $log)"
|
||||
if [[ $rc -ne 0 && $fails -eq 0 ]]; then
|
||||
echo "FAIL $loader aborted (exit $rc): $(grep -v '^$' "$log" | tail -n 1)" | tee -a "$log"; fails=1
|
||||
fi
|
||||
echo; echo "== $loader$suffix: $(grep -c '^PASS' "$log") passed, $fails failed (log: $log)"
|
||||
grep '^FAIL' "$log"
|
||||
exit "$fails"
|
||||
+21
-3
@@ -11,6 +11,7 @@
|
||||
# Env: VM_DIR (see common.sh), VM_USER (default: your host username; theupriser when that is root),
|
||||
# VM_PASSWORD (steamify), VM_SSH_KEY (private key to authorize; default
|
||||
# ~/.ssh/steamify-vm_ed25519, asked once when that doesn't exist), REPO (shared as 9p `repo`, default ../steamify-cachyos),
|
||||
# VM_INSTALL_MEM (RAM of the live installer VM only; default VM_MEM, else run.sh's 8G),
|
||||
# VM_CACHE (host dir for the packages, default ~/vms/pkg-cache; empty = none),
|
||||
# VM_STEAMIFY (a Steamify ISO also runs steamify-install: the Steamify page's ids,
|
||||
# empty = defaults, skip = plain CachyOS), VM_BOOTLOADER (limine; or systemd-boot, grub), VM_TIMEZONE (the host's), VM_HOST_IP (the host as the guest sees it,
|
||||
@@ -18,6 +19,7 @@
|
||||
# The VM's user and key are recorded in $VM_DIR (vm-user, ssh-key) for the
|
||||
# other scripts. Never touches your existing SSH keys or ~/.ssh/known_hosts.
|
||||
set -euo pipefail
|
||||
[[ -n "${CI:-}" ]] && export VM_HEADLESS=1 # no display in CI (QEMU fails with "OpenGL is not supported by the display")
|
||||
here="$(cd "$(dirname "$0")" && pwd)"
|
||||
repo="$(cd "$here/.." && pwd)"
|
||||
[[ -n "${VM_USER:-}" ]] || VM_USER="$(id -un)"
|
||||
@@ -87,7 +89,15 @@ boot="$VM_DIR/iso-boot"
|
||||
mkdir -p "$boot"
|
||||
# One loop setup at a time: parallel installs (vmtest.sh --install) otherwise get "Device or resource busy".
|
||||
exec 9> /tmp/vminstall-iso.lock; flock 9
|
||||
if ! command -v udisksctl >/dev/null && [[ $EUID -eq 0 ]]; then
|
||||
if command -v bsdtar >/dev/null; then
|
||||
# No loop device, no udisks, no root: libarchive reads the ISO9660 image directly (a CI container has no
|
||||
# loop partition nodes, so the mounts below can't work there).
|
||||
mnt="$(mktemp -d)"
|
||||
cleanup_loop() { chmod -R u+rwX "$mnt" 2>/dev/null || true; rm -rf "$mnt" 2>/dev/null || true; } # the ISO's files come out read-only
|
||||
trap cleanup_loop EXIT
|
||||
bsdtar -xf "$iso" -C "$mnt" arch/boot/x86_64/vmlinuz-linux-cachyos arch/boot/x86_64/initramfs-linux-cachyos.img boot EFI 2>/dev/null || true
|
||||
[[ -f "$mnt/arch/boot/x86_64/vmlinuz-linux-cachyos" ]] || { echo "bsdtar found no kernel in the ISO." >&2; exit 1; }
|
||||
elif ! command -v udisksctl >/dev/null && [[ $EUID -eq 0 ]]; then
|
||||
# No udisks (the WSL box, as root): a plain loop device and mount.
|
||||
loop="$(losetup -f -r -P --show "$iso")"
|
||||
mnt="$(mktemp -d)"
|
||||
@@ -162,19 +172,27 @@ append="$search archisobasedir=arch cow_spacesize=10G module_blacklist=pcspkr co
|
||||
append+=" systemd.run=\"/usr/bin/bash -c 'curl -fsS --retry 150 --retry-all-errors --retry-delay 2 http://$host_ip:$port/vminstall-live.sh | bash'\""
|
||||
append+=" systemd.run_success_action=none systemd.run_failure_action=none systemd.wants=kernel-command-line.service"
|
||||
echo "Installing: watch the VM's window, or follow the console with tail -f $VM_DIR/serial.log (install log: $www/install.log)..."
|
||||
VM_SERIAL="$VM_DIR/serial.log" VM_ISO="$iso" VM_KERNEL="$boot/vmlinuz-linux-cachyos" VM_INITRD="$boot/initramfs-linux-cachyos.img" VM_APPEND="$append" \
|
||||
VM_MEM="${VM_INSTALL_MEM:-${VM_MEM:-}}" VM_SERIAL="$VM_DIR/serial.log" VM_ISO="$iso" VM_KERNEL="$boot/vmlinuz-linux-cachyos" VM_INITRD="$boot/initramfs-linux-cachyos.img" VM_APPEND="$append" \
|
||||
./run.sh install "${run_flags[@]}" > vm-install.log 2>&1 &
|
||||
qemu=$!
|
||||
# 90 minutes; a failure reported by the live system ends it at once (it stays up after one)
|
||||
waited=0
|
||||
for _ in $(seq 1080); do
|
||||
kill -0 $qemu 2>/dev/null || break
|
||||
# A sign of life every minute (CI shows nothing else for ~10 minutes): where the live installer is.
|
||||
(( waited++ % 12 == 0 )) && echo " .. installing, $((waited * 5 / 60)) min: $(tail -n 1 "$www/install.log" 2>/dev/null | cut -c1-110)"
|
||||
[[ -s "$www/status" && "$(cat "$www/status")" != ok ]] && { sleep 5; kill $qemu 2>/dev/null; wait $qemu 2>/dev/null; break; }
|
||||
sleep 5
|
||||
done
|
||||
kill -0 $qemu 2>/dev/null && { echo "The install didn't finish in 90 minutes; see $www/install.log." >&2; kill $qemu; exit 1; }
|
||||
status="$(cat "$www/status" 2>/dev/null || echo "no status (the live system never reported back)")"
|
||||
cp "$www/install.log" install.log 2>/dev/null || true
|
||||
[[ "$status" == ok ]] || { echo "Install failed: $status. Log: $VM_DIR/install.log" >&2; exit 1; }
|
||||
if [[ "$status" != ok ]]; then
|
||||
echo "Install failed: $status. Log: $VM_DIR/install.log" >&2
|
||||
# In CI only the job log survives: show why.
|
||||
for f in vm-install.log serial.log install.log; do [[ -s "$f" ]] && { echo "--- $f (last 40 lines)" >&2; tail -n 40 "$f" | sed 's/\x1b\[[0-9;]*[A-Za-z]//g' >&2; }; done
|
||||
exit 1
|
||||
fi
|
||||
qemu-img snapshot -c clean disk.qcow2 && cp vars.fd vars.clean.fd
|
||||
echo "Installed; snapshot 'clean' taken."
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
# The VM must run with its cache shared (one per VM, next to its disk), and
|
||||
# gets all host cores but 2 for the build: start it with
|
||||
# VM_CACHE=$VM_DIR/iso-cache VM_CPUS=$(( $(nproc) * 3 / 4 )) scripts/vmreset.sh --fremont
|
||||
# Env: VM_DIR (see common.sh), ISO_BRANCH (feat/steamify), ISO_OUT (the host's
|
||||
# Env: VM_DIR (see common.sh), ISO_BRANCH (master), ISO_OUT (the host's
|
||||
# steamify-cachyos-live-iso/out/desktop).
|
||||
set -euo pipefail
|
||||
here="$(cd "$(dirname "$0")" && pwd)"
|
||||
. "$here/common.sh"
|
||||
steamify=""
|
||||
[[ "${1:-}" == --steamify ]] && steamify="${2:?--steamify needs a guest path}"
|
||||
branch="${ISO_BRANCH:-feat/steamify}"
|
||||
branch="${ISO_BRANCH:-master}"
|
||||
# Where the ISO lands: out/desktop of the host's live-ISO checkout (next to
|
||||
# this repo), where a local build would put it.
|
||||
out="${ISO_OUT:-$(dirname "$(cd "$here/.." && pwd)")/steamify-cachyos-live-iso/out/desktop}"
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Progress of test jobs, one line per change (for a monitor; see the progress-report skill).
|
||||
# scripts/vmprogress.sh [--once] [job...] jobs: limine systemd-boot grub cli menu hw installer toggles (default all)
|
||||
# scripts/vmprogress.sh [--once] [job...] jobs: limine systemd-boot grub limine-generic systemd-boot-generic grub-generic cli menu hw installer toggles nvidia (default all)
|
||||
# Per job (only a new step, a finished job or a FAIL counts as a change): state (install NN% <stage> / <test step> / done / -), checks passed/expected, failed.
|
||||
# Line: "HH:MM total P/E F failed ;; job | state | P/E | F failed ;; ...". Prints nothing while nothing
|
||||
# changes (checked every 30 s), "ALLDONE" and exits once every started job has its summary line.
|
||||
# Expected counts: the last complete run of each (AGENTS.md "State"); update them when checks are added.
|
||||
set -uo pipefail
|
||||
declare -A expect=([limine]=43 [systemd-boot]=42 [grub]=42 [cli]=55 [menu]=36 [hw]=77 [installer]=4 [toggles]=42)
|
||||
declare -A expect=([limine]=43 [systemd-boot]=42 [grub]=42 [cli]=65 [menu]=37 [hw]=78 [installer]=4 [toggles]=42 [nvidia]=43 [limine-generic]=25 [systemd-boot-generic]=25 [grub-generic]=25)
|
||||
once=false; jobs=()
|
||||
for a in "$@"; do [[ "$a" == --once ]] && once=true || jobs+=("$a"); done
|
||||
[[ ${#jobs[@]} -gt 0 ]] || jobs=(limine systemd-boot grub cli menu hw installer toggles)
|
||||
[[ ${#jobs[@]} -gt 0 ]] || jobs=(limine systemd-boot grub limine-generic systemd-boot-generic grub-generic cli menu hw installer toggles nvidia)
|
||||
vms="$HOME/vms"
|
||||
|
||||
status() { # status <job>: "state|pass|fail|finished(0/1)|started(0/1)"
|
||||
local j="$1" log dir
|
||||
case "$j" in limine|systemd-boot|grub) log="$vms/bl-$j.test.log" dir="$vms/bl-$j" ;; *) log="$vms/run-$j.log" dir="$vms/run-$j" ;; esac
|
||||
case "$j" in limine|systemd-boot|grub|limine-generic|systemd-boot-generic|grub-generic) log="$vms/bl-$j.test.log" dir="$vms/bl-$j" ;; *) log="$vms/run-$j.log" dir="$vms/run-$j" ;; esac
|
||||
[[ -f "$log" ]] || { echo "-|0|0|0|0"; return; }
|
||||
local p f st run
|
||||
# The logs are appended to: only the latest run counts (from its "===== vm..." header on).
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ export XDG_RUNTIME_DIR=/run/user/$uid DBUS_SESSION_BUS_ADDRESS=unix:path=/run/us
|
||||
rm -f /tmp/vmshot.png
|
||||
if [ -n "$clean" ]; then
|
||||
# Steam as a whole: closing only its web helper leaves a black window.
|
||||
# It comes back at the next login (steam-desktop-autostart).
|
||||
# It comes back at the next login (Steam autostart entry).
|
||||
steam -shutdown >/dev/null 2>&1 & sleep 5; pkill -u "$USER" -x steam; pkill -u "$USER" -x steamwebhelper
|
||||
pkill -u "$USER" cachyos-hello; pkill -u "$USER" -x konsole
|
||||
sleep 2
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ yn() { [ -e "$1" ] && echo y || echo n; }
|
||||
echo "DM=$(systemctl show -p Id --value display-manager) sddm-autologin=$(yn /etc/sddm.conf.d/10-gamescope-autologin.conf) sync=$(yn /etc/systemd/system/sync-steamos-session.path) sudoers=$(sudo test -f /etc/sudoers.d/gamescope-session-switch && echo y || echo n)"
|
||||
echo "plasmalogin [Autologin]: $(sed -n '/^\[Autologin\]/,/^\[/p' /etc/plasmalogin.conf | grep -v '^\[' | tr '\n' ' ')"
|
||||
echo "shortcut=$(grep -h Exec= ~/Desktop/*Gaming*.desktop 2>/dev/null || echo none)"
|
||||
echo "steam-unit=$([ -f ~/.config/systemd/user/steam-desktop-autostart.service ] && systemctl --user is-enabled steam-desktop-autostart.service || echo none) glyphs=$(yn ~/.config/environment.d/99-gamescope-steam-glyphs.conf)"
|
||||
echo "steam-autostart=$(grep -qs "^Exec=.*-silent" ~/.config/autostart/steam.desktop && echo silent || ([ -f ~/.config/autostart/steam.desktop ] && echo plain || echo none)) glyphs=$(yn ~/.config/environment.d/99-gamescope-steam-glyphs.conf)"
|
||||
echo "lnf=$(kreadconfig6 --file kdeglobals --group KDE --key LookAndFeelPackage) dark-lnf=$(kreadconfig6 --file kdeglobals --group KDE --key DefaultDarkLookAndFeel) scheme=$(kreadconfig6 --file kdeglobals --group General --key ColorScheme) cursor=$(kreadconfig6 --file kcminputrc --group Mouse --key cursorTheme) vapor-pkg=$(pacman -Q cachyos-vapor 2>/dev/null || echo none) layout-backup=$(yn ~/.local/state/steamify/theme-layout)"
|
||||
echo "wallpaper: $(grep -h '^Image=' ~/.config/plasma-org.kde.plasma.desktop-appletsrc | sort -u | tr '\n' ' ')"
|
||||
echo "lock_screen=$(kreadconfig6 --file kdeglobals --group 'KDE Action Restrictions' --key action/lock_screen) autolock=$(kreadconfig6 --file kscreenlockerrc --group Daemon --key Autolock) metaL=$(kreadconfig6 --file kglobalshortcutsrc --group ksmserver --key 'Lock Session' | cut -c1-12)"
|
||||
|
||||
+5
-1
@@ -32,7 +32,7 @@ suite="${1:?usage: $0 <suite> [--window] | --prepare}"
|
||||
[[ "${2:-}" == --window ]] || export VM_HEADLESS=1
|
||||
dir="$repo/share/vmtest/$suite"
|
||||
[[ -d "$dir" ]] || { echo "No suite $suite (folders in share/vmtest/)" >&2; exit 2; }
|
||||
case "$suite" in cli) port=2301 ;; menu) port=2302 ;; hw) port=2303 ;; installer) port=2304 ;; toggles) port=2305 ;; *) port=2390 ;; esac
|
||||
case "$suite" in cli) port=2301 ;; menu) port=2302 ;; hw) port=2303 ;; installer) port=2304 ;; toggles) port=2305 ;; nvidia) port=2306 ;; *) port=2390 ;; esac
|
||||
export VM_PORT="${VM_PORT:-$port}"
|
||||
export VM_DIR="$HOME/vms/run-$suite"
|
||||
export REPO="${REPO:-$repo/../steamify-cachyos}"
|
||||
@@ -96,7 +96,11 @@ for block in "$dir"/*.sh; do
|
||||
done
|
||||
vm_stop
|
||||
} 2>&1 | tee "$log" | sed -u "s/^/[$suite] /" >> "$TEST_LOG"
|
||||
rc=${PIPESTATUS[0]} # an abort inside the braces must not pass as 0 failed checks
|
||||
fails="$(grep -c '^FAIL' "$log")"
|
||||
if [[ $rc -ne 0 && $fails -eq 0 ]]; then
|
||||
echo "FAIL $suite aborted (exit $rc): $(grep -v '^$' "$log" | tail -n 1)" | tee -a "$log"; fails=1
|
||||
fi
|
||||
echo "== $suite: $(grep -c '^PASS' "$log") passed, $fails failed, $(grep -c '^SKIP' "$log") skipped (log: $log)" | tee -a "$log"
|
||||
grep '^FAIL' "$log"
|
||||
exit "$fails"
|
||||
+24
-16
@@ -4,10 +4,12 @@
|
||||
# scripts/vmtest.sh [--install] [--window] [--screen] [boot | <loader>... | <suite>...]
|
||||
# no argument everything: boot (all advertised loaders) and all suites
|
||||
# boot the boot loader test (limine, systemd-boot, grub), or name loaders
|
||||
# <suite> cli, menu, hw, installer, toggles (folders in share/vmtest/)
|
||||
# generic the plain-PC install check for every loader (vmbootloadertest.sh --quick --generic: a PC that is not a
|
||||
# Steam Machine must get no Steam Machine items and no DKMS modules); part of the default run
|
||||
# <suite> cli, menu, hw, installer, toggles, nvidia (folders in share/vmtest/)
|
||||
# --install install the boot loader VMs first from the newest Steamify ISO (asks before replacing a disk)
|
||||
# --window show the VMs' windows (default: headless; one shared Konsole follows ~/vms/test.log)
|
||||
# MAX_PARALLEL=3 (env) VMs at once; the slowest suites start first
|
||||
# MAX_PARALLEL=3 (env) VMs at once (5 worked on a 9800X3D / 64 GB); the slowest suites start first
|
||||
# --screen run in a detached `screen` session named vmtest: `screen -r vmtest` to watch, Ctrl-a d to leave
|
||||
# The suites run on the plain CachyOS VM ~/vms/steamify-vm (Plasma, from vminstall.sh --iso <CachyOS ISO>
|
||||
# with VM_STEAMIFY=skip); the boot loader test on ~/vms/bl-<loader> (Steamify ISO).
|
||||
@@ -18,13 +20,14 @@ here="$(cd "$(dirname "$0")" && pwd)"
|
||||
repo="$(cd "$here/.." && pwd)"
|
||||
iso_repo="$repo/../steamify-cachyos-live-iso"
|
||||
args=("$@")
|
||||
install=""; window=""; screen=false; loaders=(); suites=(); want_boot=false
|
||||
install=""; window=""; screen=false; loaders=(); suites=(); want_boot=false; want_generic=false
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
--install) install=--install ;;
|
||||
--window) window=--window ;;
|
||||
--screen) screen=true ;;
|
||||
boot) want_boot=true ;;
|
||||
generic) want_generic=true ;;
|
||||
limine|systemd-boot|grub) loaders+=("$a"); want_boot=true ;;
|
||||
*) [[ -d "$repo/share/vmtest/$a" ]] && suites+=("$a") || { echo "Unknown argument: $a" >&2; exit 2; } ;;
|
||||
esac
|
||||
@@ -37,27 +40,32 @@ if $screen; then
|
||||
echo "Running in the screen session vmtest: screen -r vmtest (Ctrl-a d to leave it running); the summary lands in ~/vms/last-test.txt"
|
||||
exit 0
|
||||
fi
|
||||
if [[ ${#loaders[@]} -eq 0 && ${#suites[@]} -eq 0 ]] && ! $want_boot; then
|
||||
want_boot=true
|
||||
for d in cli menu hw installer toggles; do [[ -d "$repo/share/vmtest/$d" ]] && suites+=("$d"); done
|
||||
if [[ ${#loaders[@]} -eq 0 && ${#suites[@]} -eq 0 ]] && ! $want_boot && ! $want_generic; then
|
||||
want_boot=true; want_generic=true
|
||||
for d in cli menu hw installer toggles nvidia; do [[ -d "$repo/share/vmtest/$d" ]] && suites+=("$d"); done
|
||||
fi
|
||||
# What the ISO advertises: the boot loaders calamares-online.sh keeps.
|
||||
advertised="$(sed -n 's/.*"bootloader:\([^"]*\)".*/\1/p' "$iso_repo/archiso/airootfs/usr/local/bin/calamares-online.sh" 2>/dev/null | head -n 1)"
|
||||
[[ -n "$advertised" ]] || { echo "Can't read the advertised boot loaders from $iso_repo (calamares-online.sh)" >&2; exit 2; }
|
||||
$want_boot && [[ ${#loaders[@]} -eq 0 ]] && read -r -a loaders <<< "$advertised"
|
||||
gloaders=() # the plain-PC install check: the same loaders as the boot loader test, or all advertised ones
|
||||
if $want_generic; then if [[ ${#loaders[@]} -gt 0 ]]; then gloaders=("${loaders[@]}"); else read -r -a gloaders <<< "$advertised"; fi; fi
|
||||
tested="limine systemd-boot grub" # the loaders vmbootloadertest.sh has a way to boot the other kernel for
|
||||
summary="$HOME/vms/last-test.txt"
|
||||
maxp="${MAX_PARALLEL:-3}" # VMs at once: 8 GB RAM each, 6 vCPUs each
|
||||
maxp="${MAX_PARALLEL:-3}" # VMs at once (4 GB RAM each in the suites, see vmsuite.sh); 5 ran fine on a 9800X3D with 64 GB
|
||||
# Jobs, the slowest first so the last ones are short: suites, then the boot loaders.
|
||||
jobs_list=()
|
||||
for s in toggles hw cli menu installer; do [[ " ${suites[*]} " == *" $s "* ]] && jobs_list+=("suite:$s"); done
|
||||
for s in "${suites[@]}"; do [[ " toggles hw cli menu installer " == *" $s "* ]] || jobs_list+=("suite:$s"); done
|
||||
for l in "${loaders[@]}"; do jobs_list+=("loader:$l"); done
|
||||
run_job() { # run_job <kind:name>: output in /tmp/vmtest-<name>.out, exit status in /tmp/vmtest-<name>.rc
|
||||
local kind="${1%%:*}" name="${1#*:}"
|
||||
if [[ "$kind" == loader ]]; then bash "$here/vmbootloadertest.sh" "$name" $install $window > "/tmp/vmtest-$name.out" 2>&1
|
||||
else bash "$here/vmsuite.sh" "$name" $window > "/tmp/vmtest-$name.out" 2>&1; fi
|
||||
echo $? > "/tmp/vmtest-$name.rc"
|
||||
for l in "${gloaders[@]}"; do jobs_list+=("generic:$l"); done
|
||||
jobtag() { [[ "${1%%:*}" == generic ]] && echo "${1#*:}-generic" || echo "${1#*:}"; } # files and names of a job
|
||||
run_job() { # run_job <kind:name>: output in /tmp/vmtest-<tag>.out, exit status in /tmp/vmtest-<tag>.rc
|
||||
local kind="${1%%:*}" name="${1#*:}" tag; tag="$(jobtag "$1")"
|
||||
if [[ "$kind" == loader ]]; then bash "$here/vmbootloadertest.sh" "$name" $install $window > "/tmp/vmtest-$tag.out" 2>&1
|
||||
elif [[ "$kind" == generic ]]; then bash "$here/vmbootloadertest.sh" "$name" $install --quick --generic $window > "/tmp/vmtest-$tag.out" 2>&1
|
||||
else bash "$here/vmsuite.sh" "$name" $window > "/tmp/vmtest-$tag.out" 2>&1; fi
|
||||
echo $? > "/tmp/vmtest-$tag.rc"
|
||||
}
|
||||
{
|
||||
echo "vmtest.sh $(date '+%F %T') branch $(git -C "$repo" branch --show-current) $(git -C "$repo" rev-parse --short HEAD)"
|
||||
@@ -73,12 +81,12 @@ for job in "${jobs_list[@]}"; do
|
||||
done
|
||||
wait
|
||||
for job in "${jobs_list[@]}"; do
|
||||
name="${job#*:}"
|
||||
sed -n '/^== /,$p' "/tmp/vmtest-$name.out"
|
||||
total=$((total + $(cat "/tmp/vmtest-$name.rc" 2>/dev/null || echo 1)))
|
||||
tag="$(jobtag "$job")"
|
||||
sed -n '/^== /,$p' "/tmp/vmtest-$tag.out"
|
||||
total=$((total + $(cat "/tmp/vmtest-$tag.rc" 2>/dev/null || echo 1)))
|
||||
done
|
||||
echo
|
||||
echo "SKIP (needs a person, TESTPLAN.md): U1-U9 the app's screens, R2.2 the first desktop login, H-Real the real Steam Machine"
|
||||
echo "== total: $total failed check(s); boot loaders: ${loaders[*]:-none}; suites: ${suites[*]:-none}"
|
||||
echo "== total: $total failed check(s); boot loaders: ${loaders[*]:-none}; plain PC: ${gloaders[*]:-none}; suites: ${suites[*]:-none}"
|
||||
} 2>&1 | tee "$summary"
|
||||
exit "$(grep -c '^FAIL' "$summary")"
|
||||
@@ -3,6 +3,9 @@
|
||||
pass() { echo "PASS $*"; }; fail() { echo "FAIL $*"; }
|
||||
k=$(uname -r)
|
||||
echo "kernel: $k"; echo "cmdline: $(cut -c1-140 /proc/cmdline)"
|
||||
if [[ "${HARDWARE:-fremont}" == generic ]]; then
|
||||
lsmod | grep -qE "^(steamify_fremont_poweroff|leds_valve)" && fail "Steam Machine modules loaded on a plain PC" || pass "no Steam Machine modules loaded (not a Steam Machine)"
|
||||
else
|
||||
compgen -G "/usr/lib/modules/$k/updates/dkms/steamify-fremont-poweroff.ko*" >/dev/null && pass "power-off fix built for the running kernel" || fail "no power-off fix for $k"
|
||||
# Loaded (a real Steam Machine), or tried at boot and refused with "No such device" (the VM has no AMD GPIO
|
||||
# controller, so the module returns -ENODEV silently). The refusal is in the journal; it only sometimes
|
||||
@@ -12,6 +15,7 @@ elif sudo journalctl -b -q --no-pager -u systemd-modules-load | grep -q "steamif
|
||||
pass "power-off fix tried at boot (No such device: no AMD GPIO controller in the VM)"
|
||||
else fail "power-off fix not loaded, and not tried at boot"; fi
|
||||
lsmod | grep -q '^leds_valve' && pass "leds_valve loaded" || fail "leds_valve not loaded"
|
||||
fi
|
||||
[[ -z "$(systemctl --failed --no-legend)" ]] && pass "no failed units" || { fail "failed units:"; systemctl --failed --no-legend; }
|
||||
# B1: booted through the loader's own EFI boot entry, not the firmware's automatic disk entry (the
|
||||
# fallback path \EFI\BOOT\BOOTX64.EFI) and not an entry without a partition (HD(0,GPT,0000...)).
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
# Guest side: Steamify's DKMS modules exist for every installed kernel.
|
||||
# Prints PASS/FAIL lines (scripts/vmbootloadertest.sh counts the FAILs).
|
||||
pass() { echo "PASS $*"; }; fail() { echo "FAIL $*"; }
|
||||
# HARDWARE=generic (a plain PC): none of Steamify's Steam Machine modules belong on it.
|
||||
if [[ "${HARDWARE:-fremont}" == generic ]]; then
|
||||
for k in $(ls /usr/lib/modules); do
|
||||
for m in cros-ec-cec leds-valve steamify-fremont-poweroff; do
|
||||
compgen -G "/usr/lib/modules/$k/updates/dkms/$m.ko*" >/dev/null && fail "$m is installed for $k, but this is not a Steam Machine" || pass "no $m for $k (not a Steam Machine)"
|
||||
done
|
||||
done
|
||||
[[ -f /etc/modules-load.d/steamify-fremont-poweroff.conf ]] && fail "modules-load.d has the power-off fix on a plain PC" || pass "no modules-load.d entry (not a Steam Machine)"
|
||||
exit 0
|
||||
fi
|
||||
kernels=$(ls /usr/lib/modules)
|
||||
n=$(wc -w <<< "$kernels")
|
||||
echo "kernels: $(tr '\n' ' ' <<< "$kernels")"
|
||||
|
||||
@@ -5,14 +5,22 @@
|
||||
pass() { echo "PASS $*"; }; fail() { echo "FAIL $*"; }
|
||||
sudo mountpoint -q /mnt || sudo mount -t 9p -o trans=virtio,version=9p2000.L repo /mnt
|
||||
cd /mnt || exit 1
|
||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier; do
|
||||
for lib in $(grep -oP '^for lib in \K.*(?=; do$)' steamify.sh); do
|
||||
# shellcheck source=/dev/null
|
||||
. "lib/$lib.sh" 2>/dev/null
|
||||
done
|
||||
# Items this Steam Machine VM has on after `--options gaming,theme,glyphs,single,launcher,notify,cec,machine,poweroff`.
|
||||
for item in gaming theme glyphs single launcher notify poweroff cec; do
|
||||
# HARDWARE=generic (a plain PC): the Steam Machine items (poweroff, cec) must stay off.
|
||||
for item in gaming theme glyphs single launcher notify; do
|
||||
if "${item}_status" 2>/dev/null; then pass "$item is on (the menu shows it ticked)"; else fail "$item is off"; fi
|
||||
done
|
||||
for item in poweroff cec; do
|
||||
if [[ "${HARDWARE:-fremont}" == generic ]]; then
|
||||
if "${item}_status" 2>/dev/null; then fail "$item is on, but this is not a Steam Machine"; else pass "$item is off (not a Steam Machine)"; fi
|
||||
else
|
||||
if "${item}_status" 2>/dev/null; then pass "$item is on (the menu shows it ticked)"; else fail "$item is off"; fi
|
||||
fi
|
||||
done
|
||||
# Steamify never renames the OS (limine-snapper-sync / grub-btrfs read it).
|
||||
grep -qx 'NAME="CachyOS Linux"' /etc/os-release && grep -qx 'PRETTY_NAME="CachyOS"' /etc/os-release && pass "os-release NAME and PRETTY_NAME are CachyOS's" || fail "os-release NAME/PRETTY_NAME changed"
|
||||
grep -q 'with Steamify' /etc/lsb-release && fail "lsb-release still says 'with Steamify'" || pass "lsb-release name is CachyOS's"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# C1-C3: extended controller support: the repo's DKMS drivers (xone + dongle firmware, xpadneo) are installed and built for every
|
||||
# installed kernel; a second run is quiet; turning it off removes them again. The VM has no dongle or controller: this covers
|
||||
# the packages, the headers and the DKMS builds, not the hardware. Covers TESTPLAN C1 (on), C2 (again), C3 (off).
|
||||
info "applying extended_controller_support (kernel headers and DKMS builds for every kernel: a few minutes)..."
|
||||
sf --defaults --options extended_controller_support > /tmp/c1.log; rc=$?
|
||||
[[ $rc -eq 0 ]] && pass "C1 exit 0" || { fail "C1 exit $rc: $(tail -n 12 /tmp/c1.log)"; exit 0; }
|
||||
pacman -Q xpadneo-dkms xone-dongle-firmware >/dev/null 2>&1 && pacman -Q xone-dkms >/dev/null 2>&1 && pass "C1 xpadneo-dkms, xone-dkms and xone-dongle-firmware are installed" || fail "C1 packages: $(pacman -Qq | grep -E 'xone|xpadneo' | tr '\n' ' ')"
|
||||
expect_on extended_controller_support
|
||||
for kd in /usr/lib/modules/*/; do
|
||||
k="$(basename "$kd")"; [[ -d "$kd/kernel" ]] || continue
|
||||
n="$(dkms status -k "$k" 2>/dev/null | grep -E 'xone|xpadneo' | grep -c installed)"
|
||||
[[ "$n" -ge 2 ]] && pass "C1 $k: DKMS built xone and xpadneo ($n modules installed)" || fail "C1 $k: DKMS: $(dkms status -k "$k" 2>&1 | tr '\n' ';')"
|
||||
modinfo -k "$k" xone_dongle >/dev/null 2>&1 && modinfo -k "$k" hid_xpadneo >/dev/null 2>&1 && pass "C1 $k: xone_dongle and hid_xpadneo modules exist" || fail "C1 $k: modules missing"
|
||||
done
|
||||
sf --defaults --options extended_controller_support | grep -qiE 'nothing|already|exit: 0' && pass "C2 a second run is quiet" || info "C2 second run: $(sf --defaults --options extended_controller_support | tail -n 3)"
|
||||
sf --defaults --options notify > /tmp/c3.log; rc=$?
|
||||
[[ $rc -eq 0 ]] && pass "C3 turn-off exit 0" || fail "C3 exit $rc: $(tail -n 8 /tmp/c3.log)"
|
||||
pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware >/dev/null 2>&1 && fail "C3 packages are still installed" || pass "C3 the three packages are removed again"
|
||||
expect_off extended_controller_support
|
||||
@@ -1,5 +1,8 @@
|
||||
# H3: BIOS update, the whole flow with WIZARD_BIOS_DRY_RUN=1 (never flashes). The VM reports an older BIOS.
|
||||
# env: BIOS_VERSION=F7F0107
|
||||
out=$(printf '11\n\ny\ny\nUPDATE\nm\nq\nn\n' | WIZARD_BIOS_DRY_RUN=1 bash /mnt/steamify.sh 2>&1 | sed 's/\x1b\[[0-9;]*m//g')
|
||||
# The BIOS row's number by its name (a new menu item shifts the numbers).
|
||||
n=$(printf 'q\n' | bash /mnt/steamify.sh 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | sed -n 's/^ *\([0-9][0-9]*\) .*Update BIOS.*/\1/p' | head -n 1)
|
||||
[[ -n "$n" ]] && pass "H3 Update BIOS is menu row $n" || { fail "H3 no Update BIOS row in the menu"; exit 0; }
|
||||
out=$(printf "$n\n\ny\ny\nUPDATE\nm\nq\nn\n" | WIZARD_BIOS_DRY_RUN=1 bash /mnt/steamify.sh 2>&1 | sed 's/\x1b\[[0-9;]*m//g')
|
||||
grep -qi "dry run" <<< "$out" && pass "H3 the dry run went through" || fail "H3 no dry-run message: $(tail -n 3 <<< "$out" | tr '\n' ' ' | cut -c1-160)"
|
||||
grep -q '^\[ERROR\]' <<< "$out" && fail "H3 errors: $(grep -B4 -m1 '^\[ERROR\]' <<< "$out" | tr '\n' '|' | cut -c1-400)" || pass "H3 no errors"
|
||||
@@ -2,8 +2,13 @@
|
||||
menu() { printf "$1" | bash /mnt/steamify.sh 2>&1 | sed 's/\x1b\[[0-9;]*m//g'; }
|
||||
# R1.1: first-run ticks: everything but Boot into desktop and BIOS
|
||||
out=$(menu 'q\n')
|
||||
for n in 1 3 4 5 6 7 8 9 10; do grep -qE "^ +$n +[a-z-]+ +\[x\]" <<< "$out" && pass "R1.1 row $n ticked" || fail "R1.1 row $n not ticked"; done
|
||||
grep -qE "^ +11 .*\[ \]" <<< "$out" && pass "R1.1 Update BIOS not ticked" || fail "R1.1 Update BIOS ticked"
|
||||
# By name, not by row number (a new item shifts the numbers): the ticked ones, then the ones that are shown but never preselected.
|
||||
for item in "SteamOS conversion" "SteamOS theme" "Steam Deck/Machine icons" "Single user mode" "Steamify shortcut" "Update notifications" "HDMI-CEC" "Steam Machine support" "Power-off fix"; do
|
||||
grep -qE "^ +[0-9]+ +[a-z-]+ +\[x\] .*$item" <<< "$out" && pass "R1.1 $item ticked" || fail "R1.1 $item not ticked"
|
||||
done
|
||||
for item in "Extended controller support" "Update BIOS"; do
|
||||
grep -qE "^ +[0-9]+ +[a-z-]+ +\[ \] .*$item" <<< "$out" && pass "R1.1 $item shown, not ticked" || fail "R1.1 $item missing or ticked"
|
||||
done
|
||||
grep -q "Boot into: \[gamescope\]" <<< "$out" && pass "R1.1 boots into gamescope by default" || fail "R1.1 boot default is not gamescope"
|
||||
# R1.2: everything OK, back in the menu with all on
|
||||
info "applying Steamify (installs packages, builds kernel modules: a few minutes)..."
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# N1: an NVIDIA PC (fake GPU): the menu hides the SteamOS conversion and its gamescope options, shows Gaming on NVIDIA, its
|
||||
# Big Picture option and Single user mode. Covers TESTPLAN N1.
|
||||
fake_nvidia
|
||||
out="$(sf --defaults --list)"
|
||||
ids="$(python3 -c 'import json,sys; d=json.load(sys.stdin); print(" ".join(sorted(i["id"] for i in d)))' <<< "$out" 2>/dev/null)"
|
||||
[[ -n "$ids" ]] && pass "N1 --defaults --list is valid JSON: $ids" || { fail "N1 --defaults --list is not JSON: $(echo "$out" | head -c 300)"; exit 0; }
|
||||
for i in nvidia bigpicture single; do [[ " $ids " == *" $i "* ]] && pass "N1 $i is offered" || fail "N1 $i is missing"; done
|
||||
for i in gaming boot glyphs; do [[ " $ids " == *" $i "* ]] && fail "N1 $i is offered on an NVIDIA PC" || pass "N1 $i is hidden"; done
|
||||
python3 -c '
|
||||
import json,sys
|
||||
d={i["id"]:i for i in json.load(sys.stdin)}
|
||||
ok = d["bigpicture"]["parent"]=="nvidia" and d["nvidia"]["on"] and d["bigpicture"]["on"] and d["single"]["on"]
|
||||
sys.exit(0 if ok else 1)' <<< "$out" && pass "N1 Big Picture is a sub-option of Gaming on NVIDIA, all three preselected" || fail "N1 parent or preselection wrong"
|
||||
st="$(sf --backend status)"
|
||||
python3 -c 'import json,sys; d=json.load(sys.stdin); ids=[i["id"] for i in d.get("items",d)]; sys.exit(1 if "gaming" in ids else 0)' <<< "$st" 2>/dev/null && pass "N1 --backend status (the app) has no conversion row" || fail "N1 --backend status lists the conversion"
|
||||
# Without a NVIDIA GPU nothing changes: the conversion is offered, Gaming on NVIDIA is not.
|
||||
out2="$(NVIDIA_DRM_DIR=/nonexistent sf --defaults --list)"
|
||||
python3 -c 'import json,sys; ids=[i["id"] for i in json.load(sys.stdin)]; sys.exit(0 if "gaming" in ids and "nvidia" not in ids and "bigpicture" not in ids else 1)' <<< "$out2" && pass "N1 no NVIDIA GPU: the conversion is offered, Gaming on NVIDIA is not" || fail "N1 no-NVIDIA menu wrong"
|
||||
@@ -0,0 +1,51 @@
|
||||
# N2-N5: Gaming on NVIDIA + Big Picture + Single user mode on a fake NVIDIA PC, for real: pacman installs Steam, the SDDM autologin,
|
||||
# the boot loader files and the initramfs, then a reboot into Plasma, then everything off again and a second reboot.
|
||||
# Covers TESTPLAN N2 (apply), N3 (after the reboot), N4 (turn off), N5 (after the second reboot).
|
||||
unit='~/.config/systemd/user/steamify-steam-autostart.service'
|
||||
g() { guest "$@"; }
|
||||
yes_() { [[ "$(g "$1 && echo YES || echo NO" | tail -n 1)" == YES ]]; } # a guest condition
|
||||
info "N2 applying nvidia,bigpicture,single (Steam, SDDM, initramfs: several minutes)..."
|
||||
rc="$(g 'fake_nvidia; sf --defaults --options nvidia,bigpicture,single > /tmp/n2.log; echo "rc=$?"' | tail -n 1)"
|
||||
[[ "$rc" == rc=0 ]] && pass "N2 apply exit 0" || { fail "N2 apply: $rc: $(g 'tail -n 15 /tmp/n2.log')"; return 0 2>/dev/null || exit 0; }
|
||||
yes_ 'pacman -Q steam >/dev/null 2>&1' && pass "N2 Steam is installed" || fail "N2 Steam missing"
|
||||
yes_ "grep -qx 'ExecStart=/usr/bin/steam -gamepadui' $unit" && pass "N2 the autostart unit starts Steam with -gamepadui" || fail "N2 unit: $(g "cat $unit")"
|
||||
yes_ 'systemctl --user is-enabled -q steamify-steam-autostart.service' && pass "N2 the unit is enabled" || fail "N2 unit not enabled"
|
||||
[[ "$(g 'kreadconfig6 --file ksmserverrc --group General --key loginMode' | tail -n 1)" == emptySession ]] && pass "N2 Plasma starts with an empty session" || fail "N2 loginMode"
|
||||
g 'is nvidia && is bigpicture && echo ON' | grep -qx ON && pass "N2 nvidia and bigpicture report on" || fail "N2 status functions"
|
||||
yes_ "grep -q 'nvidia-drm.modeset=1 nvidia-drm.fbdev=1' /etc/default/limine" && pass "N2 the kernel parameters are in /etc/default/limine" || fail "N2 limine defaults"
|
||||
yes_ "sudo grep -q 'nvidia-drm.fbdev=1' /boot/limine.conf" && pass "N2 and in the generated /boot/limine.conf" || fail "N2 limine.conf"
|
||||
yes_ 'test -f /etc/mkinitcpio.conf.d/90-steamify-nvidia.conf && test -x /usr/local/libexec/steamify-nvidia-initramfs && test -f /etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook' && pass "N2 early-load file, hook and its script installed" || fail "N2 initramfs files"
|
||||
yes_ 'sudo find /boot -name "initramfs*" -exec sh -c "lsinitcpio {} | grep -q nvidia" \; -print | grep -q .' && pass "N2 the NVIDIA modules are in the initramfs" || fail "N2 initramfs has no nvidia modules"
|
||||
yes_ 'systemctl is-enabled -q sddm.service' && pass "N2 SDDM is the login manager" || fail "N2 sddm not enabled"
|
||||
yes_ "grep -qx 'Session=plasma.desktop' /etc/sddm.conf.d/zzz-steamify-autologin.conf && grep -qx \"User=\$USER\" /etc/sddm.conf.d/zzz-steamify-autologin.conf" && pass "N2 SDDM autologin: the user into the Plasma session" || fail "N2 autologin file: $(g 'cat /etc/sddm.conf.d/zzz-steamify-autologin.conf')"
|
||||
yes_ 'is single' && pass "N2 single user mode is on" || fail "N2 single not on"
|
||||
g 'fake_nvidia; sf --defaults --options nvidia,bigpicture,single | tail -n 3' | grep -qiE 'nothing|already|exit: 0' && pass "N2 a second run is quiet" || info "N2 second run: $(g 'fake_nvidia; sf --defaults --options nvidia,bigpicture,single | tail -n 3')"
|
||||
|
||||
reboot_guest && pass "N3 the VM is back after the reboot" || { fail "N3 no ssh after the reboot"; return 0 2>/dev/null || exit 0; }
|
||||
up=""; for _ in $(seq 40); do vm_ssh "pgrep -u $VM_USER -x plasmashell" >/dev/null 2>&1 && { up=1; break; }; sleep 3; done
|
||||
[[ -n "$up" ]] && pass "N3 Plasma straight after the boot (SDDM autologin, no greeter)" || fail "N3 no plasmashell after the reboot"
|
||||
yes_ '! pgrep -x sddm-greeter >/dev/null' && pass "N3 no greeter running" || fail "N3 sddm-greeter is running"
|
||||
yes_ 'grep -q "nvidia-drm.modeset=1" /proc/cmdline && grep -q "nvidia-drm.fbdev=1" /proc/cmdline' && pass "N3 the kernel parameters are on the running command line" || fail "N3 cmdline: $(g 'cat /proc/cmdline')"
|
||||
yes_ 'systemctl is-active -q sddm.service' && pass "N3 sddm is the running display manager" || fail "N3 sddm not active"
|
||||
yes_ 'journalctl --user -b --no-pager -u steamify-steam-autostart.service | grep -qiE "Started|Starting"' && pass "N3 the Steam autostart unit was started at login" || fail "N3 unit never started: $(g 'systemctl --user status steamify-steam-autostart.service 2>&1 | head -n 8')"
|
||||
[[ "$(g 'kreadconfig6 --file ksmserverrc --group General --key loginMode' | tail -n 1)" == emptySession ]] && pass "N3 the empty session setting survived" || fail "N3 loginMode after the reboot"
|
||||
|
||||
info "N4 turning everything off (only notify stays)..."
|
||||
rc="$(g 'fake_nvidia; sf --defaults --options notify > /tmp/n4.log; echo "rc=$?"' | tail -n 1)"
|
||||
[[ "$rc" == rc=0 ]] && pass "N4 turn-off exit 0" || { fail "N4 turn-off: $rc: $(g 'tail -n 15 /tmp/n4.log')"; return 0 2>/dev/null || exit 0; }
|
||||
yes_ '! pacman -Q steam >/dev/null 2>&1' && pass "N4 Steam is removed again (Steamify installed it)" || fail "N4 Steam is still installed"
|
||||
yes_ "! test -e $unit" && pass "N4 the autostart unit is gone" || fail "N4 unit still there"
|
||||
[[ -z "$(g 'kreadconfig6 --file ksmserverrc --group General --key loginMode' | tail -n 1)" ]] && pass "N4 loginMode is back to not set" || fail "N4 loginMode: $(g 'kreadconfig6 --file ksmserverrc --group General --key loginMode')"
|
||||
yes_ '! grep -q nvidia-drm /etc/default/limine' && pass "N4 the kernel parameters are gone from /etc/default/limine" || fail "N4 limine defaults still have them"
|
||||
# Snapshot entries (snapper's, rootflags=.../.snapshots/N/snapshot) keep the command line of their time: a snapshot of the state with the
|
||||
# parameters is meant to boot that state. Only the current boot entries count.
|
||||
yes_ "! sudo grep 'cmdline:' /boot/limine.conf | grep -v '\.snapshots/' | grep -q nvidia-drm" && pass "N4 and from the current entries in /boot/limine.conf (snapshot entries keep their old command line)" || fail "N4 limine.conf still has them: $(g "sudo grep 'cmdline:' /boot/limine.conf | grep -v '\.snapshots/' | cut -c1-150" | tr '\n' '|')"
|
||||
yes_ '! test -e /etc/mkinitcpio.conf.d/90-steamify-nvidia.conf && ! test -e /usr/local/libexec/steamify-nvidia-initramfs && ! test -e /etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook' && pass "N4 early-load file, hook and script removed" || fail "N4 initramfs files remain"
|
||||
yes_ '! test -e /etc/sddm.conf.d/zzz-steamify-autologin.conf' && pass "N4 the SDDM autologin file is gone" || fail "N4 autologin file remains"
|
||||
yes_ 'systemctl is-enabled -q plasmalogin.service && ! systemctl is-enabled -q sddm.service' && pass "N4 plasma-login-manager is the login manager again" || fail "N4 login manager: $(g 'systemctl show -p Id --value display-manager')"
|
||||
yes_ '! is nvidia && ! is bigpicture && ! is single' && pass "N4 nvidia, bigpicture and single report off" || fail "N4 status still on"
|
||||
|
||||
reboot_guest && pass "N5 the VM is back after the second reboot" || { fail "N5 no ssh after the second reboot"; return 0 2>/dev/null || exit 0; }
|
||||
up=""; for _ in $(seq 40); do vm_ssh "pgrep -u $VM_USER -x plasmashell" >/dev/null 2>&1 && { up=1; break; }; sleep 3; done
|
||||
[[ -n "$up" ]] && pass "N5 Plasma comes up (the test autologin of plasma-login-manager)" || fail "N5 no plasmashell after the second reboot"
|
||||
yes_ '! grep -q "nvidia-drm" /proc/cmdline' && pass "N5 the kernel parameters are off the command line" || fail "N5 cmdline still has them"
|
||||
+22
-2
@@ -6,7 +6,7 @@ pass() { echo "PASS $*"; }; fail() { echo "FAIL $*"; }; skip() { echo "SKIP $*";
|
||||
sudo mountpoint -q /mnt || sudo mount -t 9p -o trans=virtio,version=9p2000.L repo /mnt
|
||||
cd /mnt || exit 1
|
||||
export SCRIPT_DIR=/mnt # steamify.sh sets it; the libs alone read patches/ and services/ from it
|
||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier; do
|
||||
for lib in $(grep -oP '^for lib in \K.*(?=; do$)' steamify.sh); do
|
||||
# shellcheck source=/dev/null
|
||||
. "lib/$lib.sh" 2>/dev/null
|
||||
done
|
||||
@@ -15,4 +15,24 @@ sf() { bash /mnt/steamify.sh "$@" < /dev/null 2>&1 | sed 's/\x1b\[[0-9;]*m//g';
|
||||
is() { "${1}_status" 2>/dev/null; }
|
||||
expect_on() { local i; for i in "$@"; do is "$i" && pass "$i is on" || fail "$i is off"; done; }
|
||||
expect_off() { local i; for i in "$@"; do is "$i" && fail "$i is on" || pass "$i is off"; done; }
|
||||
ticks() { local i; for i in gaming theme glyphs single launcher notify vram cec machine poweroff boot; do is "$i" && printf '%s ' "$i"; done; echo; }
|
||||
ticks() { local i; for i in gaming nvidia bigpicture theme glyphs single launcher notify vram cec machine poweroff boot; do is "$i" && printf '%s ' "$i"; done; echo; }
|
||||
# fake_nvidia: an NVIDIA PC for the nvidia suite. A fake RTX 5080 in a fake DRM tree (NVIDIA_DRM_DIR is Steamify's test hook, exported
|
||||
# here: call it in every guest command that runs the wizard) and fake NVIDIA modules for every installed kernel (renamed copies of a
|
||||
# tiny module, then depmod), so `modinfo nvidia_drm` finds one and the initramfs build has modules to put in.
|
||||
fake_nvidia() {
|
||||
local d=/var/tmp/fake-drm k kd src ext m
|
||||
mkdir -p "$d/card1/device"
|
||||
echo 0x10de > "$d/card1/device/vendor"; echo 0x030000 > "$d/card1/device/class"; echo 0x2c02 > "$d/card1/device/device"
|
||||
for kd in /usr/lib/modules/*/; do
|
||||
k="$(basename "$kd")"
|
||||
[[ -d "$kd/kernel" ]] || continue
|
||||
src="$(find "$kd/kernel" -name 'dummy.ko*' | head -n 1)"
|
||||
[[ -n "$src" ]] || { echo "no dummy module for $k"; continue; }
|
||||
ext="${src##*dummy.ko}"
|
||||
for m in nvidia nvidia-modeset nvidia-uvm nvidia-drm; do
|
||||
[[ -e "$kd/kernel/drivers/video/$m.ko$ext" ]] || sudo install -Dm644 "$src" "$kd/kernel/drivers/video/$m.ko$ext"
|
||||
done
|
||||
sudo depmod -a "$k"
|
||||
done
|
||||
export NVIDIA_DRM_DIR="$d"
|
||||
}
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
# Tests lib/controllers.sh (extended controller support: xone, the Xbox wireless dongle, and xpadneo, Xbox Bluetooth) with a stub pacman
|
||||
# and a temp home. No root, VM or hardware needed: bash tests/controllers-test.sh
|
||||
# The Steamify checkout (REPO, default: the steamify-cachyos next to this repo)
|
||||
REPO="${REPO:-$(cd "$(dirname "$0")/../../steamify-cachyos" && pwd)}"; cd "$REPO" || exit 1
|
||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
||||
fail=0
|
||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
||||
|
||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
||||
source lib/common.sh; source lib/state.sh; source lib/controllers.sh; source lib/menu.sh
|
||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||
kwriteconfig6() { local f="" k="" v=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; *) v="$1" ;; esac; shift; done; mkdir -p "$(dirname "$f")"; sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; }
|
||||
kreadconfig6() { local f="" k=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group|--default) shift ;; esac; shift; done; sed -n "s/^$k=//p" "$f" 2>/dev/null; }
|
||||
# A pretend package database.
|
||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; PACMAN_FAIL=0
|
||||
pacman() {
|
||||
case "$1" in
|
||||
-Q) local p; for p in "${@:2}"; do [[ " $PKGS " == *" $p "* ]] || return 1; done ;;
|
||||
-S) [[ $PACMAN_FAIL == 1 ]] && return 1; echo "S ${*:4}" >> "$PACMAN_LOG"; PKGS+=" ${*:4}" ;;
|
||||
-Rns) echo "R ${*:3}" >> "$PACMAN_LOG"; local p; for p in ${*:3}; do PKGS=" ${PKGS// $p / } "; done ;;
|
||||
esac
|
||||
}
|
||||
HEADERS=0; install_kernel_headers() { HEADERS=$((HEADERS + 1)); }
|
||||
|
||||
check "off to begin with" '! extended_controller_support_status'
|
||||
extended_controller_support_enable
|
||||
check "installs the repo's xpadneo-dkms, xone-dkms and the dongle firmware" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware'
|
||||
check "kernel headers are made sure of first" '[[ $HEADERS == 1 ]]'
|
||||
check "what we installed is recorded" '[[ "$(state_get extended_controller_support installed_pkgs)" == "xpadneo-dkms xone-dkms xone-dongle-firmware" ]]'
|
||||
check "it is on" extended_controller_support_status
|
||||
n="$(wc -l < "$PACMAN_LOG")"; extended_controller_support_enable
|
||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||
extended_controller_support_disable
|
||||
check "off: the three packages are removed again" '! pacman -Q xpadneo-dkms 2>/dev/null && ! pacman -Q xone-dkms 2>/dev/null && ! pacman -Q xone-dongle-firmware 2>/dev/null && [[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||
|
||||
# The AUR's xone-dkms-git conflicts with the repo's xone-dkms: it counts, and is kept.
|
||||
PKGS=" xone-dkms-git xone-dongle-firmware xpadneo-dkms"; : > "$PACMAN_LOG"
|
||||
check "xone-dkms-git counts as xone: already on" extended_controller_support_status
|
||||
extended_controller_support_enable; extended_controller_support_disable
|
||||
check "with xone-dkms-git: nothing installed and nothing removed" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q xone-dkms-git xpadneo-dkms xone-dongle-firmware'
|
||||
PKGS=" xone-dkms-git"
|
||||
extended_controller_support_enable
|
||||
check "xone-dkms-git present: only the missing ones are installed, never xone-dkms" 'grep -q "^S xpadneo-dkms xone-dongle-firmware$" "$PACMAN_LOG" && ! pacman -Q xone-dkms 2>/dev/null'
|
||||
extended_controller_support_disable
|
||||
check "and off removes only those two, xone-dkms-git stays" 'pacman -Q xone-dkms-git && ! pacman -Q xpadneo-dkms 2>/dev/null'
|
||||
|
||||
# A failed install is an error and records nothing.
|
||||
PKGS=""; PACMAN_FAIL=1
|
||||
check "a failed pacman is an error" '! extended_controller_support_enable >/dev/null'
|
||||
check "...and records nothing" '[[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||
PACMAN_FAIL=0
|
||||
|
||||
# Packages that were already there are never removed by turning it off.
|
||||
PKGS=" xpadneo-dkms xone-dkms xone-dongle-firmware"; : > "$PACMAN_LOG"
|
||||
extended_controller_support_enable; extended_controller_support_disable
|
||||
check "packages you had before stay" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware && [[ ! -s "$PACMAN_LOG" ]]'
|
||||
|
||||
# The menu.
|
||||
check "offered on every PC" 'component_available extended_controller_support'
|
||||
check "not preselected: it builds kernel modules for every kernel" '[[ " ${NO_PRESELECT[*]} " == *" extended_controller_support "* ]]'
|
||||
check "a top-level item with a label" '[[ -z "${PARENT[extended_controller_support]:-}" && -n "${LABEL[extended_controller_support]}" ]]'
|
||||
|
||||
# The "new" badge: an opt-in option added after setup shows it, but is never ticked for you.
|
||||
component_selectable() { return 0; }
|
||||
declare -A CURRENT=([gaming]=1 [nvidia]=0 [extended_controller_support]=0 [vram]=0 [boot]=0)
|
||||
rm -f "$STATE_DIR/features.state"
|
||||
check "new opt-in option (conversion on, no record): the new badge" 'feature_new_optin extended_controller_support'
|
||||
check "...but it is not ticked for you (not a new default option)" '! feature_new extended_controller_support'
|
||||
check "...and the menu label says (new)" '[[ "$(menu_label extended_controller_support)" == *"(new)"* ]]'
|
||||
check "a new default option is still ticked for you, and is not the opt-in kind" 'feature_new vram && ! feature_new_optin vram'
|
||||
check "Boot into never gets the badge (it is a choice row)" '! feature_new_optin boot'
|
||||
state_set_features() { kwriteconfig6 --file "$STATE_DIR/features.state" --group State --key "$1" "$2"; }
|
||||
state_set_features extended_controller_support off
|
||||
check "once a run recorded it as off, the badge is gone" '! feature_new_optin extended_controller_support'
|
||||
rm -f "$STATE_DIR/features.state"
|
||||
CURRENT[gaming]=0; CURRENT[nvidia]=1
|
||||
check "on an NVIDIA PC (Gaming on NVIDIA on, no conversion) it shows too" 'feature_new_optin extended_controller_support'
|
||||
CURRENT[nvidia]=0
|
||||
check "with neither the conversion nor Gaming on NVIDIA on (a fresh PC) nothing is new" '! feature_new_optin extended_controller_support && ! feature_new vram'
|
||||
CURRENT[gaming]=1; CURRENT[extended_controller_support]=1
|
||||
check "already on: not new" '! feature_new_optin extended_controller_support'
|
||||
exit $fail
|
||||
@@ -0,0 +1,170 @@
|
||||
== pc first run
|
||||
wanted: gaming glyphs theme single launcher notify
|
||||
disable:
|
||||
enable: gaming glyphs theme single launcher notify
|
||||
== pc first run, untick gaming
|
||||
wanted: theme launcher notify
|
||||
disable:
|
||||
enable: theme launcher notify
|
||||
== pc single on
|
||||
wanted: gaming theme single launcher notify
|
||||
disable:
|
||||
enable: gaming theme single launcher notify
|
||||
== pc single then gaming off
|
||||
wanted: theme launcher notify
|
||||
disable:
|
||||
enable: theme launcher notify
|
||||
== pc boot desktop
|
||||
wanted: gaming boot glyphs theme single launcher notify
|
||||
disable:
|
||||
enable: gaming boot glyphs theme single launcher notify
|
||||
== pc boot desktop then gaming off
|
||||
wanted: theme launcher notify
|
||||
disable:
|
||||
enable: theme launcher notify
|
||||
== pc silent only
|
||||
wanted: gaming silent glyphs theme single launcher notify
|
||||
disable:
|
||||
enable: gaming silent glyphs theme single launcher notify
|
||||
== pc all on, theme off
|
||||
wanted: gaming boot silent glyphs single launcher notify
|
||||
disable: theme
|
||||
enable: gaming silent notify
|
||||
== pc launcher off
|
||||
wanted:
|
||||
disable: launcher
|
||||
enable:
|
||||
== pc steamgame on without launcher
|
||||
wanted: theme launcher steamgame notify
|
||||
disable:
|
||||
enable: theme launcher steamgame notify
|
||||
== machine first run
|
||||
wanted: gaming glyphs theme single launcher steamgame notify vram cec machine poweroff
|
||||
disable:
|
||||
enable: gaming glyphs theme single launcher steamgame notify vram cec machine poweroff
|
||||
== machine silent hidden until boot desktop
|
||||
wanted: gaming silent glyphs theme single launcher notify vram machine
|
||||
disable:
|
||||
enable: gaming silent glyphs theme single launcher notify vram machine
|
||||
== machine boot desktop keeps silent
|
||||
wanted: gaming boot silent glyphs theme single launcher notify vram machine
|
||||
disable:
|
||||
enable: gaming boot silent glyphs theme single launcher notify vram machine
|
||||
== machine off
|
||||
wanted: gaming glyphs theme single launcher notify vram
|
||||
disable: poweroff machine
|
||||
enable: gaming glyphs theme single launcher notify vram
|
||||
== machine poweroff off
|
||||
wanted: gaming glyphs theme single launcher notify vram machine
|
||||
disable: poweroff
|
||||
enable: gaming glyphs theme single launcher notify vram machine
|
||||
== machine poweroff on brings machine
|
||||
wanted: gaming glyphs theme single launcher notify vram machine poweroff
|
||||
disable:
|
||||
enable: gaming glyphs theme single launcher notify vram machine poweroff
|
||||
== machine kpin removal
|
||||
wanted: gaming glyphs theme single launcher notify vram machine poweroff
|
||||
disable: kpin
|
||||
enable: gaming glyphs theme single launcher notify vram machine poweroff
|
||||
== nvidia first run
|
||||
wanted: nvidia bigpicture theme single launcher notify
|
||||
disable:
|
||||
enable: nvidia bigpicture theme single launcher notify
|
||||
== nvidia bigpicture off
|
||||
wanted: nvidia theme single launcher notify
|
||||
disable: bigpicture
|
||||
enable: nvidia theme single launcher notify
|
||||
== nvidia nvsilent on
|
||||
wanted: nvidia nvsilent theme single launcher notify
|
||||
disable: bigpicture
|
||||
enable: nvidia nvsilent theme single launcher notify
|
||||
== nvidia nvsilent then bigpicture
|
||||
wanted: nvidia bigpicture theme single launcher notify
|
||||
disable:
|
||||
enable: nvidia bigpicture theme single launcher notify
|
||||
== nvidia off
|
||||
wanted: theme single launcher notify
|
||||
disable: nvsilent bigpicture nvidia
|
||||
enable: theme single launcher notify
|
||||
== nvidia single
|
||||
wanted: nvidia bigpicture theme launcher notify
|
||||
disable:
|
||||
enable: nvidia bigpicture theme launcher notify
|
||||
== nvidia gaming already on
|
||||
wanted: nvidia theme launcher notify
|
||||
disable: gaming
|
||||
enable: nvidia theme launcher notify
|
||||
== outdated features
|
||||
wanted: gaming glyphs theme single launcher notify
|
||||
disable:
|
||||
enable: gaming glyphs single launcher notify
|
||||
== reapply (a)
|
||||
wanted: gaming glyphs theme single launcher notify
|
||||
disable:
|
||||
enable: gaming glyphs theme single launcher notify
|
||||
== backend_apply single
|
||||
{"event":"plan","disable":[],"enable":["gaming","single"]}
|
||||
== backend_apply boot
|
||||
{"event":"plan","disable":[],"enable":[]}
|
||||
== backend_apply poweroff
|
||||
{"event":"plan","disable":[],"enable":["machine","poweroff"]}
|
||||
== backend_apply silent
|
||||
{"event":"plan","disable":[],"enable":["gaming","silent"]}
|
||||
== backend_apply kpin
|
||||
{"event":"plan","disable":[],"enable":[]}
|
||||
== backend_apply gaming boot
|
||||
{"event":"plan","disable":[],"enable":["gaming","boot"]}
|
||||
== backend_apply launcher steamgame
|
||||
{"event":"plan","disable":[],"enable":["launcher","steamgame"]}
|
||||
== backend_apply nvidia bigpicture
|
||||
{"event":"plan","disable":[],"enable":["nvidia","bigpicture"]}
|
||||
== backend_apply nvidia nvsilent
|
||||
{"event":"plan","disable":[],"enable":["nvidia","nvsilent"]}
|
||||
== backend_apply nvidia bigpicture nvsilent
|
||||
{"event":"plan","disable":[],"enable":["nvidia","bigpicture"]}
|
||||
== backend_apply nvidia single
|
||||
{"event":"plan","disable":[],"enable":["single"]}
|
||||
== backend_apply nvidia boot
|
||||
{"event":"plan","disable":[],"enable":[]}
|
||||
== defaults_list []
|
||||
{"hideWhen":"","hint":"boot into gaming mode, Steam on the desktop","id":"gaming","kind":"toggle","label":"SteamOS conversion","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"","id":"boot","kind":"choice","label":"Boot into the desktop instead of gaming mode","needs":"","on":false,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"in the tray at login on the desktop, no window","id":"silent","kind":"toggle","label":"Start Steam silently in desktop mode","needs":"","on":false,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"Deck button icons in gaming mode","id":"glyphs","kind":"toggle","label":"Install Steam Deck/Machine icons","needs":"","on":true,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","on":false,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","on":false,"parent":"","selectable":true}
|
||||
== backend_status []
|
||||
{"bios":null,"firstRun":true,"items":[{"hint":"boot into gaming mode, Steam on the desktop","id":"gaming","kind":"toggle","label":"SteamOS conversion","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"","id":"boot","kind":"choice","label":"Boot into the desktop instead of gaming mode","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":false},{"hint":"in the tray at login on the desktop, no window","id":"silent","kind":"toggle","label":"Start Steam silently in desktop mode","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":false},{"hint":"Deck button icons in gaming mode","id":"glyphs","kind":"toggle","label":"Install Steam Deck/Machine icons","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":true},{"hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":false},{"hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":false}],"pinnedKernel":"7.1.6-1","steamMachine":false,"version":"0.0.0"}
|
||||
== defaults_list [fremont steam vram]
|
||||
{"hideWhen":"","hint":"boot into gaming mode, Steam on the desktop","id":"gaming","kind":"toggle","label":"SteamOS conversion","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"","id":"boot","kind":"choice","label":"Boot into the desktop instead of gaming mode","needs":"","on":false,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"in the tray at login on the desktop, no window","id":"silent","kind":"toggle","label":"Start Steam silently in desktop mode","needs":"","on":false,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"Deck button icons in gaming mode","id":"glyphs","kind":"toggle","label":"Install Steam Deck/Machine icons","needs":"","on":true,"parent":"gaming","selectable":true}
|
||||
{"hideWhen":"","hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"Steamify in your Steam library, for the controller and gaming mode","id":"steamgame","kind":"toggle","label":"Add as non-Steam game","needs":"","on":true,"parent":"launcher","selectable":true}
|
||||
{"hideWhen":"","hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","on":false,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the game in front keeps its VRAM, background apps make room","id":"vram","kind":"toggle","label":"VRAM booster","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"LED bar driver, hardware settings in Steam","id":"machine","kind":"toggle","label":"Steam Machine support","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the Steam Machine stays off after shutting down","id":"poweroff","kind":"toggle","label":"Power-off fix","needs":"","on":true,"parent":"machine","selectable":true}
|
||||
== backend_status [fremont steam vram]
|
||||
{"bios":null,"firstRun":true,"items":[{"hint":"boot into gaming mode, Steam on the desktop","id":"gaming","kind":"toggle","label":"SteamOS conversion","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"","id":"boot","kind":"choice","label":"Boot into the desktop instead of gaming mode","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":false},{"hint":"in the tray at login on the desktop, no window","id":"silent","kind":"toggle","label":"Start Steam silently in desktop mode","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":false},{"hint":"Deck button icons in gaming mode","id":"glyphs","kind":"toggle","label":"Install Steam Deck/Machine icons","needs":"","new":false,"on":false,"parent":"gaming","selectable":true,"update":false,"wanted":true},{"hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"Steamify in your Steam library, for the controller and gaming mode","id":"steamgame","kind":"toggle","label":"Add as non-Steam game","needs":"","new":false,"on":false,"parent":"launcher","selectable":true,"update":false,"wanted":true},{"hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":false},{"hint":"the game in front keeps its VRAM, background apps make room","id":"vram","kind":"toggle","label":"VRAM booster","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"LED bar driver, hardware settings in Steam","id":"machine","kind":"toggle","label":"Steam Machine support","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"the Steam Machine stays off after shutting down","id":"poweroff","kind":"toggle","label":"Power-off fix","needs":"","new":false,"on":false,"parent":"machine","selectable":true,"update":false,"wanted":true}],"pinnedKernel":"7.1.6-1","steamMachine":true,"version":"0.0.0"}
|
||||
== defaults_list [nvidia steam]
|
||||
{"hideWhen":"","hint":"Steam on the desktop, started at login","id":"nvidia","kind":"toggle","label":"Gaming on NVIDIA","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the controller-friendly Steam (untick: Steam's normal window)","id":"bigpicture","kind":"toggle","label":"Steam starts in Big Picture","needs":"","on":true,"parent":"nvidia","selectable":true}
|
||||
{"hideWhen":"bigpicture","hint":"in the tray at login, no window (untick: Steam's normal window)","id":"nvsilent","kind":"toggle","label":"Start Steam silently","needs":"","on":false,"parent":"nvidia","selectable":true}
|
||||
{"hideWhen":"","hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","on":true,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","on":false,"parent":"","selectable":true}
|
||||
{"hideWhen":"","hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","on":false,"parent":"","selectable":true}
|
||||
== backend_status [nvidia steam]
|
||||
{"bios":null,"firstRun":true,"items":[{"hint":"Steam on the desktop, started at login","id":"nvidia","kind":"toggle","label":"Gaming on NVIDIA","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"the controller-friendly Steam (untick: Steam's normal window)","id":"bigpicture","kind":"toggle","label":"Steam starts in Big Picture","needs":"","new":false,"on":false,"parent":"nvidia","selectable":true,"update":false,"wanted":true},{"hint":"in the tray at login, no window (untick: Steam's normal window)","id":"nvsilent","kind":"toggle","label":"Start Steam silently","needs":"","new":false,"on":false,"parent":"nvidia","selectable":true,"update":false,"wanted":false},{"hint":"Vapor look (cachyos-vapor)","id":"theme","kind":"toggle","label":"Install SteamOS theme","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"no password, lock screen or log out (SDDM)","id":"single","kind":"toggle","label":"Single user mode","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"the app on the desktop, Steamify Terminal in the launcher","id":"launcher","kind":"toggle","label":"Steamify shortcut","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"a notification when there's a new Steamify, never updates by itself","id":"notify","kind":"toggle","label":"Update notifications","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":true},{"hint":"Xbox wireless dongle (xone), Xbox controllers over Bluetooth (xpadneo)","id":"extended_controller_support","kind":"toggle","label":"Extended controller support","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":false},{"hint":"use Steam with the TV remote, TV on/off with the PC (experimental)","id":"cec","kind":"toggle","label":"HDMI-CEC","needs":"","new":false,"on":false,"parent":"","selectable":true,"update":false,"wanted":false}],"pinnedKernel":"7.1.6-1","steamMachine":false,"version":"0.0.0"}
|
||||
@@ -0,0 +1,135 @@
|
||||
#!/bin/bash
|
||||
# Golden-output test for the menu rules (lib/menu.sh, lib/backend.sh): what
|
||||
# toggling does to WANTED, what plan_changes picks, and the JSON the app and
|
||||
# the installer read. Hardware and package state are stubbed, so no root, VM
|
||||
# or hardware is needed.
|
||||
# bash tests/menu-test.sh compare with menu-test.golden
|
||||
# bash tests/menu-test.sh --update rewrite the golden file (review the diff!)
|
||||
# The Steamify checkout (REPO, default: the steamify-cachyos next to this repo)
|
||||
REPO="${REPO:-$(cd "$(dirname "$0")/../../steamify-cachyos" && pwd)}"; HERE="$(cd "$(dirname "$0")" && pwd)"; cd "$REPO" || exit 1
|
||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
||||
|
||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
||||
VERSION=0.0.0
|
||||
for lib in $(grep -oP '^for lib in \K.*(?=; do$)' steamify.sh); do
|
||||
source "lib/$lib.sh"
|
||||
done
|
||||
info() { :; }; ok() { :; }; warn() { :; }; err() { :; }
|
||||
# From the entry point.
|
||||
RESTART_FOR_LOGIN=false; restart_needed() { return 1; }
|
||||
|
||||
# Hardware profile and what is "on", set per scenario.
|
||||
HW=""; ON=""
|
||||
has() { [[ " $HW " == *" $1 "* ]]; }
|
||||
nvidia_present() { has nvidia; }
|
||||
nvidia_available() { has nvidia; }
|
||||
bigpicture_available() { has nvidia; }
|
||||
machine_available() { has fremont; }
|
||||
detect_valve_fremont() { has fremont; }
|
||||
vram_available() { has vram; }
|
||||
vram_selectable() { return 0; }
|
||||
steamgame_available() { has steam; }
|
||||
kpin_available() { has fremont && [[ " $ON " == *" kpin "* ]]; }
|
||||
hdmi_available() { return 1; }
|
||||
bios_available() { return 1; }
|
||||
bios_selectable() { return 1; }
|
||||
cec_repair() { return 1; }
|
||||
launcher_repair() { return 1; }
|
||||
bios_lookup_newest() { :; }
|
||||
kernel_overview() { :; }
|
||||
os_version_refresh() { :; }
|
||||
for c in "${COMPONENTS[@]}"; do
|
||||
eval "${c}_status() { [[ \" \$ON \" == *\" $c \"* ]]; }"
|
||||
done
|
||||
|
||||
show() {
|
||||
# show <label>: WANTED as the ticked ids, then the plan.
|
||||
local c w=""
|
||||
for c in "${COMPONENTS[@]}"; do [[ "${WANTED[$c]:-0}" == 1 ]] && w+=" $c"; done
|
||||
echo "$1"
|
||||
echo " wanted:$w"
|
||||
plan_changes
|
||||
echo " disable: ${TO_DISABLE[*]:-}"
|
||||
echo " enable: ${TO_ENABLE[*]:-}"
|
||||
}
|
||||
|
||||
scenario() {
|
||||
# scenario <name> <hardware> <on> [toggle...]
|
||||
local name="$1"; HW="$2"; ON="$3"; shift 3
|
||||
rm -rf "$STATE_DIR"; REAPPLY=false
|
||||
detect_components
|
||||
local t
|
||||
for t in "$@"; do toggle_component "$t"; done
|
||||
show "== $name"
|
||||
}
|
||||
|
||||
run() {
|
||||
scenario "pc first run" "" ""
|
||||
scenario "pc first run, untick gaming" "" "" gaming
|
||||
scenario "pc single on" "" "" gaming single
|
||||
scenario "pc single then gaming off" "" "" single gaming
|
||||
scenario "pc boot desktop" "" "" boot
|
||||
scenario "pc boot desktop then gaming off" "" "" boot gaming
|
||||
scenario "pc silent only" "" "gaming" silent
|
||||
scenario "pc all on, theme off" "" "gaming boot silent theme glyphs single launcher steamgame notify" theme
|
||||
scenario "pc launcher off" "" "launcher steamgame" launcher
|
||||
scenario "pc steamgame on without launcher" "steam" "" gaming launcher steamgame
|
||||
scenario "machine first run" "fremont steam vram" ""
|
||||
scenario "machine silent hidden until boot desktop" "fremont steam vram" "gaming silent"
|
||||
scenario "machine boot desktop keeps silent" "fremont steam vram" "gaming silent" boot
|
||||
scenario "machine off" "fremont steam vram" "gaming machine poweroff" machine
|
||||
scenario "machine poweroff off" "fremont steam vram" "gaming machine poweroff" poweroff
|
||||
scenario "machine poweroff on brings machine" "fremont steam vram" "gaming" poweroff
|
||||
scenario "machine kpin removal" "fremont steam vram" "gaming machine poweroff kpin"
|
||||
scenario "nvidia first run" "nvidia steam" ""
|
||||
scenario "nvidia bigpicture off" "nvidia steam" "nvidia bigpicture" bigpicture
|
||||
scenario "nvidia nvsilent on" "nvidia steam" "nvidia bigpicture" nvsilent
|
||||
scenario "nvidia nvsilent then bigpicture" "nvidia steam" "nvidia" nvsilent bigpicture
|
||||
scenario "nvidia off" "nvidia steam" "nvidia bigpicture nvsilent" nvidia
|
||||
scenario "nvidia single" "nvidia steam" "" single
|
||||
scenario "nvidia gaming already on" "nvidia steam" "gaming" gaming
|
||||
|
||||
# Feature versions: an old record is ticked and re-applied.
|
||||
HW=""; ON="gaming theme"; rm -rf "$STATE_DIR"; REAPPLY=false
|
||||
state_set features gaming 2.1.0; state_set features theme 2.1.0
|
||||
detect_components; show "== outdated features"
|
||||
REAPPLY=true; ON="gaming theme launcher"; detect_components; show "== reapply (a)"
|
||||
REAPPLY=false
|
||||
|
||||
# The app's own rules (backend_apply's normalisation) go through the same plan.
|
||||
HW="fremont steam vram"; ON=""; rm -rf "$STATE_DIR"
|
||||
detect_components
|
||||
local sel
|
||||
for sel in "single" "boot" "poweroff" "silent" "kpin" "gaming boot" "launcher steamgame"; do
|
||||
echo "== backend_apply $sel"
|
||||
backend_sudo() { return 0; }
|
||||
backend_run_component() { return 0; }
|
||||
# shellcheck disable=SC2086
|
||||
backend_apply $sel | jq -c 'select(.event == "plan")'
|
||||
done
|
||||
HW="nvidia steam"; ON=""; detect_components
|
||||
for sel in "bigpicture" "nvsilent" "bigpicture nvsilent" "single" "boot"; do
|
||||
echo "== backend_apply nvidia $sel"
|
||||
# shellcheck disable=SC2086
|
||||
backend_apply $sel | jq -c 'select(.event == "plan")'
|
||||
done
|
||||
|
||||
# JSON for the app and the installer page.
|
||||
local hw
|
||||
for hw in "" "fremont steam vram" "nvidia steam"; do
|
||||
HW="$hw"; ON=""; rm -rf "$STATE_DIR"; detect_components
|
||||
echo "== defaults_list [$hw]"
|
||||
defaults_list | jq -S -c '.[]'
|
||||
echo "== backend_status [$hw]"
|
||||
backend_status | jq -S -c 'del(.kernel, .cecDevices, .leds)'
|
||||
done
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == --update ]]; then
|
||||
run > "$HERE/menu-test.golden" 2>&1
|
||||
echo "wrote $HERE/menu-test.golden ($(wc -l < "$HERE/menu-test.golden") lines)"
|
||||
elif diff -u "$HERE/menu-test.golden" <(run 2>&1); then
|
||||
echo "ok menu rules, plan and JSON match the golden file"
|
||||
else
|
||||
echo "FAIL menu rules changed (diff above; --update if intended)"; exit 1
|
||||
fi
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
|
||||
# one: tests/nvidia-test.sh). Run from this repo (REPO points at the Steamify checkout):
|
||||
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
|
||||
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
|
||||
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
|
||||
# Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help.
|
||||
# The Steamify checkout (REPO, default: the steamify-cachyos next to this repo)
|
||||
REPO="${REPO:-$(cd "$(dirname "$0")/../../steamify-cachyos" && pwd)}"; cd "$REPO" || exit 1
|
||||
# patch_file (lib/common.sh) reads the hook script from $SCRIPT_DIR/patches.
|
||||
SCRIPT_DIR="$PWD"
|
||||
REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}"
|
||||
source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
|
||||
mode="${1:-check}"
|
||||
fail=0
|
||||
say() { echo "$*" | tee -a "$REPORT"; }
|
||||
pass() { say "PASS $*"; }
|
||||
bad() { say "FAIL $*"; fail=1; }
|
||||
note() { say " $*"; }
|
||||
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
|
||||
|
||||
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
|
||||
|
||||
report_system() {
|
||||
say "-- GPU and software"
|
||||
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
|
||||
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
|
||||
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
|
||||
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
|
||||
done
|
||||
note "boot loader file: $(nvidia_boot_file || true)"
|
||||
note "cmdline: $(cat /proc/cmdline)"
|
||||
}
|
||||
|
||||
check_state() {
|
||||
say "-- Steamify's view"
|
||||
if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected"
|
||||
elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied"
|
||||
else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi
|
||||
for c in /sys/class/drm/card[0-9]*/device; do
|
||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')"
|
||||
done
|
||||
ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported"
|
||||
local p
|
||||
for p in $NVIDIA_PARAMS; do
|
||||
if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line"
|
||||
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
|
||||
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
|
||||
done
|
||||
say "-- the live NVIDIA driver"
|
||||
local m
|
||||
for m in modeset fbdev; do
|
||||
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
|
||||
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
|
||||
done
|
||||
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
|
||||
local c found=0
|
||||
for c in /sys/class/drm/card[0-9]*/device; do
|
||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
|
||||
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
|
||||
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
|
||||
done
|
||||
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
|
||||
say "-- initramfs"
|
||||
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
|
||||
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
|
||||
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
|
||||
say "-- what apply would change"
|
||||
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
|
||||
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
|
||||
}
|
||||
|
||||
case "$mode" in
|
||||
check)
|
||||
report_system; check_state ;;
|
||||
apply)
|
||||
report_system
|
||||
say "-- applying"
|
||||
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
|
||||
else bad "nvidia_enable failed (output above)"; fi
|
||||
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
|
||||
visual)
|
||||
report_system
|
||||
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
|
||||
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
|
||||
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
|
||||
say "visual result: $a: $what"
|
||||
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
|
||||
say "-- gamescope and NVIDIA lines from this boot's log"
|
||||
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
|
||||
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
|
||||
note "(more in $REPORT)" ;;
|
||||
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
|
||||
esac
|
||||
say ""; say "Report: $REPORT"
|
||||
exit $fail
|
||||
Executable
+207
@@ -0,0 +1,207 @@
|
||||
#!/bin/bash
|
||||
# Tests lib/nvidia.sh ("Gaming on NVIDIA" and its Big Picture option) and the menu rules around it, against a fake RTX 5080
|
||||
# (PCI 10de:2c02) beside an Intel iGPU, a stub modinfo, pacman and systemctl, and a temp home. No root, VM or NVIDIA
|
||||
# hardware needed: bash tests/nvidia-test.sh
|
||||
# The Steamify checkout (REPO, default: the steamify-cachyos next to this repo)
|
||||
REPO="${REPO:-$(cd "$(dirname "$0")/../../steamify-cachyos" && pwd)}"; cd "$REPO" || exit 1
|
||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
||||
fail=0
|
||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
||||
|
||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
||||
source lib/common.sh; source lib/state.sh; source lib/login-manager.sh; source lib/single-user.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; source lib/menu.sh
|
||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||
# KDE's config tools on plain files under the temp home (a relative file name is relative to ~/.config, as in KDE).
|
||||
kwriteconfig6() {
|
||||
local f="" k="" v="" del=0
|
||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; --delete) del=1 ;; *) v="$1" ;; esac; shift; done
|
||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"; mkdir -p "$(dirname "$f")"
|
||||
if [[ $del == 1 ]]; then sed -i "/^$k=/d" "$f" 2>/dev/null; else sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; fi
|
||||
}
|
||||
kreadconfig6() {
|
||||
local f="" k="" d="" r
|
||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --default) d="$2"; shift ;; --group) shift ;; esac; shift; done
|
||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"
|
||||
r="$(sed -n "s/^$k=//p" "$f" 2>/dev/null)"; printf '%s\n' "${r:-$d}"
|
||||
}
|
||||
# A pretend package database and systemd: what the tests assert on.
|
||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; ENABLED=0
|
||||
pacman() {
|
||||
case "$1" in
|
||||
-Q) [[ " $PKGS " == *" $2 "* ]] ;;
|
||||
-S) echo "S $*" >> "$PACMAN_LOG"; PKGS+=" ${*: -1}" ;;
|
||||
-Rns) echo "R $*" >> "$PACMAN_LOG"; PKGS=" ${PKGS//${*: -1}/} " ;;
|
||||
esac
|
||||
}
|
||||
user_systemctl() {
|
||||
case "$1" in
|
||||
enable) ENABLED=1 ;;
|
||||
disable) ENABLED=0 ;;
|
||||
is-enabled) [[ $ENABLED == 1 ]] ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
FAKE_DRIVER=1; modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
|
||||
GAMING_ON=0; gaming_status() { [[ "$GAMING_ON" == 1 ]]; }
|
||||
UNIT="$HOME/.config/systemd/user/$NVIDIA_UNIT"
|
||||
|
||||
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
|
||||
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
|
||||
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
|
||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
|
||||
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
|
||||
: > "$T/cmdline"; NVIDIA_CMDLINE="$T/cmdline" # the running kernel's command line: without the parameters
|
||||
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
|
||||
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
|
||||
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
|
||||
NVIDIA_MODULES_DIR="$T/mods"
|
||||
NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked
|
||||
mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd"
|
||||
# The component's kernel step edits this boot loader file (systemd-boot's) in the tests, never a real one.
|
||||
printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot-manage.conf"; nvidia_boot_file() { echo "$T/sdboot-manage.conf"; }
|
||||
|
||||
# --- detection
|
||||
check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
|
||||
FAKE_DRIVER=0; check "no nvidia_drm module (nouveau): not an NVIDIA PC" '! nvidia_present'
|
||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA GPU: not an NVIDIA PC" '! nvidia_present'
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- which items the menu shows
|
||||
check "NVIDIA PC: the SteamOS conversion and its gamescope options are hidden" '! component_available gaming && ! component_available boot && ! component_available glyphs'
|
||||
check "NVIDIA PC: Gaming on NVIDIA and Big Picture are shown" 'component_available nvidia && component_available bigpicture'
|
||||
GAMING_ON=1
|
||||
check "NVIDIA PC with the conversion already on: it is shown, so it can be turned off" 'component_available gaming && component_available boot'
|
||||
check "...and Gaming on NVIDIA is hidden (both would start Steam)" '! component_available nvidia && ! component_available bigpicture'
|
||||
GAMING_ON=0; NVIDIA_DRM_DIR="$T/none"
|
||||
check "no NVIDIA: the conversion is shown as before" 'component_available gaming && component_available boot'
|
||||
check "...and Gaming on NVIDIA is hidden" '! component_available nvidia && ! component_available bigpicture'
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- "Add as non-Steam game" is for gaming mode's controller: not offered on an NVIDIA PC (unless already on)
|
||||
steamgame_available() { return 0; }; STEAMGAME_ON=0; steamgame_status() { [[ "$STEAMGAME_ON" == 1 ]]; }
|
||||
check "NVIDIA PC: Add as non-Steam game is hidden" '! component_available steamgame'
|
||||
STEAMGAME_ON=1; check "...unless it is already on (so it can be turned off)" 'component_available steamgame'; STEAMGAME_ON=0
|
||||
NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA: it is offered as before" 'component_available steamgame'
|
||||
steamgame_available() { return 1; }; check "no NVIDIA, no Steam account yet: still not offered" '! component_available steamgame'
|
||||
steamgame_available() { return 0; }; NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- turning it on
|
||||
check "off to begin with" '! nvidia_status && ! bigpicture_status'
|
||||
nvidia_enable
|
||||
check "Steam is installed when missing, and recorded as ours" 'grep -q "^S " "$PACMAN_LOG" && [[ "$(state_get nvidia installed_pkgs)" == steam ]]'
|
||||
check "the autostart unit is written: Steam without arguments" 'grep -q "^ExecStart=/usr/bin/steam $" "$UNIT"'
|
||||
check "it is on" 'nvidia_status && ! bigpicture_status'
|
||||
n="$(wc -l < "$PACMAN_LOG")"; nvidia_enable
|
||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||
|
||||
# --- Big Picture
|
||||
bigpicture_enable
|
||||
check "Big Picture: Steam starts with -gamepadui" 'grep -q "^ExecStart=/usr/bin/steam -gamepadui$" "$UNIT" && bigpicture_status'
|
||||
nvidia_enable
|
||||
check "turning Gaming on NVIDIA on again keeps Big Picture" 'bigpicture_status'
|
||||
check "Big Picture: Plasma starts with an empty session" '[[ "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" == emptySession ]]'
|
||||
bigpicture_disable
|
||||
check "Big Picture off: Steam's normal window again" '! bigpicture_status && nvidia_status'
|
||||
check "...and the session setting is back as it was (not set)" '[[ -z "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" ]]'
|
||||
|
||||
# --- turning it off
|
||||
bigpicture_enable; nvidia_disable
|
||||
check "off: the unit is gone and Steam, which we installed, is removed" '! nvidia_status && [[ ! -e "$UNIT" ]] && ! pacman -Q steam && [[ -z "$(state_get nvidia installed_pkgs)" ]]'
|
||||
check "Big Picture without the unit does nothing" 'bigpicture_enable && bigpicture_disable && [[ ! -e "$UNIT" ]]'
|
||||
|
||||
# --- Steam that was there already is never removed
|
||||
PKGS=" steam"; : > "$PACMAN_LOG"
|
||||
nvidia_enable; nvidia_disable
|
||||
check "Steam installed before is kept, and not installed again" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q steam'
|
||||
|
||||
# --- kernel parameters and early modules (a supported card only: RTX 20 series or newer)
|
||||
check "RTX 5080 (2c02) is supported: no chwd legacy lists" nvidia_supported
|
||||
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
|
||||
check "RTX 5080 is not on a legacy list" 'nvidia_supported && ! nvidia_legacy_gpu'
|
||||
echo 0x1c03 > "$T/drm/card1/device/device"
|
||||
check "GTX 1060 (older than RTX 20): no kernel setup, but still an NVIDIA PC" '! nvidia_supported && nvidia_legacy_gpu && nvidia_present'
|
||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
||||
|
||||
for loader in limine limineplus sdboot grub; do
|
||||
case $loader in
|
||||
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
|
||||
# CachyOS writes its line as "+=" and may already have nvidia_drm.modeset=1 in it.
|
||||
limineplus) F="$T/limine"; printf 'KERNEL_CMDLINE[default]+="quiet splash nvidia_drm.modeset=1"\n' > "$F" ;;
|
||||
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
|
||||
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
|
||||
esac
|
||||
nvidia_boot_file() { echo "$F"; }
|
||||
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
|
||||
nvidia_kernel_enable
|
||||
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
|
||||
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
|
||||
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
|
||||
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
|
||||
SUM="$(cat "$F")"; nvidia_kernel_enable
|
||||
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
|
||||
nvidia_kernel_disable
|
||||
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
|
||||
done
|
||||
|
||||
# A missing patches/ file must be an error, never an empty script or hook.
|
||||
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
|
||||
# The pacman hook's script decides again at every kernel change.
|
||||
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
|
||||
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
|
||||
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
|
||||
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
|
||||
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
|
||||
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
rm -rf "$T/mods/5.0.0-leftover"; nvidia_kernel_disable
|
||||
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
|
||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
|
||||
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_kernel_enable
|
||||
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
|
||||
rm -rf "$T/mods/6.6.0-lts"
|
||||
# Generated boot entries without the parameters (the initramfs build failed): an error.
|
||||
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
|
||||
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
|
||||
check "boot entries without the parameters: error" '! nvidia_kernel_enable >/dev/null'
|
||||
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
|
||||
# A config file without the setting to edit: an error, not "applied".
|
||||
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
|
||||
check "no setting to edit: error, nothing rebuilt" '! nvidia_kernel_enable >/dev/null && [[ $REBUILDS == 0 ]]'
|
||||
FAKE_DRIVER=0; NVIDIA_DRM_DIR="$T/drm"; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_kernel_enable
|
||||
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
|
||||
|
||||
# --- single user mode on NVIDIA: its own login step (SDDM, autologin into Plasma) without the conversion
|
||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/drm" # an earlier section ended without the driver
|
||||
SW="$T/switches.log"; : > "$SW"; TARGET_USER=tester; SINGLE_AUTOLOGIN="$T/sddm.conf.d/zzz-steamify-autologin.conf"
|
||||
switch_to_sddm() { echo sddm >> "$SW"; }; switch_to_plasmalogin() { echo plasmalogin >> "$SW"; }
|
||||
remove_sddm_base_autologin() { :; } # would look at the real /etc/sddm.conf
|
||||
GAMING_ON=0
|
||||
check "single user mode is offered on NVIDIA without the conversion..." 'component_available single'
|
||||
GAMING_ON=1; check "...and with it" 'component_available single'; GAMING_ON=0
|
||||
single_login_enable
|
||||
check "single user: SDDM, autologin of the user into the Plasma session" 'grep -qx "User=tester" "$SINGLE_AUTOLOGIN" && grep -qx "Session=plasma.desktop" "$SINGLE_AUTOLOGIN" && grep -qx "Relogin=true" "$SINGLE_AUTOLOGIN" && grep -qx sddm "$SW"'
|
||||
c1="$(cat "$SINGLE_AUTOLOGIN")"; single_login_enable
|
||||
check "single user login: a second run changes nothing" '[[ "$(cat "$SINGLE_AUTOLOGIN")" == "$c1" ]]'
|
||||
single_login_disable
|
||||
check "single user off: the file is gone and plasma-login-manager is the login manager again" '[[ ! -e "$SINGLE_AUTOLOGIN" ]] && grep -qx plasmalogin "$SW"'
|
||||
: > "$SW"; GAMING_ON=1; single_login_enable
|
||||
check "with the conversion on, single user mode leaves the login to it" '[[ ! -e "$SINGLE_AUTOLOGIN" && ! -s "$SW" ]]'
|
||||
GAMING_ON=0
|
||||
# --- the menu rules
|
||||
declare -A WANTED=([nvidia]=1 [bigpicture]=1 [gaming]=0 [boot]=0 [single]=0 [machine]=0 [poweroff]=0 [launcher]=0 [steamgame]=0)
|
||||
component_selectable() { return 0; }
|
||||
toggle_component nvidia
|
||||
check "unticking Gaming on NVIDIA unticks Big Picture" '[[ "${WANTED[nvidia]}" == 0 && "${WANTED[bigpicture]}" == 0 ]]'
|
||||
toggle_component bigpicture
|
||||
check "ticking Big Picture ticks Gaming on NVIDIA" '[[ "${WANTED[nvidia]}" == 1 && "${WANTED[bigpicture]}" == 1 ]]'
|
||||
WANTED[single]=0; WANTED[gaming]=0; toggle_component single
|
||||
check "ticking single user mode does not tick the conversion where it isn't offered" '[[ "${WANTED[single]}" == 1 && "${WANTED[gaming]}" == 0 ]]'
|
||||
check "Big Picture follows Gaming on NVIDIA in the menu" '[[ " ${COMPONENTS[*]} " == *" nvidia bigpicture "* && "${PARENT[bigpicture]}" == nvidia ]]'
|
||||
|
||||
exit $fail
|
||||
@@ -0,0 +1,161 @@
|
||||
"""Unit tests of the Python helpers in steamify-cachyos/patches (stdlib only).
|
||||
|
||||
Run through tests/python-test.sh (REPO = the Steamify checkout), or:
|
||||
REPO=../steamify-cachyos python3 -m unittest tests/patches_test.py -v
|
||||
"""
|
||||
import contextlib
|
||||
import importlib.util
|
||||
import io
|
||||
import os
|
||||
import struct
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
REPO = os.environ.get("REPO") or os.path.join(os.path.dirname(__file__), "..", "..", "steamify-cachyos")
|
||||
|
||||
|
||||
def load(name, filename):
|
||||
spec = importlib.util.spec_from_file_location(name, os.path.join(REPO, "patches", filename))
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
shortcuts = load("steam_shortcuts", "steam-shortcuts.py")
|
||||
notifier = load("steamify_notifier", "steamify-notifier.py")
|
||||
|
||||
|
||||
class VdfTests(unittest.TestCase):
|
||||
def test_roundtrip(self):
|
||||
root = [("shortcuts", [("0", [("appid", 123), ("AppName", "A"), ("tags", [])])])]
|
||||
self.assertEqual(shortcuts.parse(shortcuts.dump(root)), root)
|
||||
|
||||
def test_empty_data_is_an_empty_list(self):
|
||||
self.assertEqual(shortcuts.parse(b""), [("shortcuts", [])])
|
||||
|
||||
def test_unknown_type_is_an_error(self):
|
||||
with self.assertRaises(ValueError):
|
||||
shortcuts.parse(b"\x07key\0")
|
||||
|
||||
def test_ints_are_unsigned_32_bit(self):
|
||||
data = shortcuts.dump([("n", -1)])
|
||||
self.assertEqual(struct.unpack_from("<I", data, 3)[0], 0xFFFFFFFF)
|
||||
|
||||
def test_keys_match_regardless_of_case(self):
|
||||
entry = [("AppName", "x")]
|
||||
self.assertEqual(shortcuts.get(entry, "appname"), "x")
|
||||
shortcuts.put(entry, "APPNAME", "y")
|
||||
self.assertEqual(entry, [("AppName", "y")])
|
||||
|
||||
def test_ours(self):
|
||||
exe = "/home/u/.local/share/steamify/bin/run-app"
|
||||
self.assertTrue(shortcuts.ours([("Exe", f'"{exe}"')], exe))
|
||||
# An older install's start script counts as ours: updated, not doubled.
|
||||
self.assertTrue(shortcuts.ours([("Exe", '"/home/u/.local/share/cachyos-gamescope-boot/bin/run-app"')], exe))
|
||||
self.assertFalse(shortcuts.ours([("Exe", '"/usr/bin/other"')], exe))
|
||||
self.assertFalse(shortcuts.ours([("Exe", '"/home/u/games/run-app"')], exe))
|
||||
|
||||
|
||||
class ShortcutsCommandTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.dir = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.dir.cleanup)
|
||||
self.vdf = os.path.join(self.dir.name, "userdata", "1", "config", "shortcuts.vdf")
|
||||
self.exe = "/home/u/.local/share/steamify/bin/run-app"
|
||||
|
||||
def run_cmd(self, *args):
|
||||
out = io.StringIO()
|
||||
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(io.StringIO()):
|
||||
rc = shortcuts.main(["steam-shortcuts.py", *args])
|
||||
return rc, out.getvalue().strip()
|
||||
|
||||
def entries(self):
|
||||
return shortcuts.shortcuts(shortcuts.load(self.vdf))
|
||||
|
||||
def test_add_creates_the_file_and_an_entry(self):
|
||||
rc, out = self.run_cmd("add", self.vdf, "Steamify", self.exe, "/icon.png", "steamify.desktop")
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertTrue(out.startswith("added "))
|
||||
(_, entry), = self.entries()
|
||||
self.assertEqual(shortcuts.get(entry, "AppName"), "Steamify")
|
||||
self.assertEqual(shortcuts.get(entry, "Exe"), f'"{self.exe}"')
|
||||
# Steam's id for a shortcut has the top bit set.
|
||||
self.assertGreaterEqual(shortcuts.get(entry, "appid"), 0x80000000)
|
||||
self.assertEqual(out, f"added {shortcuts.get(entry, 'appid')}")
|
||||
|
||||
def test_add_twice_updates_instead_of_doubling(self):
|
||||
self.run_cmd("add", self.vdf, "Steamify", self.exe, "/a.png", "a.desktop")
|
||||
rc, out = self.run_cmd("add", self.vdf, "Steamify 2", self.exe, "/b.png", "b.desktop")
|
||||
self.assertTrue(out.startswith("updated "))
|
||||
entries = self.entries()
|
||||
self.assertEqual(len(entries), 1)
|
||||
self.assertEqual(shortcuts.get(entries[0][1], "AppName"), "Steamify 2")
|
||||
self.assertEqual(shortcuts.get(entries[0][1], "icon"), "/b.png")
|
||||
|
||||
def test_other_entries_are_kept(self):
|
||||
self.run_cmd("add", self.vdf, "Other", "/usr/bin/other", "", "")
|
||||
self.run_cmd("add", self.vdf, "Steamify", self.exe, "", "")
|
||||
self.assertEqual(len(self.entries()), 2)
|
||||
self.assertEqual([k for k, _ in self.entries()], ["0", "1"])
|
||||
|
||||
def test_find(self):
|
||||
self.assertEqual(self.run_cmd("find", self.vdf, self.exe)[0], 1)
|
||||
_, out = self.run_cmd("add", self.vdf, "Steamify", self.exe, "", "")
|
||||
rc, found = self.run_cmd("find", self.vdf, self.exe)
|
||||
self.assertEqual((rc, found), (0, out.split()[1]))
|
||||
|
||||
def test_remove_by_appid_renumbers(self):
|
||||
self.run_cmd("add", self.vdf, "Other", "/usr/bin/other", "", "")
|
||||
_, out = self.run_cmd("add", self.vdf, "Steamify", self.exe, "", "")
|
||||
self.assertEqual(self.run_cmd("remove", self.vdf, out.split()[1])[0], 0)
|
||||
entries = self.entries()
|
||||
self.assertEqual([k for k, _ in entries], ["0"])
|
||||
self.assertEqual(shortcuts.get(entries[0][1], "AppName"), "Other")
|
||||
|
||||
def test_remove_of_nothing_leaves_the_file_alone(self):
|
||||
self.run_cmd("add", self.vdf, "Steamify", self.exe, "", "")
|
||||
with open(self.vdf, "rb") as f:
|
||||
before = f.read()
|
||||
self.assertEqual(self.run_cmd("remove", self.vdf, "999")[0], 0)
|
||||
with open(self.vdf, "rb") as f:
|
||||
self.assertEqual(f.read(), before)
|
||||
|
||||
def test_unknown_command(self):
|
||||
self.assertEqual(self.run_cmd("bogus", self.vdf)[0], 2)
|
||||
|
||||
|
||||
class NotifierTests(unittest.TestCase):
|
||||
def test_version(self):
|
||||
self.assertEqual(notifier.version("v2.11.1"), (2, 11, 1))
|
||||
self.assertEqual(notifier.version("2.9.0"), (2, 9, 0))
|
||||
self.assertIsNone(notifier.version("nightly"))
|
||||
|
||||
def test_versions_compare_as_numbers(self):
|
||||
self.assertGreater(notifier.version("2.10.0"), notifier.version("2.9.0"))
|
||||
|
||||
def pending(self, new, seen="", skipped=""):
|
||||
values = {"seen": seen, "skipped": skipped}
|
||||
with mock.patch.object(notifier, "state", lambda key: values[key]):
|
||||
return notifier.pending(new)
|
||||
|
||||
def test_newer_than_seen(self):
|
||||
self.assertTrue(self.pending("2.12.0", seen="2.11.1"))
|
||||
|
||||
def test_same_or_older_is_not_pending(self):
|
||||
self.assertFalse(self.pending("2.11.1", seen="2.11.1"))
|
||||
self.assertFalse(self.pending("2.9.0", seen="2.11.1"))
|
||||
|
||||
def test_skipped_version_is_not_pending(self):
|
||||
self.assertFalse(self.pending("2.12.0", seen="2.11.1", skipped="2.12.0"))
|
||||
|
||||
def test_nothing_seen_yet(self):
|
||||
self.assertTrue(self.pending("2.12.0", seen=""))
|
||||
|
||||
def test_unparsable_tag_is_not_pending(self):
|
||||
# A release tag like "nightly" must not crash the daily check.
|
||||
self.assertFalse(self.pending("nightly", seen="2.11.1"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# Unit tests of the Python helpers in steamify-cachyos/patches (steam-shortcuts.py,
|
||||
# steamify-notifier.py). No root, VM or hardware needed: bash tests/python-test.sh
|
||||
# The Steamify checkout (REPO, default: the steamify-cachyos next to this repo)
|
||||
REPO="${REPO:-$(cd "$(dirname "$0")/../../steamify-cachyos" && pwd)}"
|
||||
export REPO
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
if python3 -B -m unittest tests/patches_test.py 2>&1 | tail -n 25 | tee /dev/stderr | grep -q '^OK'; then
|
||||
echo "ok Python helpers"
|
||||
else
|
||||
echo "FAIL Python helpers"; exit 1
|
||||
fi
|
||||
Reference in new issue
Block a user