Files
Classroom_Desktop/tools/build-release.sh
T
ekklesiaandClaude Opus 5 d2d30d6b0c feat: take the last of sway out of the classroom
The DVD player was the only thing still speaking a compositor the room
no longer runs. It asked sway's tree whether VLC's window had really
gone fullscreen, because VLC reports playing while its window is still
the black startup one the loading cover exists to hide.

VLC's own status was measured as a replacement and is not one: it
reports fullscreen true in the same 250ms poll as playing, because the
flag is the option it was started with and not a report about its
window. So the cover is held for a floor and capped by the deadline that
was already there, and the compositor is not asked anything.

Focus-or-launch went the same way. The session already takes an
exclusive lock, so a second one cannot start, and bringing an existing
one to the front is the panel's job.

classroom-window, classroom_sway and classroom_chrome are gone with it —
the last of them was reachable from nothing at all.

DVD also moves out of the status row, where it sat beside the clock as
though a disc were a machine reading. It is an application: it is in the
row with Wonder Ink and the browser, and classroom-provision removes it
from the layout on a machine with no optical drive, which retires
DVD_ENABLED. A computer that moves between rooms takes its drive with
it; nobody remembers to edit a file when it does.

The panel is rebuilt from the package at every login now. Plasma keeps
whatever panel it first built, so an update could change the bar in the
package and never change it in a room — measured, with an icon that
outlived the file it came from. Editing the live panel configuration was
tried instead and destroyed the panel, because the shell owns that file.
Removing it before the shell starts is safe and makes the desktop
stateless.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 13:00:50 -05:00

365 lines
10 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
if [[ $# -ne 1 ]]; then
echo "Usage: $0 VERSION"
exit 1
fi
VERSION="$1"
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version: $VERSION"
echo "Expected MAJOR.MINOR.PATCH, for example 0.1.6"
exit 1
fi
STAGE="$ROOT/packaging/root"
OUTPUT="$ROOT/dist/ekklesia-classroom_${VERSION}_amd64.deb"
# Syntax check everything the package ships, by shebang, so this cannot
# drift out of date as classroom commands are added.
echo "Validating sources"
for script in "$ROOT/packaging/debian/postinst" "$ROOT"/scripts/* "$ROOT"/tests/*; do
[[ -f "$script" ]] || continue
case "$(head -n 1 "$script")" in
*python3*)
python3 -m py_compile "$script"
;;
*bash*|*bin/sh*)
bash -n "$script"
;;
esac
done
for module in "$ROOT"/lib/*.py; do
[[ -f "$module" ]] || continue
python3 -m py_compile "$module"
done
for policy in "$ROOT"/config/chrome/policies/*/*.json; do
[[ -f "$policy" ]] || continue
python3 -c 'import json, sys; json.load(open(sys.argv[1]))' "$policy"
done
find "$ROOT/scripts" "$ROOT/lib" \
-name '__pycache__' -type d -prune -exec rm -rf {} + 2>/dev/null || true
for test in "$ROOT"/tests/test-*.sh; do
[[ -x "$test" ]] || continue
echo "Running $(basename "$test")"
"$test" > /dev/null || {
echo "Tests failed. Run it directly to see why:"
echo " $test"
exit 1
}
done
echo "Building Ekklesia Classroom ${VERSION}"
# Always construct the package from clean canonical sources.
rm -rf "$STAGE"
mkdir -p "$STAGE/DEBIAN" "$ROOT/dist"
# Debian package metadata.
sed \
"s/^Version: @VERSION@$/Version: ${VERSION}/" \
"$ROOT/packaging/debian/control.template" \
> "$STAGE/DEBIAN/control"
install -m755 \
"$ROOT/packaging/debian/postinst" \
"$STAGE/DEBIAN/postinst"
# Classroom commands.
install -Dm755 \
"$ROOT/scripts/classroom-browser" \
"$STAGE/usr/local/bin/classroom-browser"
install -Dm755 \
"$ROOT/scripts/classroom-dvd" \
"$STAGE/usr/local/bin/classroom-dvd"
install -Dm755 \
"$ROOT/scripts/classroom-dvd-session" \
"$STAGE/usr/local/bin/classroom-dvd-session"
install -Dm755 \
"$ROOT/scripts/classroom-dvd-css-setup" \
"$STAGE/usr/local/bin/classroom-dvd-css-setup"
install -Dm755 \
"$ROOT/scripts/classroom-mqtt" \
"$STAGE/usr/local/bin/classroom-mqtt"
install -Dm755 \
"$ROOT/scripts/classroom-scale" \
"$STAGE/usr/local/bin/classroom-scale"
install -Dm755 \
"$ROOT/scripts/classroom-shutdown" \
"$STAGE/usr/local/bin/classroom-shutdown"
install -Dm755 \
"$ROOT/scripts/classroom-chrome-setup" \
"$STAGE/usr/local/bin/classroom-chrome-setup"
install -Dm755 \
"$ROOT/scripts/classroom-provision" \
"$STAGE/usr/local/bin/classroom-provision"
install -Dm755 \
"$ROOT/scripts/classroom-printer-setup" \
"$STAGE/usr/local/bin/classroom-printer-setup"
# Shared helpers imported by the classroom commands.
install -Dm644 \
"$ROOT/lib/classroom_config.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_config.py"
install -Dm644 \
"$ROOT/lib/classroom_mqtt.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_mqtt.py"
install -Dm644 \
"$ROOT/lib/classroom_vlc.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_vlc.py"
install -Dm644 \
"$ROOT/config/wallpapers/classroom-calm.png" \
"$STAGE/usr/share/backgrounds/ekklesia/classroom-calm.png"
# Chrome enterprise policy: suppress first-run and sign-in nags, and pin
# Home to Wonder Ink. Nothing here restricts where teachers can browse.
install -Dm644 \
"$ROOT/config/chrome/policies/managed/ekklesia-classroom.json" \
"$STAGE/etc/opt/chrome/policies/managed/ekklesia-classroom.json"
install -Dm644 \
"$ROOT/config/chrome/policies/recommended/ekklesia-classroom.json" \
"$STAGE/etc/opt/chrome/policies/recommended/ekklesia-classroom.json"
install -Dm755 \
"$ROOT/scripts/ekklesia-classroom-update" \
"$STAGE/usr/local/bin/ekklesia-classroom-update"
# System configuration.
install -Dm644 \
"$ROOT/config/sddm/ekklesia-classroom.conf" \
"$STAGE/etc/sddm.conf.d/ekklesia-classroom.conf"
install -Dm644 \
"$ROOT/systemd/updater/ekklesia-classroom-update.service" \
"$STAGE/etc/systemd/system/ekklesia-classroom-update.service"
install -Dm644 \
"$ROOT/systemd/updater/ekklesia-classroom-update.timer" \
"$STAGE/etc/systemd/system/ekklesia-classroom-update.timer"
install -Dm644 \
"$ROOT/systemd/provision/ekklesia-classroom-provision.service" \
"$STAGE/etc/systemd/system/ekklesia-classroom-provision.service"
install -Dm644 \
"$ROOT/systemd/shutdown/ekklesia-classroom-shutdown.service" \
"$STAGE/etc/systemd/system/ekklesia-classroom-shutdown.service"
install -Dm644 \
"$ROOT/systemd/mqtt/ekklesia-classroom-mqtt.service" \
"$STAGE/etc/systemd/system/ekklesia-classroom-mqtt.service"
# The classroom desktop.
#
# Not a shell, and not a daemon: a Plasma session described in files Plasma
# already reads. The panel, the window behaviour, the notifications, the
# lockdown and the palette are all in here, which is why there is no longer
# a dock, a window helper, a notification wrapper or a compositor config in
# the list above.
# Not /etc/xdg: plasma-workspace already owns files by these names there.
# The classroom's directory goes in front of it in XDG_CONFIG_DIRS instead.
for setting in kdeglobals kwinrc kwinrulesrc kscreenlockerrc ksmserverrc \
krunnerrc plasmanotifyrc; do
install -Dm644 \
"$ROOT/config/plasma/xdg/${setting}" \
"$STAGE/etc/ekklesia-classroom/xdg/${setting}"
done
install -Dm644 \
"$ROOT/config/environment/90-ekklesia-classroom.conf" \
"$STAGE/etc/environment.d/90-ekklesia-classroom.conf"
for scheme in EkklesiaDark EkklesiaLight; do
install -Dm644 \
"$ROOT/config/plasma/colors/${scheme}.colors" \
"$STAGE/usr/share/color-schemes/${scheme}.colors"
done
LOOK="$STAGE/usr/share/plasma/look-and-feel/org.ekklesia.classroom.desktop"
install -Dm644 \
"$ROOT/config/plasma/lookandfeel/metadata.json" \
"$LOOK/metadata.json"
install -Dm644 \
"$ROOT/config/plasma/lookandfeel/contents/defaults" \
"$LOOK/contents/defaults"
install -Dm644 \
"$ROOT/config/plasma/lookandfeel/contents/layouts/org.kde.plasma.desktop-layout.js" \
"$LOOK/contents/layouts/org.kde.plasma.desktop-layout.js"
for entry in "$ROOT"/config/plasma/applications/*.desktop; do
install -Dm644 "$entry" \
"$STAGE/usr/share/applications/$(basename "$entry")"
done
# Shadows Chrome's own entry. XDG_DATA_DIRS searches /usr/local/share first,
# so the panel matches a Chrome window to this launcher instead of to
# Chrome's, and the room gets one button rather than two.
for entry in "$ROOT"/config/plasma/applications-local/*.desktop; do
install -Dm644 "$entry" \
"$STAGE/usr/local/share/applications/$(basename "$entry")"
done
install -Dm644 \
"$ROOT/config/plasma/solid/ekklesia-dvd.desktop" \
"$STAGE/usr/share/solid/actions/ekklesia-dvd.desktop"
# Two marks the classroom draws itself, because nothing in Breeze says
# either thing: a lesson, and fetching a child's grown-up.
for icon in ekklesia-wonderink ekklesia-parent-call; do
install -Dm644 \
"$ROOT/config/icons/${icon}.svg" \
"$STAGE/usr/share/icons/hicolor/scalable/apps/${icon}.svg"
done
# The panel is the only way a teacher has of getting anywhere. Plasma gives
# up restarting it after three crashes in a minute; this does not.
install -Dm644 \
"$ROOT/systemd/user/plasma-plasmashell.service.d/ekklesia-classroom.conf" \
"$STAGE/etc/systemd/user/plasma-plasmashell.service.d/ekklesia-classroom.conf"
install -Dm644 \
"$ROOT/systemd/user/ekklesia-classroom-audio.service" \
"$STAGE/etc/systemd/user/ekklesia-classroom-audio.service"
install -Dm644 \
"$ROOT/systemd/user/ekklesia-classroom-desktop.service" \
"$STAGE/etc/systemd/user/ekklesia-classroom-desktop.service"
install -Dm755 \
"$ROOT/scripts/classroom-wonderink" \
"$STAGE/usr/local/bin/classroom-wonderink"
install -Dm755 \
"$ROOT/scripts/classroom-audio" \
"$STAGE/usr/local/bin/classroom-audio"
install -Dm755 \
"$ROOT/scripts/classroom-parent-call" \
"$STAGE/usr/local/bin/classroom-parent-call"
install -Dm755 \
"$ROOT/scripts/classroom-desktop-layout" \
"$STAGE/usr/local/bin/classroom-desktop-layout"
install -Dm755 \
"$ROOT/scripts/classroom-desktop-reset" \
"$STAGE/usr/local/bin/classroom-desktop-reset"
install -Dm755 \
"$ROOT/scripts/classroom-theme" \
"$STAGE/usr/local/bin/classroom-theme"
install -Dm644 \
"$ROOT/lib/classroom_audio.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_audio.py"
install -Dm644 \
"$ROOT/lib/classroom_parent_call.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_parent_call.py"
# The notifier the MQTT service uses to put a church message on screen.
install -Dm755 \
"$ROOT/scripts/classroom-notify" \
"$STAGE/usr/local/bin/classroom-notify"
install -Dm755 \
"$ROOT/scripts/classroom-notify-test" \
"$STAGE/usr/local/bin/classroom-notify-test"
install -Dm644 \
"$ROOT/lib/classroom_optical.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_optical.py"
# The DVD overlay draws its own control bar as a layer-shell surface, so it
# still needs the icon and stylesheet helpers the dock used to share.
install -Dm644 \
"$ROOT/lib/classroom_icons.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_icons.py"
install -Dm644 \
"$ROOT/lib/classroom_style.py" \
"$STAGE/usr/local/lib/ekklesia-classroom/classroom_style.py"
install -Dm644 \
"$ROOT/config/icons/dvd.svg" \
"$STAGE/etc/ekklesia-classroom/icons/dvd.svg"
install -Dm644 \
"$ROOT/config/overlay/style.css.in" \
"$STAGE/etc/ekklesia-classroom/overlay/style.css.in"
# DVD mode control bar.
for icon in media-play media-pause chapter-prev chapter-next \
disc-menu eject close; do
install -Dm644 \
"$ROOT/config/icons/${icon}.svg" \
"$STAGE/etc/ekklesia-classroom/icons/${icon}.svg"
done
printf '%s\n' "$VERSION" > "$ROOT/VERSION"
install -Dm644 \
"$ROOT/VERSION" \
"$STAGE/usr/local/lib/ekklesia-classroom/VERSION"
dpkg-deb \
--root-owner-group \
--build "$STAGE" "$OUTPUT"
echo
echo "Built:"
echo "$OUTPUT"
sha256sum "$OUTPUT"