Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bin/omarchy-restart-shell
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ session_omarchy_path=$(systemctl --user show-environment 2>/dev/null | sed -n 's
CONFIG_DIR="$session_omarchy_path/shell"
[[ -f $CONFIG_DIR/shell.qml ]] || { echo "Omarchy shell config not found: $CONFIG_DIR" >&2; exit 1; }

# A double-click or two setup helpers can request a restart at the same time.
# The first invocation already satisfies every overlapping request; letting a
# second one enter the kill loop can terminate the replacement shell while it
# is still starting. Coalesce concurrent restarts instead.
exec {restart_lock_fd}>"${XDG_RUNTIME_DIR:-/tmp}/omarchy-restart-shell.lock"
flock -n "$restart_lock_fd" || exit 0

# Allow running from outside the session (e.g. over ssh) by deriving the
# Hyprland instance signature from the newest instance runtime dir.
if [[ -z ${HYPRLAND_INSTANCE_SIGNATURE:-} ]]; then
Expand Down
70 changes: 70 additions & 0 deletions test/shell.d/restart-shell-concurrency-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

require_command flock

test_tmp=$(mktemp -d)
holder_pid=""

cleanup() {
[[ -n $holder_pid ]] && kill "$holder_pid" 2>/dev/null || true
[[ -n $holder_pid ]] && wait "$holder_pid" 2>/dev/null || true
rm -rf "$test_tmp"
}
trap cleanup EXIT

session_root="$test_tmp/session"
runtime_dir="$test_tmp/runtime"
mock_bin="$test_tmp/bin"
marker="$test_tmp/restart-progressed"
ready="$test_tmp/lock-ready"
mkdir -p "$session_root/shell" "$runtime_dir" "$mock_bin"
touch "$session_root/shell/shell.qml"

cat >"$mock_bin/systemctl" <<'SH'
#!/bin/bash
if [[ ${1:-} == "--user" && ${2:-} == "show-environment" ]]; then
printf 'OMARCHY_PATH=%s\n' "$OMARCHY_TEST_SESSION_PATH"
else
exit 1
fi
SH

for command in omarchy-hyprland-session-locked omarchy-shell quickshell hyprctl; do
cat >"$mock_bin/$command" <<'SH'
#!/bin/bash
touch "$OMARCHY_TEST_MARKER"
exit 99
SH
chmod +x "$mock_bin/$command"
done
chmod +x "$mock_bin/systemctl"

(
exec 9>"$runtime_dir/omarchy-restart-shell.lock"
flock 9
touch "$ready"
sleep 30
) &
holder_pid=$!

for (( attempt = 0; attempt < 100; attempt++ )); do
[[ -f $ready ]] && break
sleep 0.01
done
[[ -f $ready ]] || fail "test acquired the shell restart lock"

PATH="$mock_bin:$PATH" \
OMARCHY_PATH="$session_root" \
XDG_RUNTIME_DIR="$runtime_dir" \
HYPRLAND_INSTANCE_SIGNATURE=test \
OMARCHY_TEST_SESSION_PATH="$session_root" \
OMARCHY_TEST_MARKER="$marker" \
timeout 1 "$ROOT/bin/omarchy-restart-shell" ||
fail "overlapping shell restart is coalesced successfully"

[[ ! -e $marker ]] || fail "overlapping shell restart does not enter the restart sequence"
pass "overlapping shell restart is coalesced before it can kill the replacement shell"