Little Waders took the Plasma build and reported what a container cannot. A disc player on a machine with no optical drive, a clock nobody at the back of the room could read, a browser at half the size of the panel around it, and Parent Call with no broker to call. The broker is the same for every classroom, so it is a default now and not something to fill in room by room. classroom-migrate brings an existing room to the same place without touching its name, its username or its password, and Parent Call distinguishes a broker it cannot reach from one that was never set up: those send somebody to look at completely different things. The disc player's detection was right and ran too late — alongside the session rather than before it, and the panel is built from the layout the moment a session starts. It runs before the display manager now, and again from udev when a drive is plugged in. UI_SCALE had a ceiling of 1.5, which cannot express a 4K television; a clock pinned at 15 points, which is the same size at every scale; and a browser that was never told the number at all. All three are fixed and the room doubles together at 200%. This also brings 0.1.47's work into the repository, where it had only ever existed in a build directory under /tmp: the hidden display dialog, its authenticated writer, the polkit action, and the church's own wallpaper. One piece of it is deliberately left out. The custom volume display needed a shell package of our own, and with one selected plasmashell builds no panel at all — measured twice, with that build's own files, on a classroom that deletes its panel configuration at every login by design. The lab connected to the real church broker the moment the package defaulted to it. Nothing was left behind, which was checked, but the guard that should have stopped it had never worked: it used iptables, which the lab image does not have, and probed with /dev/tcp under dash, where that always fails. Both reported success. Co-Authored-By: Claude Opus 5 <[email protected]>
463 lines
14 KiB
Bash
Executable File
463 lines
14 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 kwinrc kwinrulesrc kscreenlockerrc ksmserverrc \
|
|
krunnerrc plasmanotifyrc powermanagementprofilesrc plasmarc \
|
|
plasmaparc; do
|
|
install -Dm644 \
|
|
"$ROOT/config/plasma/xdg/${setting}" \
|
|
"$STAGE/etc/ekklesia-classroom/xdg/${setting}"
|
|
done
|
|
|
|
# kdeglobals is composed rather than copied: the session policy plus the
|
|
# dark palette itself. Naming a colour scheme does not produce one, and a
|
|
# room whose user profile had never had a scheme applied came up light.
|
|
install -d "$STAGE/etc/ekklesia-classroom/xdg"
|
|
"$ROOT/tools/build-kdeglobals" > "$STAGE/etc/ekklesia-classroom/xdg/kdeglobals"
|
|
chmod 0644 "$STAGE/etc/ekklesia-classroom/xdg/kdeglobals"
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/environment/90-ekklesia-classroom.conf" \
|
|
"$STAGE/etc/environment.d/90-ekklesia-classroom.conf"
|
|
|
|
# The one that actually reaches a session started by a display manager.
|
|
# startplasma sources this directory; PAM does not read environment.d, so
|
|
# without this file none of the settings above are in the cascade at all
|
|
# and the room comes up as stock Plasma. Measured, on a real machine.
|
|
install -Dm644 \
|
|
"$ROOT/config/plasma/env/zz-ekklesia-classroom.sh" \
|
|
"$STAGE/etc/xdg/plasma-workspace/env/zz-ekklesia-classroom.sh"
|
|
|
|
# The power button does nothing. Two layers, because while a session is
|
|
# running PowerDevil holds logind's inhibitor and would overrule it.
|
|
install -Dm644 \
|
|
"$ROOT/config/systemd/logind-ekklesia-classroom.conf" \
|
|
"$STAGE/etc/systemd/logind.conf.d/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"
|
|
|
|
# NO SHELL PACKAGE OF OUR OWN.
|
|
#
|
|
# Plasma 6.3 loads the volume display from the shell package and from
|
|
# nowhere else — the look and feel is not consulted, which was measured —
|
|
# so a shell package is the only supported way to replace it, and a
|
|
# classroom-sized one was built and tried. With it selected, plasmashell
|
|
# builds no panel at all: not the stock one, not ours. Measured twice, and
|
|
# the room's panel is deleted at every login on purpose, so every login
|
|
# would have come up with nothing on the screen.
|
|
#
|
|
# The volume display is Plasma's own instead. UI_SCALE makes it the right
|
|
# size on a television, which is what the room actually needed.
|
|
|
|
# The room's Plasma style: the card a notification and the volume display
|
|
# are drawn on. Only the pieces the classroom changes; everything else
|
|
# comes from Breeze, so this can never leave a popup undrawn.
|
|
STYLE="$STAGE/usr/share/plasma/desktoptheme/ekklesia"
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/plasma/desktoptheme/metadata.json" \
|
|
"$STYLE/metadata.json"
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/plasma/desktoptheme/dialogs/background.svg" \
|
|
"$STYLE/dialogs/background.svg"
|
|
|
|
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"
|
|
|
|
# Shadows the old notification daemon's D-Bus activation. Deactivating its
|
|
# systemd unit is not enough: D-Bus starts it on demand from a file
|
|
# mako-notifier owns, and the crash-recovery test on a migrated machine
|
|
# caught it doing exactly that while the panel was down.
|
|
install -Dm644 \
|
|
"$ROOT/config/dbus/fr.emersion.mako.service" \
|
|
"$STAGE/usr/local/share/dbus-1/services/fr.emersion.mako.service"
|
|
|
|
# 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-admin-terminal" \
|
|
"$STAGE/usr/local/bin/classroom-admin-terminal"
|
|
|
|
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"
|
|
|
|
# Converges a machine that used to run something else. Called from
|
|
# postinst on every install, and by hand by a technician.
|
|
install -Dm755 \
|
|
"$ROOT/scripts/classroom-migrate" \
|
|
"$STAGE/usr/local/bin/classroom-migrate"
|
|
|
|
# One number, one place to ask for it.
|
|
install -Dm755 \
|
|
"$ROOT/scripts/classroom-ui-scale" \
|
|
"$STAGE/usr/local/bin/classroom-ui-scale"
|
|
|
|
# The room's display size: a hidden dialog behind a chord, a writer that
|
|
# asks for an administrator password, and the one thing that applies the
|
|
# answer at every login.
|
|
for command in classroom-display-settings classroom-set-scale; do
|
|
install -Dm755 \
|
|
"$ROOT/scripts/${command}" \
|
|
"$STAGE/usr/local/bin/${command}"
|
|
done
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/polkit/org.ekklesia.classroom.display.policy" \
|
|
"$STAGE/usr/share/polkit-1/actions/org.ekklesia.classroom.display.policy"
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/plasma/autostart/ekklesia-classroom-scale.desktop" \
|
|
"$STAGE/etc/xdg/autostart/ekklesia-classroom-scale.desktop"
|
|
|
|
# The panel's disc player follows this machine's hardware, and the
|
|
# detection has to have happened before a session starts.
|
|
install -Dm644 \
|
|
"$ROOT/systemd/layout/ekklesia-classroom-layout.service" \
|
|
"$STAGE/etc/systemd/system/ekklesia-classroom-layout.service"
|
|
|
|
install -Dm644 \
|
|
"$ROOT/config/udev/60-ekklesia-classroom-optical.rules" \
|
|
"$STAGE/etc/udev/rules.d/60-ekklesia-classroom-optical.rules"
|
|
|
|
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"
|