forked from unom/punktfunk
feat(install): pick per-distro defaults from user intent
The guided installer defaulted every option to no, so Bazzite and Nobara users who held Enter got a degraded pad and no linger — the opposite of those distro pages. Prompts now name the intent, defaults follow the box, and a summary prints before the first sudo. Fixes #431
This commit is contained in:
@@ -18,14 +18,25 @@ on:
|
||||
paths:
|
||||
- scripts/install.sh
|
||||
- data/platforms.json
|
||||
- scripts/ci/check-install-defaults.sh
|
||||
- .gitea/workflows/installer-smoke.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- scripts/install.sh
|
||||
- data/platforms.json
|
||||
- scripts/ci/check-install-defaults.sh
|
||||
- .gitea/workflows/installer-smoke.yml
|
||||
|
||||
jobs:
|
||||
defaults:
|
||||
name: derived defaults
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Assert per-family installer defaults
|
||||
run: sh scripts/ci/check-install-defaults.sh
|
||||
|
||||
smoke:
|
||||
name: smoke (${{ matrix.family }})
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
@@ -9,8 +9,10 @@ Steam **Gaming Mode** and the **KDE desktop**, and follows the box when you swit
|
||||
Nothing in the config picks a mode.
|
||||
|
||||
**One command instead?** The [guided installer](/docs/install#guided-install-preview) (preview) does
|
||||
everything on this page — it detects the distro, installs the host, joins the groups, opens the
|
||||
firewall and starts it:
|
||||
everything on this page — it detects the distro, installs the host, joins the `input` and
|
||||
`punktfunk` groups, enables linger, opens the firewall and starts it. Those last two match the
|
||||
hand steps below (Bazzite hosts are usually headless, and the virtual Steam Deck pad needs the
|
||||
group):
|
||||
|
||||
<Installer />
|
||||
|
||||
|
||||
@@ -54,9 +54,10 @@ Versions before this one stopped the display manager for the stream's duration
|
||||
root helper, the `punktfunk` group, and lingering, and left the box with nothing able to start a
|
||||
desktop session, so Steam's own "Switch to Desktop" hung until a reboot.
|
||||
|
||||
> **Join the `punktfunk` group on any box you stream Game Mode from.** The takeover itself no
|
||||
> longer needs it — the group now gates the usbip nodes the virtual Steam Deck pad attaches
|
||||
> through, so without it the pad arrives as an ordinary Xbox 360 controller:
|
||||
> **Join the `punktfunk` group on any box you stream Game Mode from.** The guided installer
|
||||
> defaults to yes on Bazzite, Nobara, and other `ujust` / Fedora Atomic boxes. The takeover
|
||||
> itself no longer needs the group — it now gates the usbip nodes the virtual Steam Deck pad
|
||||
> attaches through, so without it the pad arrives as an ordinary Xbox 360 controller:
|
||||
>
|
||||
> ```sh
|
||||
> sudo usermod -aG punktfunk "$USER" # then log out and back in
|
||||
|
||||
@@ -35,15 +35,17 @@ Prefer to read what runs first (it's plain `sh`, ~450 lines):
|
||||
|
||||
<Installer inspect />
|
||||
|
||||
It asks before anything optional (Moonlight compat, the shared clipboard, the `punktfunk` group,
|
||||
starting at boot) and every answer has a default, so `sh install.sh --yes` — or piping it with no
|
||||
terminal — runs unattended; `--channel stable|canary`, `--mgmt-port`, `--no-start`, `--uninstall` and the environment
|
||||
twins (`PUNKTFUNK_INSTALL_YES`, `PUNKTFUNK_INSTALL_CHANNEL`, `PUNKTFUNK_INSTALL_GAMESTREAM`,
|
||||
`PUNKTFUNK_INSTALL_CLIPBOARD`, `PUNKTFUNK_INSTALL_PUNKTFUNK_GROUP`, `PUNKTFUNK_INSTALL_LINGER`,
|
||||
`PUNKTFUNK_INSTALL_MGMT_PORT`) are listed by `--help`. It covers Ubuntu/Debian, Fedora, Arch-family
|
||||
and Bazzite/Fedora Atomic; NixOS, SteamOS and Windows it points at their pages. **Preview:** the
|
||||
per-system pages above remain the documented path, and the script runs exactly the install commands
|
||||
they show (CI fails if the two drift apart). Re-running is safe.
|
||||
It asks about intent, not internals (full controller, third-party Moonlight clients, clipboard,
|
||||
start at boot) and every answer has a default, so `sh install.sh --yes` — or piping it with no
|
||||
terminal — runs unattended. The default follows the box: Bazzite and Nobara join the `punktfunk`
|
||||
group and linger; an active Sunshine/Apollo host opts into Moonlight compat; a seatless SSH
|
||||
session lingers. Clipboard stays off. `--channel stable|canary`, `--mgmt-port`, `--no-start`,
|
||||
`--uninstall` and the environment twins (`PUNKTFUNK_INSTALL_YES`, `PUNKTFUNK_INSTALL_CHANNEL`,
|
||||
`PUNKTFUNK_INSTALL_GAMESTREAM`, `PUNKTFUNK_INSTALL_CLIPBOARD`, `PUNKTFUNK_INSTALL_PUNKTFUNK_GROUP`,
|
||||
`PUNKTFUNK_INSTALL_LINGER`, `PUNKTFUNK_INSTALL_MGMT_PORT`) are listed by `--help`. It covers
|
||||
Ubuntu/Debian, Fedora, Arch-family and Bazzite/Fedora Atomic; NixOS, SteamOS and Windows it points
|
||||
at their pages. **Preview:** the per-system pages above remain the documented path, and the script
|
||||
runs exactly the install commands they show (CI fails if the two drift apart). Re-running is safe.
|
||||
|
||||
`--channel` also **switches** a host that is already installed — see
|
||||
[Release Channels](/docs/channels#switch-an-installed-box-between-channels). Without the flag the
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
# 7. The installer under --dry-run against faked os-release files detects every family it claims
|
||||
# to (and --uninstall prints each family's removal) — the committed half of the manual
|
||||
# 16-file matrix PR #345 was verified with. Needs curl on PATH (the script's own prerequisite).
|
||||
# Per-family *defaults* (group / linger / GameStream) live in check-install-defaults.sh.
|
||||
# 8. scripts/web-init.sh — the web console's host-readiness gate — actually waits for the host's
|
||||
# first-run files and actually stops waiting when they land, against a faked config dir. Not
|
||||
# docs drift, but the same shape: a packaging script no build exercises, whose failure mode
|
||||
@@ -165,6 +166,7 @@ installer_case fedora-rm 'ID=fedora\nVERSION_ID=44\n' 'yum.rep
|
||||
installer_case arch-rm 'ID=arch\n' '/etc/pacman.conf' --uninstall
|
||||
installer_case omarchy-rm 'ID=omarchy\nID_LIKE=arch\n' 'punktfunk-omarchy remove' --uninstall
|
||||
installer_case bazzite-rm 'ID=bazzite\nID_LIKE="fedora"\nVERSION_ID=43\n' 'punktfunk-sysext remove' --uninstall
|
||||
sh scripts/ci/check-install-defaults.sh || fail=1
|
||||
|
||||
# ---------------------------------------------------------------- gate 8: channel switching
|
||||
# A box that already has all three binaries, on a repo config naming one channel, told --channel
|
||||
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/bin/sh
|
||||
# Derived defaults for the guided installer (scripts/install.sh, issue #431).
|
||||
# Faked os-release + --dry-run --yes --no-start: each family must print the summary that
|
||||
# --yes would actually take, and that summary must appear before the first sudo.
|
||||
# DISPLAY / WAYLAND_DISPLAY / XDG_SESSION_TYPE are pinned per case so a graphical seat on
|
||||
# the machine running the gate cannot leak into a "headless" assertion.
|
||||
set -u
|
||||
cd "$(dirname "$0")/../.." || exit 2
|
||||
|
||||
fail=0
|
||||
osr=$(mktemp -d)
|
||||
gsbin=$(mktemp -d)
|
||||
ujbin=$(mktemp -d)
|
||||
trap 'rm -rf "$osr" "$gsbin" "$ujbin"' EXIT
|
||||
|
||||
# name os-release-body seat(desktop|headless) extra-PATH-dir expected-substring [install.sh args...]
|
||||
defaults_case() {
|
||||
name=$1
|
||||
printf '%b' "$2" > "$osr/$name"
|
||||
seat=$3
|
||||
extra=$4
|
||||
want=$5
|
||||
shift 5
|
||||
case "$seat" in
|
||||
desktop) _env="DISPLAY=:0 WAYLAND_DISPLAY= XDG_SESSION_TYPE=x11" ;;
|
||||
headless) _env="DISPLAY= WAYLAND_DISPLAY= XDG_SESSION_TYPE=" ;;
|
||||
*) echo "::error::defaults_case $name: seat must be desktop or headless, got '$seat'"; fail=1; return ;;
|
||||
esac
|
||||
# $_env is expanded on purpose: the seat pins must override a graphical session on the
|
||||
# machine running the gate. Quoted "$@" are extra install.sh flags (e.g. --no-punktfunk-group).
|
||||
out=$(env $_env PATH="${extra:+$extra:}$PATH" \
|
||||
PUNKTFUNK_INSTALL_OS_RELEASE="$osr/$name" \
|
||||
sh scripts/install.sh --dry-run --yes --no-start "$@" 2>&1) || {
|
||||
echo "::error::scripts/install.sh --dry-run --yes --no-start on fake $name ($seat) exited $?"
|
||||
printf '%s\n' "$out" | sed 's/^/ /'
|
||||
fail=1
|
||||
return
|
||||
}
|
||||
case "$out" in
|
||||
*"$want"*) ;;
|
||||
*)
|
||||
echo "::error::scripts/install.sh --dry-run on fake $name ($seat) did not print '$want':"
|
||||
printf '%s\n' "$out" | sed 's/^/ /'
|
||||
fail=1
|
||||
return ;;
|
||||
esac
|
||||
# Summary is the audit trail for --yes; it has to land before any privileged command.
|
||||
# A re-run on a box that already has the host may print no sudo at all — Choices must
|
||||
# still appear; when sudo does print, it must not come first.
|
||||
if ! printf '%s\n' "$out" | awk '
|
||||
/Choices \(nothing below has run yet\)/ { c=NR }
|
||||
index($0, " + sudo") && !s { s=NR }
|
||||
END { if (!c) exit 1; if (s && c > s) exit 1 }
|
||||
'; then
|
||||
echo "::error::scripts/install.sh --dry-run on fake $name ($seat): Choices must print before the first '+ sudo':"
|
||||
printf '%s\n' "$out" | sed 's/^/ /'
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
DEB='ID=debian\nVERSION_ID=13\nPRETTY_NAME="Debian GNU/Linux 13"\n'
|
||||
FED='ID=fedora\nVERSION_ID=44\nPRETTY_NAME="Fedora Linux 44"\n'
|
||||
ARCH='ID=arch\nPRETTY_NAME="Arch Linux"\n'
|
||||
OMA='ID=omarchy\nID_LIKE=arch\nVERSION_ID=4.0.1\nPRETTY_NAME="Omarchy"\n'
|
||||
BAZ='ID=bazzite\nID_LIKE="fedora"\nVERSION_ID=43\nPRETTY_NAME="Bazzite"\n'
|
||||
NOB='ID=nobara\nID_LIKE="fedora"\nVERSION_ID=43\nPRETTY_NAME="Nobara Linux"\n'
|
||||
|
||||
# Desktop seat: only the couch/HTPC distros flip group + linger on.
|
||||
defaults_case debian-desk "$DEB" desktop '' 'Full controller: no'
|
||||
defaults_case debian-desk2 "$DEB" desktop '' 'Third-party clients (Moonlight, Artemis): no'
|
||||
defaults_case debian-desk3 "$DEB" desktop '' 'Shared clipboard: no'
|
||||
defaults_case debian-desk4 "$DEB" desktop '' 'Start at boot with nobody logged in: no'
|
||||
defaults_case fedora-desk "$FED" desktop '' 'Full controller: no'
|
||||
defaults_case fedora-desk2 "$FED" desktop '' 'Start at boot with nobody logged in: no'
|
||||
defaults_case arch-desk "$ARCH" desktop '' 'Full controller: no'
|
||||
defaults_case arch-desk2 "$ARCH" desktop '' 'Start at boot with nobody logged in: no'
|
||||
# Omarchy is a sit-at Arch flavour, not a couch/HTPC default — linger only if the session is seatless.
|
||||
defaults_case omarchy-desk "$OMA" desktop '' 'Full controller: no'
|
||||
defaults_case omarchy-desk2 "$OMA" desktop '' 'Start at boot with nobody logged in: no'
|
||||
defaults_case omarchy-ssh "$OMA" headless '' 'Start at boot with nobody logged in: yes (no graphical session)'
|
||||
|
||||
defaults_case bazzite-desk "$BAZ" desktop '' 'Full controller: yes (Bazzite — virtual Steam Deck pad)'
|
||||
defaults_case bazzite-desk2 "$BAZ" desktop '' 'Start at boot with nobody logged in: yes (Bazzite hosts are usually headless)'
|
||||
defaults_case bazzite-desk3 "$BAZ" desktop '' 'Third-party clients (Moonlight, Artemis): no'
|
||||
defaults_case bazzite-desk4 "$BAZ" desktop '' 'Shared clipboard: no'
|
||||
|
||||
defaults_case nobara-desk "$NOB" desktop '' 'Full controller: yes (Nobara — virtual Steam Deck pad)'
|
||||
defaults_case nobara-desk2 "$NOB" desktop '' 'Start at boot with nobody logged in: yes (Nobara hosts are usually headless)'
|
||||
# Flags/env still win over the distro default.
|
||||
defaults_case bazzite-flag "$BAZ" desktop '' 'Full controller: no' --no-punktfunk-group
|
||||
|
||||
# No graphical seat (SSH, CI, a pipe) → linger even on a generic distro.
|
||||
defaults_case debian-ssh "$DEB" headless '' 'Start at boot with nobody logged in: yes (no graphical session)'
|
||||
defaults_case debian-ssh2 "$DEB" headless '' 'Full controller: no'
|
||||
|
||||
# Active Sunshine-family host (detect-conflicts exit 1) → Moonlight compat defaults on.
|
||||
# A dormant leftover is not enough — that is the same split detect-conflicts uses.
|
||||
cat > "$gsbin/punktfunk-host" <<'EOF'
|
||||
#!/bin/sh
|
||||
if [ "${1:-}" = detect-conflicts ]; then
|
||||
echo "Sunshine is running"
|
||||
exit 1
|
||||
fi
|
||||
echo 0.0.0-test
|
||||
EOF
|
||||
chmod +x "$gsbin/punktfunk-host"
|
||||
defaults_case debian-gs "$DEB" desktop "$gsbin" 'Third-party clients (Moonlight, Artemis): yes (Sunshine/Apollo already on this box)'
|
||||
defaults_case debian-gs2 "$DEB" desktop "$gsbin" 'Full controller: no'
|
||||
|
||||
# ujust is how Bazzite-shaped boxes that aren't ID=bazzite still identify.
|
||||
printf '#!/bin/sh\nexit 0\n' > "$ujbin/ujust"
|
||||
chmod +x "$ujbin/ujust"
|
||||
defaults_case debian-ujust "$DEB" desktop "$ujbin" 'Full controller: yes (Game Mode / HTPC box — virtual Steam Deck pad)'
|
||||
defaults_case debian-ujust2 "$DEB" desktop "$ujbin" 'Start at boot with nobody logged in: yes (Game Mode / HTPC box)'
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "installer default matrix failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "installer default matrix ok"
|
||||
+132
-26
@@ -4,10 +4,11 @@
|
||||
# curl -fsSL https://punktfunk.unom.io/install.sh | sh
|
||||
# curl -fsSLO https://punktfunk.unom.io/install.sh && sh install.sh --help # read it first
|
||||
#
|
||||
# Zero-to-streaming for a Linux host: detect the distro → add the package repo → install → deal
|
||||
# with a Sunshine/Apollo/Vibeshine already on the box (move one port) → groups → options →
|
||||
# firewall → start the services → verify → print how to pair. Plain POSIX sh, `read` prompts,
|
||||
# no TUI. Every prompt has a default so `--yes` (or no terminal) runs unattended.
|
||||
# Zero-to-streaming for a Linux host: detect the distro → ask intent (not internals) → print
|
||||
# the choices → add the package repo → install → deal with a Sunshine/Apollo/Vibeshine already
|
||||
# on the box (move one port) → groups → options → firewall → start the services → verify →
|
||||
# print how to pair. Plain POSIX sh, `read` prompts, no TUI. Every prompt has a default so
|
||||
# `--yes` (or no terminal) runs unattended; the default follows the box, not a global no.
|
||||
#
|
||||
# This is WP4 of the docs-and-onboarding overhaul and is labelled PREVIEW on purpose: the per-distro
|
||||
# docs pages (https://docs.punktfunk.unom.io/docs/install) remain the documented default until it
|
||||
@@ -25,10 +26,10 @@ USER=${USER:-$(id -un)}; export USER
|
||||
YES=${PUNKTFUNK_INSTALL_YES:-0}
|
||||
CHANNEL=${PUNKTFUNK_INSTALL_CHANNEL:-stable}
|
||||
CHANNEL_SET=0; [ -n "${PUNKTFUNK_INSTALL_CHANNEL:-}" ] && CHANNEL_SET=1 # asked for, vs. defaulted
|
||||
GAMESTREAM=${PUNKTFUNK_INSTALL_GAMESTREAM:-} # 1/0, empty = ask (default no)
|
||||
CLIPBOARD=${PUNKTFUNK_INSTALL_CLIPBOARD:-} # 1/0, empty = ask (default no)
|
||||
PF_GROUP=${PUNKTFUNK_INSTALL_PUNKTFUNK_GROUP:-} # 1/0, empty = ask (default no)
|
||||
LINGER=${PUNKTFUNK_INSTALL_LINGER:-} # 1/0, empty = ask (default no)
|
||||
GAMESTREAM=${PUNKTFUNK_INSTALL_GAMESTREAM:-} # 1/0, empty = ask
|
||||
CLIPBOARD=${PUNKTFUNK_INSTALL_CLIPBOARD:-} # 1/0, empty = ask
|
||||
PF_GROUP=${PUNKTFUNK_INSTALL_PUNKTFUNK_GROUP:-} # 1/0, empty = ask
|
||||
LINGER=${PUNKTFUNK_INSTALL_LINGER:-} # 1/0, empty = ask
|
||||
MGMT_PORT=${PUNKTFUNK_INSTALL_MGMT_PORT:-47991} # where the management API moves to on a conflict
|
||||
START=1
|
||||
DRY=${PUNKTFUNK_INSTALL_DRY_RUN:-0}
|
||||
@@ -42,10 +43,10 @@ usage: sh install.sh [options]
|
||||
-y, --yes no prompts: take every default (also the behaviour without a terminal)
|
||||
--channel stable|canary package channel (default stable; canary = latest main build). On a box
|
||||
that already has the host this SWITCHES channel, either direction.
|
||||
--gamestream | --no-gamestream also serve stock Moonlight clients (default no — trusted LANs only)
|
||||
--clipboard | --no-clipboard allow the shared clipboard on this host (default no)
|
||||
--punktfunk-group | --no-punktfunk-group join the punktfunk group (virtual Steam Deck pad; default no)
|
||||
--linger | --no-linger start the host at boot with nobody logged in (default no)
|
||||
--gamestream | --no-gamestream Moonlight/Artemis/third-party clients (default depends on the box)
|
||||
--clipboard | --no-clipboard shared clipboard (default no)
|
||||
--punktfunk-group | --no-punktfunk-group full controller / virtual Steam Deck pad (default depends on the box)
|
||||
--linger | --no-linger start at boot with nobody logged in (default depends on the box)
|
||||
--mgmt-port N port to move the management API to if Sunshine/Apollo holds 47990 (default $MGMT_PORT)
|
||||
--no-start install and configure, but don't enable the services
|
||||
--uninstall stop the services and remove the packages + repo (config stays: $DOCS/uninstall)
|
||||
@@ -120,7 +121,13 @@ run() {
|
||||
fi
|
||||
printf ' + %s\n' "$cmd"
|
||||
[ "$DRY" = 1 ] && return 0
|
||||
if [ -n "$TTY" ]; then sh -ec "$cmd" < "$TTY"; else sh -ec "$cmd" < /dev/null; fi \
|
||||
# --yes means unattended: never block on a sudo password (sudo reads the TTY, not stdin).
|
||||
# Printed command stays without -n so the platforms.json verbatim gate still matches.
|
||||
exec_cmd=$cmd
|
||||
if [ "$YES" = 1 ]; then
|
||||
exec_cmd=$(printf '%s' "$cmd" | sed 's/sudo /sudo -n /g')
|
||||
fi
|
||||
if [ -n "$TTY" ] && [ "$YES" != 1 ]; then sh -ec "$exec_cmd" < "$TTY"; else sh -ec "$exec_cmd" < /dev/null; fi \
|
||||
|| die "that step failed — fix it and re-run (the script is safe to repeat), or follow the page by hand: $DOCS_PAGE"
|
||||
}
|
||||
|
||||
@@ -296,6 +303,115 @@ if [ "$FAMILY" = dnf ]; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------- choices
|
||||
# Empty flag/env still means "ask". The default behind Enter (and --yes) follows the box:
|
||||
# couch/HTPC distros want the Deck pad and linger; an active Sunshine-family host wants
|
||||
# Moonlight compat; a seatless session wants linger. Clipboard stays off. Flags/env win.
|
||||
has_graphical_seat() {
|
||||
[ -n "${DISPLAY:-}" ] && return 0
|
||||
[ -n "${WAYLAND_DISPLAY:-}" ] && return 0
|
||||
case "${XDG_SESSION_TYPE:-}" in x11|wayland) return 0 ;; esac
|
||||
return 1
|
||||
}
|
||||
couch_box() {
|
||||
[ "$FAMILY" = sysext ] && return 0
|
||||
[ "$ID" = bazzite ] && return 0
|
||||
[ "$ID" = nobara ] && return 0
|
||||
command -v ujust >/dev/null 2>&1 && return 0
|
||||
return 1
|
||||
}
|
||||
# Same split as `punktfunk-host detect-conflicts`: exit 1 only when a Sunshine-family host
|
||||
# runs or autostarts. A dormant leftover is not a reason to open Moonlight ports.
|
||||
sunshine_active() {
|
||||
if command -v punktfunk-host >/dev/null 2>&1; then
|
||||
punktfunk-host detect-conflicts >/dev/null 2>&1 && return 1 || return 0
|
||||
fi
|
||||
for u in sunshine.service apollo.service vibeshine.service; do
|
||||
systemctl is-active --quiet "$u" 2>/dev/null && return 0
|
||||
systemctl is-enabled --quiet "$u" 2>/dev/null && return 0
|
||||
systemctl --user is-active --quiet "$u" 2>/dev/null && return 0
|
||||
systemctl --user is-enabled --quiet "$u" 2>/dev/null && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
GROUP_WHY=; GS_WHY=; LINGER_WHY=
|
||||
DEF_GROUP=n; DEF_GS=n; DEF_LINGER=n
|
||||
|
||||
if couch_box; then
|
||||
DEF_GROUP=y
|
||||
DEF_LINGER=y
|
||||
case "$ID" in
|
||||
bazzite)
|
||||
GROUP_WHY="Bazzite — virtual Steam Deck pad"
|
||||
LINGER_WHY="Bazzite hosts are usually headless" ;;
|
||||
nobara)
|
||||
GROUP_WHY="Nobara — virtual Steam Deck pad"
|
||||
LINGER_WHY="Nobara hosts are usually headless" ;;
|
||||
*)
|
||||
GROUP_WHY="Game Mode / HTPC box — virtual Steam Deck pad"
|
||||
LINGER_WHY="Game Mode / HTPC box" ;;
|
||||
esac
|
||||
fi
|
||||
if ! has_graphical_seat; then
|
||||
DEF_LINGER=y
|
||||
[ -z "$LINGER_WHY" ] && LINGER_WHY="no graphical session"
|
||||
fi
|
||||
if sunshine_active; then
|
||||
DEF_GS=y
|
||||
GS_WHY="Sunshine/Apollo already on this box"
|
||||
fi
|
||||
|
||||
if [ -z "$PF_GROUP" ]; then
|
||||
if [ "$DEF_GROUP" = y ]; then
|
||||
case "$ID" in
|
||||
bazzite) q="Bazzite detected — joining the punktfunk group so the virtual Steam Deck pad works" ;;
|
||||
nobara) q="Nobara detected — joining the punktfunk group so the virtual Steam Deck pad works" ;;
|
||||
*) q="Game Mode / HTPC box detected — joining the punktfunk group so the virtual Steam Deck pad works" ;;
|
||||
esac
|
||||
ask "$q" y && PF_GROUP=1 || PF_GROUP=0
|
||||
else
|
||||
ask "Do you want the full controller — paddles, trackpads, gyro? (skip it and the pad arrives as a plain Xbox 360 controller)" n && PF_GROUP=1 || PF_GROUP=0
|
||||
GROUP_WHY=
|
||||
fi
|
||||
[ "$PF_GROUP" = 0 ] && GROUP_WHY=
|
||||
fi
|
||||
if [ -z "$GAMESTREAM" ]; then
|
||||
if [ "$DEF_GS" = y ]; then
|
||||
ask "Sunshine or Apollo is already on this box — also serve Moonlight, Artemis, or another third-party client? (Punktfunk's own apps don't need this)" y && GAMESTREAM=1 || GAMESTREAM=0
|
||||
else
|
||||
ask "Will you connect with Moonlight, Artemis, or another third-party client? (Punktfunk's own apps don't need this)" n && GAMESTREAM=1 || GAMESTREAM=0
|
||||
GS_WHY=
|
||||
fi
|
||||
[ "$GAMESTREAM" = 0 ] && GS_WHY=
|
||||
fi
|
||||
if [ -z "$CLIPBOARD" ]; then
|
||||
ask "Share the clipboard between this host and your clients? (each client still opts in per host)" n && CLIPBOARD=1 || CLIPBOARD=0
|
||||
fi
|
||||
if [ -z "$LINGER" ]; then
|
||||
if [ "$DEF_LINGER" = y ]; then
|
||||
ask "$LINGER_WHY — start the host at boot with nobody logged in?" y && LINGER=1 || LINGER=0
|
||||
else
|
||||
ask "Is this a box you stream from and rarely log into? (starts the host at boot with nobody logged in)" n && LINGER=1 || LINGER=0
|
||||
LINGER_WHY=
|
||||
fi
|
||||
[ "$LINGER" = 0 ] && LINGER_WHY=
|
||||
fi
|
||||
|
||||
yn() { [ "$1" = 1 ] && printf yes || printf no; }
|
||||
choice_line() {
|
||||
if [ -n "$3" ] && [ "$2" = 1 ]; then
|
||||
printf ' %s: %s (%s)\n' "$1" "$(yn "$2")" "$3"
|
||||
else
|
||||
printf ' %s: %s\n' "$1" "$(yn "$2")"
|
||||
fi
|
||||
}
|
||||
say "Choices (nothing below has run yet)"
|
||||
choice_line "Full controller" "$PF_GROUP" "$GROUP_WHY"
|
||||
choice_line "Third-party clients (Moonlight, Artemis)" "$GAMESTREAM" "$GS_WHY"
|
||||
choice_line "Shared clipboard" "$CLIPBOARD" ""
|
||||
choice_line "Start at boot with nobody logged in" "$LINGER" "$LINGER_WHY"
|
||||
|
||||
# ---------------------------------------------------------------------------- 1. install
|
||||
# The snippets below are data/platforms.json's install lines, verbatim (stable channel); canary
|
||||
# and the Fedora group are edited in. check-docs-drift.sh gate 6 keeps them identical.
|
||||
@@ -547,9 +663,6 @@ elif ! getent group input >/dev/null 2>&1; then
|
||||
else
|
||||
run 'sudo usermod -aG input "$USER"'; RELOGIN=1
|
||||
fi
|
||||
if [ -z "$PF_GROUP" ]; then
|
||||
ask "Also join the punktfunk group? It enables the virtual Steam Deck controller (paddles, trackpads, gyro) by granting usbip attach — only on a machine you trust ($DOCS/gamescope#nobara-and-other-autologin-display-managers)" n && PF_GROUP=1 || PF_GROUP=0
|
||||
fi
|
||||
if [ "$PF_GROUP" = 1 ]; then
|
||||
if id -nG "$USER" 2>/dev/null | tr ' ' '\n' | grep -qx punktfunk; then ok "already in the punktfunk group"
|
||||
else run 'sudo usermod -aG punktfunk "$USER"'; RELOGIN=1; fi
|
||||
@@ -557,16 +670,10 @@ fi
|
||||
|
||||
# ---------------------------------------------------------------------------- 4. options
|
||||
say "Options (host.env — everything here is off by default and reversible)"
|
||||
if [ -z "$GAMESTREAM" ]; then
|
||||
ask "Also serve stock Moonlight clients (GameStream compat)? Its pairing runs over plain HTTP — trusted LANs only; Punktfunk's own apps don't need it" n && GAMESTREAM=1 || GAMESTREAM=0
|
||||
fi
|
||||
if [ "$GAMESTREAM" = 1 ]; then
|
||||
[ "$CONFLICT" = 1 ] && warn "with another GameStream host running, only one can bind the Moonlight ports — stop the other first or skip this"
|
||||
set_env PUNKTFUNK_GAMESTREAM 1
|
||||
fi
|
||||
if [ -z "$CLIPBOARD" ]; then
|
||||
ask "Allow the shared clipboard on this host (each client still opts in per host)?" n && CLIPBOARD=1 || CLIPBOARD=0
|
||||
fi
|
||||
[ "$CLIPBOARD" = 1 ] && set_env PUNKTFUNK_CLIPBOARD on
|
||||
|
||||
# ---------------------------------------------------------------------------- 5. firewall
|
||||
@@ -591,6 +698,9 @@ fi
|
||||
# ---------------------------------------------------------------------------- 6. start
|
||||
if [ "$START" = 1 ]; then
|
||||
say "Starting the host and the web console"
|
||||
# Linger is what creates a user manager on a seatless box; apply it before probing
|
||||
# `systemctl --user`, otherwise SSH/headless installs print the enable command and stop.
|
||||
[ "$LINGER" = 1 ] && run 'sudo loginctl enable-linger "$USER"'
|
||||
if ! systemctl --user show-environment >/dev/null 2>&1; then
|
||||
warn "no user systemd session here (ssh without a login session?) — run this from a terminal in your desktop session:"
|
||||
echo " systemctl --user enable --now punktfunk-host punktfunk-web"
|
||||
@@ -606,10 +716,6 @@ if [ "$START" = 1 ]; then
|
||||
# The plugin runner fills the game library; apt/dnf/sysext start it themselves, Arch doesn't.
|
||||
if systemctl --user list-unit-files punktfunk-scripting.service 2>/dev/null | grep -q disabled; then units="$units punktfunk-scripting"; fi
|
||||
run "systemctl --user enable --now $units"
|
||||
if [ -z "$LINGER" ]; then
|
||||
ask "Start the host at boot even with nobody logged in (headless box)?" n && LINGER=1 || LINGER=0
|
||||
fi
|
||||
[ "$LINGER" = 1 ] && run 'sudo loginctl enable-linger "$USER"'
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user