Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
feat: ccebuild restart — cycle services left on a replaced binary
`install` unlinks the destination before writing, so a service still running the
pre-install inode reports its exe as "... (deleted)". That is a precise,
bookkeeping-free signal that a restart is owed: units already on the current
binary are skipped, so this is safe to run after every install and is a no-op
when nothing changed.
--all forces every running cce service, which is what a shell-script unit needs:
gpu-watcher's exe is /usr/bin/bash, so editing the script never shows as
deleted and the default pass correctly leaves it alone.
The compositor is unreachable here by construction — it is not a user unit
(startcce launches it) and restarting it would tear down the session. GUI
windows are likewise out of scope; `status` still lists them so they can be
relaunched deliberately.
A unit that comes back inactive is reported and exits non-zero rather than
passing silently.
Verified: with four services on deleted inodes, restart cycled exactly those
four to active and skipped gpu-watcher; the second run reported nothing to do;
--all cycled all five. No errors in the journal, status bar back with its 10
modules.
Co-Authored-By: Claude Fable 5 <[email protected]>
scripts/ccebuild | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/scripts/ccebuild b/scripts/ccebuild
index 70f7d30..6fc8563 100755
--- a/scripts/ccebuild
+++ b/scripts/ccebuild
@@ -230,6 +230,61 @@ cmd_prune() {
printf '==> pruned\n'
}
+# Restart the user services whose binary has been replaced underneath them.
+#
+# `install` unlinks the destination before writing, so a service still running
+# the pre-install inode reports its exe as "... (deleted)" — a precise signal
+# that a restart is owed, and one that needs no timestamp bookkeeping. Units
+# already on the current binary are left alone, so this is safe to run after
+# every install.
+#
+# The compositor is deliberately unreachable here: it is not a user unit (it is
+# started by startcce), and restarting it would tear down the session.
+cmd_restart() {
+ local all=0
+ [ "${1:-}" = --all ] && all=1
+
+ systemctl --user daemon-reload 2>/dev/null || true
+
+ local units unit pid exe want=()
+ units=$(systemctl --user list-units --type=service --state=running --no-legend 2>/dev/null \
+ | awk '{print $1}' | grep -E '^(cce|gpu-watcher)' || true)
+ [ -n "$units" ] || { printf 'ccebuild: no cce user services running\n'; return; }
+
+ for unit in $units; do
+ if [ "$all" -eq 1 ]; then
+ want+=("$unit")
+ continue
+ fi
+ pid=$(systemctl --user show -p MainPID --value "$unit" 2>/dev/null)
+ [ -n "$pid" ] && [ "$pid" != 0 ] || continue
+ exe=$(readlink "/proc/$pid/exe" 2>/dev/null) || continue
+ case "$exe" in *"(deleted)") want+=("$unit") ;; esac
+ done
+
+ if [ ${#want[@]} -eq 0 ]; then
+ printf 'ccebuild: every running cce service is already on its current binary\n'
+ return
+ fi
+
+ printf '==> restarting %d service(s)\n' "${#want[@]}"
+ for unit in "${want[@]}"; do
+ printf ' %s ... ' "$unit"
+ if systemctl --user restart "$unit" 2>/dev/null; then
+ printf '%s\n' "$(systemctl --user is-active "$unit")"
+ else
+ printf 'FAILED\n'
+ fi
+ done
+
+ # A unit that comes back inactive is a silent breakage — surface it.
+ local bad=0
+ for unit in "${want[@]}"; do
+ [ "$(systemctl --user is-active "$unit")" = active ] || { printf 'ccebuild: %s is NOT active\n' "$unit" >&2; bad=1; }
+ done
+ [ "$bad" -eq 0 ] || exit 1
+}
+
# The root-owned install paths. Separate command because it needs sudo, which is
# exactly why these drifted three weeks behind everything else.
cmd_install_system() {
@@ -269,6 +324,8 @@ usage: ccebuild <command>
and user unit (derived from cargo metadata)
status show built-vs-installed drift, and running processes
that are not on their installed binary
+ restart [--all] restart user services still running a replaced binary
+ (--all: every running cce service). Never the compositor.
prune [--apply] delete target/ artifacts of crates cargo no longer
knows about (renamed/retired); dry-run by default
install-system update the root-owned binaries (needs sudo); backs up
@@ -287,6 +344,7 @@ case "${1:-}" in
build) cmd_build ;;
install) shift; cmd_install "$@" ;;
status) cmd_status ;;
+ restart) shift; cmd_restart "$@" ;;
prune) shift; cmd_prune "$@" ;;
install-system) cmd_install_system ;;
-h|--help|help|"") usage ;;