Harden Panama launcher actions
This commit is contained in:
@@ -7,18 +7,12 @@ set -euo pipefail
|
|||||||
|
|
||||||
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
action="${1:-}"
|
action="${1:-}"
|
||||||
|
helper_dir="${PANAMA_ACTION_HELPER_DIR:-$script_dir}"
|
||||||
|
confirm_attempts="${PANAMA_ACTION_CONFIRM_ATTEMPTS:-20}"
|
||||||
|
confirm_delay="${PANAMA_ACTION_CONFIRM_DELAY:-0.1}"
|
||||||
|
|
||||||
if command -v panama-osd >/dev/null 2>&1; then
|
osd_command=("$helper_dir/panama-osd")
|
||||||
osd_command=(panama-osd)
|
gallery_command=("$helper_dir/panama-prism-gallery")
|
||||||
else
|
|
||||||
osd_command=("$script_dir/panama-osd")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v panama-prism-gallery >/dev/null 2>&1; then
|
|
||||||
gallery_command=(panama-prism-gallery)
|
|
||||||
else
|
|
||||||
gallery_command=("$script_dir/panama-prism-gallery")
|
|
||||||
fi
|
|
||||||
|
|
||||||
report_failure() {
|
report_failure() {
|
||||||
local status=$?
|
local status=$?
|
||||||
@@ -35,8 +29,8 @@ trap report_failure EXIT
|
|||||||
show_state() {
|
show_state() {
|
||||||
local state="$1" on_icon="$2" off_icon="$3" label="$4"
|
local state="$1" on_icon="$2" off_icon="$3" label="$4"
|
||||||
case "$state" in
|
case "$state" in
|
||||||
true) "${osd_command[@]}" message "$on_icon" "$label On" ;;
|
true) PANAMA_OSD_STRICT=1 "${osd_command[@]}" message "$on_icon" "$label On" ;;
|
||||||
false) "${osd_command[@]}" message "$off_icon" "$label Off" ;;
|
false) PANAMA_OSD_STRICT=1 "${osd_command[@]}" message "$off_icon" "$label Off" ;;
|
||||||
*)
|
*)
|
||||||
printf 'Panama action returned an invalid state: %s\n' "$state" >&2
|
printf 'Panama action returned an invalid state: %s\n' "$state" >&2
|
||||||
return 1
|
return 1
|
||||||
@@ -44,12 +38,55 @@ show_state() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state_is_active() {
|
||||||
|
local target="$1"
|
||||||
|
case "$target" in
|
||||||
|
caffeine)
|
||||||
|
systemd-inhibit --list --no-pager --no-legend 2>/dev/null \
|
||||||
|
| awk '$1 == "Panama" && $(NF - 1) == "Caffeine" && $NF == "block" { found = 1 } END { exit !found }'
|
||||||
|
;;
|
||||||
|
night-light)
|
||||||
|
pgrep -u "$(id -u)" -x hyprsunset >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*) return 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_confirmed_state() {
|
||||||
|
local target="$1" expected="$2" attempt
|
||||||
|
for ((attempt = 0; attempt < confirm_attempts; attempt++)); do
|
||||||
|
if [[ $expected == true ]] && state_is_active "$target"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ $expected == false ]] && ! state_is_active "$target"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep "$confirm_delay"
|
||||||
|
done
|
||||||
|
printf 'Panama action could not confirm %s reached state %s\n' "$target" "$expected" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
toggle_state() {
|
toggle_state() {
|
||||||
local target="$1" on_icon="$2" off_icon="$3" label="$4" state
|
local target="$1" on_icon="$2" off_icon="$3" label="$4" state
|
||||||
state="$(qs ipc call "$target" toggle)"
|
state="$(qs ipc call "$target" toggle)"
|
||||||
|
case "$state" in true|false) ;; *) show_state "$state" "$on_icon" "$off_icon" "$label"; return ;; esac
|
||||||
|
wait_for_confirmed_state "$target" "$state"
|
||||||
show_state "$state" "$on_icon" "$off_icon" "$label"
|
show_state "$state" "$on_icon" "$off_icon" "$label"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait_for_shell() {
|
||||||
|
local attempt
|
||||||
|
for ((attempt = 0; attempt < confirm_attempts; attempt++)); do
|
||||||
|
if qs ipc show >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep "$confirm_delay"
|
||||||
|
done
|
||||||
|
printf 'Panama shell did not become ready after restart\n' >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
control-center) qs ipc call quicksettings open ;;
|
control-center) qs ipc call quicksettings open ;;
|
||||||
notifications) qs ipc call notifications open ;;
|
notifications) qs ipc call notifications open ;;
|
||||||
@@ -69,23 +106,30 @@ case "$action" in
|
|||||||
toggle_state night-light night-light-symbolic night-light-disabled-symbolic "Night Light"
|
toggle_state night-light night-light-symbolic night-light-disabled-symbolic "Night Light"
|
||||||
;;
|
;;
|
||||||
focus-start)
|
focus-start)
|
||||||
qs ipc call focus start
|
state="$(qs ipc call focus start)"
|
||||||
"${osd_command[@]}" message preferences-system-time-symbolic "Focus Session Started"
|
[[ $state == true ]]
|
||||||
|
PANAMA_OSD_STRICT=1 "${osd_command[@]}" message preferences-system-time-symbolic "Focus Session Started"
|
||||||
;;
|
;;
|
||||||
focus-end)
|
focus-end)
|
||||||
qs ipc call focus end
|
state="$(qs ipc call focus end)"
|
||||||
"${osd_command[@]}" message media-playback-stop-symbolic "Focus Session Ended"
|
if [[ $state == true ]]; then
|
||||||
|
PANAMA_OSD_STRICT=1 "${osd_command[@]}" message media-playback-stop-symbolic "Focus Session Ended"
|
||||||
|
else
|
||||||
|
PANAMA_OSD_STRICT=1 "${osd_command[@]}" message dialog-information-symbolic "No Focus Session Running"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
capture) qs ipc call capture open ;;
|
capture) qs ipc call capture open ;;
|
||||||
intelligence) qs ipc call screen-intelligence open ;;
|
intelligence) qs ipc call screen-intelligence open ;;
|
||||||
screenshot) qs ipc call capture screenNow ;;
|
screenshot) qs ipc call capture screenNow ;;
|
||||||
microphone) "${osd_command[@]}" microphone toggle ;;
|
microphone) PANAMA_OSD_STRICT=1 "${osd_command[@]}" microphone toggle ;;
|
||||||
|
|
||||||
gallery) "${gallery_command[@]}" ;;
|
gallery) "${gallery_command[@]}" ;;
|
||||||
restart-shell)
|
restart-shell)
|
||||||
qs kill
|
qs kill >/dev/null 2>&1 || true
|
||||||
quickshell --daemonize
|
quickshell --daemonize
|
||||||
|
wait_for_shell
|
||||||
|
PANAMA_OSD_STRICT=1 "${osd_command[@]}" message view-refresh-symbolic "Panama Restarted"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
printf 'Usage: panama-action {%s}\n' \
|
printf 'Usage: panama-action {%s}\n' \
|
||||||
|
|||||||
@@ -2,12 +2,22 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
|
strict_delivery() {
|
||||||
|
[[ ${PANAMA_OSD_STRICT:-false} == true || ${PANAMA_OSD_STRICT:-false} == 1 ]]
|
||||||
|
}
|
||||||
|
|
||||||
show_progress() {
|
show_progress() {
|
||||||
qs ipc call osd progress "$1" "$2" 100 "$3" >/dev/null 2>&1 || true
|
if ! qs ipc call osd progress "$1" "$2" 100 "$3" >/dev/null 2>&1; then
|
||||||
|
strict_delivery && return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
show_message() {
|
show_message() {
|
||||||
qs ipc call osd message "$1" "$2" >/dev/null 2>&1 || true
|
if ! qs ipc call osd message "$1" "$2" >/dev/null 2>&1; then
|
||||||
|
strict_delivery && return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
volume_state() {
|
volume_state() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool initialized: false
|
property bool initialized: false
|
||||||
|
property bool suppressStatusEvents: false
|
||||||
|
|
||||||
// The manual switch. Ignored while `automatic` is on.
|
// The manual switch. Ignored while `automatic` is on.
|
||||||
property bool enabled: Settings.nightLightEnabledByDefault
|
property bool enabled: Settings.nightLightEnabledByDefault
|
||||||
@@ -53,6 +54,22 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Launcher actions already provide immediate Prism OSD feedback. Keep the
|
||||||
|
// ambient Signal Glass channel quiet for that path so one choice produces
|
||||||
|
// one confirmation instead of two competing transients.
|
||||||
|
function toggleQuietly(): void {
|
||||||
|
root.suppressStatusEvents = true;
|
||||||
|
root.toggle();
|
||||||
|
root.suppressStatusEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore(manualEnabled: bool, automaticEnabled: bool): void {
|
||||||
|
root.suppressStatusEvents = true;
|
||||||
|
root.enabled = manualEnabled;
|
||||||
|
root.automatic = automaticEnabled;
|
||||||
|
root.suppressStatusEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
// The window wraps midnight (17:00 → 10:00), so the comparison flips when
|
// The window wraps midnight (17:00 → 10:00), so the comparison flips when
|
||||||
// `from` is later in the day than `to`.
|
// `from` is later in the day than `to`.
|
||||||
function inWindow(hour: real): bool {
|
function inWindow(hour: real): bool {
|
||||||
@@ -118,7 +135,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
if (!root.initialized)
|
if (!root.initialized || root.suppressStatusEvents)
|
||||||
return;
|
return;
|
||||||
StatusEvents.publish({
|
StatusEvents.publish({
|
||||||
key: "display-night-light",
|
key: "display-night-light",
|
||||||
|
|||||||
@@ -114,7 +114,10 @@ ShellRoot {
|
|||||||
IpcHandler {
|
IpcHandler {
|
||||||
target: "focus"
|
target: "focus"
|
||||||
|
|
||||||
function start(): void { FocusSession.startDefault(); }
|
function start(): bool {
|
||||||
|
FocusSession.startDefault();
|
||||||
|
return FocusSession.active;
|
||||||
|
}
|
||||||
function reveal(): void { FocusSession.reveal(); }
|
function reveal(): void { FocusSession.reveal(); }
|
||||||
function dismiss(): void { FocusSession.dismiss(); }
|
function dismiss(): void { FocusSession.dismiss(); }
|
||||||
function pause(): void { FocusSession.pauseOrResume(); }
|
function pause(): void { FocusSession.pauseOrResume(); }
|
||||||
@@ -123,7 +126,12 @@ ShellRoot {
|
|||||||
ShellState.openOverview(FocusSession.workspaceId);
|
ShellState.openOverview(FocusSession.workspaceId);
|
||||||
FocusSession.dismiss();
|
FocusSession.dismiss();
|
||||||
}
|
}
|
||||||
function end(): void { FocusSession.end(false); }
|
function end(): bool {
|
||||||
|
if (!FocusSession.active)
|
||||||
|
return false;
|
||||||
|
FocusSession.end(false);
|
||||||
|
return !FocusSession.active;
|
||||||
|
}
|
||||||
function status(): string {
|
function status(): string {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
active: FocusSession.active,
|
active: FocusSession.active,
|
||||||
@@ -272,10 +280,21 @@ ShellRoot {
|
|||||||
IpcHandler {
|
IpcHandler {
|
||||||
target: "night-light"
|
target: "night-light"
|
||||||
function toggle(): bool {
|
function toggle(): bool {
|
||||||
NightLight.toggle();
|
NightLight.toggleQuietly();
|
||||||
return NightLight.active;
|
return NightLight.active;
|
||||||
}
|
}
|
||||||
function status(): bool { return NightLight.active; }
|
function status(): bool { return NightLight.active; }
|
||||||
|
function settings(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
enabled: NightLight.enabled,
|
||||||
|
automatic: NightLight.automatic,
|
||||||
|
active: NightLight.active
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function restore(enabled: bool, automatic: bool): bool {
|
||||||
|
NightLight.restore(enabled, automatic);
|
||||||
|
return NightLight.active;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ fi
|
|||||||
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
||||||
gsettings set org.gnome.desktop.session idle-delay 0
|
gsettings set org.gnome.desktop.session idle-delay 0
|
||||||
|
|
||||||
# Run scripts
|
# Run each setup stage in its own process. This keeps strict-shell options and
|
||||||
for script in ~/.local/share/Panama/setup/scripts/*; do source $script; done
|
# helper variables local to the script that owns them.
|
||||||
|
for script in ~/.local/share/Panama/setup/scripts/*; do "$script"; done
|
||||||
|
|
||||||
# Revert to normal idle settings
|
# Revert to normal idle settings
|
||||||
gsettings set org.gnome.desktop.screensaver lock-enabled true
|
gsettings set org.gnome.desktop.screensaver lock-enabled true
|
||||||
|
|||||||
@@ -88,11 +88,6 @@ else
|
|||||||
log "Linked Tokyo Night Moon theme → $VICINAE_THEME"
|
log "Linked Tokyo Night Moon theme → $VICINAE_THEME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install the Panama command collection into Vicinae's XDG data directory.
|
|
||||||
# This is intentionally separate from ~/.config/vicinae: script commands are
|
|
||||||
# user data in Vicinae 0.26, just like custom themes.
|
|
||||||
"$PANAMA_PATH/setup/scripts/link-vicinae-scripts"
|
|
||||||
|
|
||||||
# Panama-native applications live in the user data directory so launchers can
|
# Panama-native applications live in the user data directory so launchers can
|
||||||
# discover them alongside system desktop entries. Keep each authored file in
|
# discover them alongside system desktop entries. Keep each authored file in
|
||||||
# the repository and expose it with a narrow per-file symlink.
|
# the repository and expose it with a narrow per-file symlink.
|
||||||
|
|||||||
@@ -11,14 +11,27 @@ vicinae_data_dir="${VICINAE_DATA_DIR:-$HOME/.local/share/vicinae}"
|
|||||||
source_dir="$panama_path/config/local/share/vicinae/scripts"
|
source_dir="$panama_path/config/local/share/vicinae/scripts"
|
||||||
scripts_dir="$vicinae_data_dir/scripts"
|
scripts_dir="$vicinae_data_dir/scripts"
|
||||||
target_dir="$scripts_dir/panama"
|
target_dir="$scripts_dir/panama"
|
||||||
backup_dir="$scripts_dir/panama.pre-panama"
|
backup_root="$vicinae_data_dir/backups"
|
||||||
|
backup_dir="$backup_root/panama.pre-panama"
|
||||||
|
legacy_backup="$scripts_dir/panama.pre-panama"
|
||||||
|
|
||||||
[[ -d "$source_dir" ]] || {
|
[[ -d "$source_dir" ]] || {
|
||||||
printf 'Panama command source is missing: %s\n' "$source_dir" >&2
|
printf 'Panama command source is missing: %s\n' "$source_dir" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir -p "$scripts_dir"
|
mkdir -p "$scripts_dir" "$backup_root"
|
||||||
|
|
||||||
|
# Older Panama builds preserved this directory alongside searchable commands.
|
||||||
|
# Move it out before reloading so those scripts cannot appear twice.
|
||||||
|
if [[ -e "$legacy_backup" ]]; then
|
||||||
|
if [[ -e "$backup_dir" ]]; then
|
||||||
|
printf 'Refusing to move %s; backup already exists at %s\n' \
|
||||||
|
"$legacy_backup" "$backup_dir" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mv "$legacy_backup" "$backup_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -L "$target_dir" ]]; then
|
if [[ -L "$target_dir" ]]; then
|
||||||
rm "$target_dir"
|
rm "$target_dir"
|
||||||
|
|||||||
@@ -47,12 +47,16 @@ cat >"$scratch/bin/qs" <<'SH'
|
|||||||
printf 'qs' >>"$OSD_TEST_LOG"
|
printf 'qs' >>"$OSD_TEST_LOG"
|
||||||
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
|
printf ' <%s>' "$@" >>"$OSD_TEST_LOG"
|
||||||
printf '\n' >>"$OSD_TEST_LOG"
|
printf '\n' >>"$OSD_TEST_LOG"
|
||||||
|
[[ ${OSD_TEST_FAIL_QS:-false} != true ]]
|
||||||
SH
|
SH
|
||||||
|
|
||||||
chmod +x "$scratch/bin/"*
|
chmod +x "$scratch/bin/"*
|
||||||
|
|
||||||
run_helper() {
|
run_helper() {
|
||||||
PATH="$scratch/bin:$PATH" OSD_TEST_LOG="$log" "$helper" "$@"
|
PATH="$scratch/bin:$PATH" OSD_TEST_LOG="$log" \
|
||||||
|
OSD_TEST_FAIL_QS="${OSD_TEST_FAIL_QS:-false}" \
|
||||||
|
PANAMA_OSD_STRICT="${PANAMA_OSD_STRICT:-false}" \
|
||||||
|
"$helper" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_line() {
|
assert_line() {
|
||||||
@@ -95,4 +99,13 @@ assert_line 'qs <ipc> <call> <osd> <message> <media-next> <Horizon — Tycho>'
|
|||||||
run_helper message notifications-disabled-symbolic 'Do Not Disturb On'
|
run_helper message notifications-disabled-symbolic 'Do Not Disturb On'
|
||||||
assert_line 'qs <ipc> <call> <osd> <message> <notifications-disabled-symbolic> <Do Not Disturb On>'
|
assert_line 'qs <ipc> <call> <osd> <message> <notifications-disabled-symbolic> <Do Not Disturb On>'
|
||||||
|
|
||||||
|
: >"$log"
|
||||||
|
if OSD_TEST_FAIL_QS=true PANAMA_OSD_STRICT=1 run_helper message dialog-error-symbolic 'Strict failure'; then
|
||||||
|
printf 'osd helper contract: strict delivery swallowed an IPC failure\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
: >"$log"
|
||||||
|
OSD_TEST_FAIL_QS=true run_helper message dialog-information-symbolic 'Best effort'
|
||||||
|
|
||||||
printf 'osd helper contract: PASS\n'
|
printf 'osd helper contract: PASS\n'
|
||||||
|
|||||||
@@ -37,7 +37,13 @@ case "$*" in
|
|||||||
'ipc call notifications dnd'|'ipc call caffeine toggle'|'ipc call night-light toggle')
|
'ipc call notifications dnd'|'ipc call caffeine toggle'|'ipc call night-light toggle')
|
||||||
printf '%s\n' "${PANAMA_ACTION_TEST_STATE:-true}"
|
printf '%s\n' "${PANAMA_ACTION_TEST_STATE:-true}"
|
||||||
;;
|
;;
|
||||||
|
'ipc call focus start'|'ipc call focus end')
|
||||||
|
printf '%s\n' "${PANAMA_ACTION_TEST_FOCUS_STATE:-true}"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
if [[ ${PANAMA_ACTION_TEST_FAIL_KILL:-false} == true && ${1:-} == kill ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
[[ ${PANAMA_ACTION_TEST_FAIL_QS:-false} != true ]]
|
[[ ${PANAMA_ACTION_TEST_FAIL_QS:-false} != true ]]
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@@ -53,6 +59,7 @@ make_recorder panama-osd <<'EOF'
|
|||||||
printf 'panama-osd' >>"$PANAMA_ACTION_TEST_LOG"
|
printf 'panama-osd' >>"$PANAMA_ACTION_TEST_LOG"
|
||||||
printf ' <%s>' "$@" >>"$PANAMA_ACTION_TEST_LOG"
|
printf ' <%s>' "$@" >>"$PANAMA_ACTION_TEST_LOG"
|
||||||
printf '\n' >>"$PANAMA_ACTION_TEST_LOG"
|
printf '\n' >>"$PANAMA_ACTION_TEST_LOG"
|
||||||
|
[[ ${PANAMA_ACTION_TEST_FAIL_OSD:-false} != true ]]
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
make_recorder panama-prism-gallery <<'EOF'
|
make_recorder panama-prism-gallery <<'EOF'
|
||||||
@@ -71,9 +78,29 @@ printf ' <%s>' "$@" >>"$PANAMA_ACTION_TEST_LOG"
|
|||||||
printf '\n' >>"$PANAMA_ACTION_TEST_LOG"
|
printf '\n' >>"$PANAMA_ACTION_TEST_LOG"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
make_recorder systemd-inhibit <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
if [[ ${PANAMA_ACTION_TEST_CONFIRMED_STATE:-${PANAMA_ACTION_TEST_STATE:-true}} == true ]]; then
|
||||||
|
printf 'Panama 1000 gib 42 systemd-inhibit sleep:idle Caffeine block\n'
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
make_recorder pgrep <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
[[ ${PANAMA_ACTION_TEST_CONFIRMED_STATE:-${PANAMA_ACTION_TEST_STATE:-true}} == true ]]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
make_recorder id <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
printf '1000\n'
|
||||||
|
EOF
|
||||||
|
|
||||||
run_action() {
|
run_action() {
|
||||||
: >"$command_log"
|
: >"$command_log"
|
||||||
HOME="$work/home" PATH="$fake_bin:$PATH" \
|
HOME="$work/home" PATH="$fake_bin:$PATH" \
|
||||||
|
PANAMA_ACTION_HELPER_DIR="$fake_bin" \
|
||||||
|
PANAMA_ACTION_CONFIRM_ATTEMPTS=1 \
|
||||||
|
PANAMA_ACTION_CONFIRM_DELAY=0 \
|
||||||
PANAMA_ACTION_TEST_LOG="$command_log" \
|
PANAMA_ACTION_TEST_LOG="$command_log" \
|
||||||
"$dispatcher" "$1"
|
"$dispatcher" "$1"
|
||||||
}
|
}
|
||||||
@@ -119,6 +146,9 @@ assert_commands $'qs <ipc> <call> <focus> <start>\npanama-osd <message> <prefere
|
|||||||
run_action focus-end
|
run_action focus-end
|
||||||
assert_commands $'qs <ipc> <call> <focus> <end>\npanama-osd <message> <media-playback-stop-symbolic> <Focus Session Ended>'
|
assert_commands $'qs <ipc> <call> <focus> <end>\npanama-osd <message> <media-playback-stop-symbolic> <Focus Session Ended>'
|
||||||
|
|
||||||
|
PANAMA_ACTION_TEST_FOCUS_STATE=false run_action focus-end
|
||||||
|
assert_commands $'qs <ipc> <call> <focus> <end>\npanama-osd <message> <dialog-information-symbolic> <No Focus Session Running>'
|
||||||
|
|
||||||
run_action capture
|
run_action capture
|
||||||
assert_commands 'qs <ipc> <call> <capture> <open>'
|
assert_commands 'qs <ipc> <call> <capture> <open>'
|
||||||
|
|
||||||
@@ -135,18 +165,43 @@ run_action gallery
|
|||||||
assert_commands 'panama-prism-gallery'
|
assert_commands 'panama-prism-gallery'
|
||||||
|
|
||||||
run_action restart-shell
|
run_action restart-shell
|
||||||
assert_commands $'qs <kill>\nquickshell <--daemonize>'
|
assert_commands $'qs <kill>\nquickshell <--daemonize>\nqs <ipc> <show>\npanama-osd <message> <view-refresh-symbolic> <Panama Restarted>'
|
||||||
|
|
||||||
if HOME="$work/home" PATH="$fake_bin:$PATH" PANAMA_ACTION_TEST_LOG="$command_log" \
|
PANAMA_ACTION_TEST_FAIL_KILL=true run_action restart-shell
|
||||||
|
assert_commands $'qs <kill>\nquickshell <--daemonize>\nqs <ipc> <show>\npanama-osd <message> <view-refresh-symbolic> <Panama Restarted>'
|
||||||
|
|
||||||
|
if HOME="$work/home" PATH="$fake_bin:$PATH" PANAMA_ACTION_HELPER_DIR="$fake_bin" \
|
||||||
|
PANAMA_ACTION_CONFIRM_ATTEMPTS=1 PANAMA_ACTION_CONFIRM_DELAY=0 PANAMA_ACTION_TEST_LOG="$command_log" \
|
||||||
"$dispatcher" definitely-not-an-action >/dev/null 2>&1; then
|
"$dispatcher" definitely-not-an-action >/dev/null 2>&1; then
|
||||||
fail 'unknown action was accepted'
|
fail 'unknown action was accepted'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
: >"$command_log"
|
: >"$command_log"
|
||||||
if PANAMA_ACTION_TEST_FAIL_QS=true HOME="$work/home" PATH="$fake_bin:$PATH" \
|
if PANAMA_ACTION_TEST_FAIL_QS=true HOME="$work/home" PATH="$fake_bin:$PATH" \
|
||||||
PANAMA_ACTION_TEST_LOG="$command_log" "$dispatcher" control-center >/dev/null 2>&1; then
|
PANAMA_ACTION_HELPER_DIR="$fake_bin" PANAMA_ACTION_CONFIRM_ATTEMPTS=1 \
|
||||||
|
PANAMA_ACTION_CONFIRM_DELAY=0 PANAMA_ACTION_TEST_LOG="$command_log" \
|
||||||
|
"$dispatcher" control-center >/dev/null 2>&1; then
|
||||||
fail 'failed shell action returned success'
|
fail 'failed shell action returned success'
|
||||||
fi
|
fi
|
||||||
assert_commands $'qs <ipc> <call> <quicksettings> <open>\nnotify-send <-a> <Panama> <-i> <dialog-error-symbolic> <Panama action failed> <The “control center” action could not be completed.>'
|
assert_commands $'qs <ipc> <call> <quicksettings> <open>\nnotify-send <-a> <Panama> <-i> <dialog-error-symbolic> <Panama action failed> <The “control center” action could not be completed.>'
|
||||||
|
|
||||||
|
: >"$command_log"
|
||||||
|
if PANAMA_ACTION_TEST_FAIL_OSD=true HOME="$work/home" PATH="$fake_bin:$PATH" \
|
||||||
|
PANAMA_ACTION_HELPER_DIR="$fake_bin" PANAMA_ACTION_CONFIRM_ATTEMPTS=1 \
|
||||||
|
PANAMA_ACTION_CONFIRM_DELAY=0 PANAMA_ACTION_TEST_LOG="$command_log" \
|
||||||
|
"$dispatcher" microphone >/dev/null 2>&1; then
|
||||||
|
fail 'failed Prism OSD delivery returned success'
|
||||||
|
fi
|
||||||
|
assert_commands $'panama-osd <microphone> <toggle>\nnotify-send <-a> <Panama> <-i> <dialog-error-symbolic> <Panama action failed> <The “microphone” action could not be completed.>'
|
||||||
|
|
||||||
|
: >"$command_log"
|
||||||
|
if PANAMA_ACTION_TEST_CONFIRMED_STATE=false HOME="$work/home" PATH="$fake_bin:$PATH" \
|
||||||
|
PANAMA_ACTION_HELPER_DIR="$fake_bin" PANAMA_ACTION_CONFIRM_ATTEMPTS=1 \
|
||||||
|
PANAMA_ACTION_CONFIRM_DELAY=0 PANAMA_ACTION_TEST_LOG="$command_log" \
|
||||||
|
"$dispatcher" caffeine >/dev/null 2>&1; then
|
||||||
|
fail 'unconfirmed Caffeine state returned success'
|
||||||
|
fi
|
||||||
|
grep -Fqx 'notify-send <-a> <Panama> <-i> <dialog-error-symbolic> <Panama action failed> <The “caffeine” action could not be completed.>' "$command_log" \
|
||||||
|
|| fail 'unconfirmed state did not send a failure notification'
|
||||||
|
|
||||||
printf 'Panama action contract: PASS\n'
|
printf 'Panama action contract: PASS\n'
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ fail() {
|
|||||||
|
|
||||||
active_target=""
|
active_target=""
|
||||||
original_state=""
|
original_state=""
|
||||||
|
night_light_snapshot=""
|
||||||
|
|
||||||
restore_target() {
|
restore_target() {
|
||||||
local target="$1" expected="$2" current
|
local target="$1" expected="$2" current
|
||||||
@@ -22,6 +23,12 @@ cleanup() {
|
|||||||
if [[ -n $active_target ]]; then
|
if [[ -n $active_target ]]; then
|
||||||
restore_target "$active_target" "$original_state"
|
restore_target "$active_target" "$original_state"
|
||||||
fi
|
fi
|
||||||
|
if [[ -n $night_light_snapshot ]]; then
|
||||||
|
local enabled automatic
|
||||||
|
enabled="$(jq -r '.enabled' <<<"$night_light_snapshot")"
|
||||||
|
automatic="$(jq -r '.automatic' <<<"$night_light_snapshot")"
|
||||||
|
qs ipc call night-light restore "$enabled" "$automatic" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@@ -51,6 +58,22 @@ rg -q '^target caffeine$' <<<"$ipc" || fail 'caffeine IPC target is missing'
|
|||||||
rg -q '^target night-light$' <<<"$ipc" || fail 'night-light IPC target is missing'
|
rg -q '^target night-light$' <<<"$ipc" || fail 'night-light IPC target is missing'
|
||||||
|
|
||||||
exercise_toggle caffeine
|
exercise_toggle caffeine
|
||||||
|
|
||||||
|
night_light_snapshot="$(qs ipc call night-light settings)"
|
||||||
|
jq -e '.enabled | type == "boolean"' <<<"$night_light_snapshot" >/dev/null \
|
||||||
|
|| fail 'night-light settings omitted enabled state'
|
||||||
|
jq -e '.automatic | type == "boolean"' <<<"$night_light_snapshot" >/dev/null \
|
||||||
|
|| fail 'night-light settings omitted automatic state'
|
||||||
exercise_toggle night-light
|
exercise_toggle night-light
|
||||||
|
|
||||||
|
original_enabled="$(jq -r '.enabled' <<<"$night_light_snapshot")"
|
||||||
|
original_automatic="$(jq -r '.automatic' <<<"$night_light_snapshot")"
|
||||||
|
qs ipc call night-light restore "$original_enabled" "$original_automatic" >/dev/null
|
||||||
|
restored_snapshot="$(qs ipc call night-light settings)"
|
||||||
|
[[ "$(jq -r '.enabled' <<<"$restored_snapshot")" == "$original_enabled" ]] \
|
||||||
|
|| fail 'night-light enabled state was not restored'
|
||||||
|
[[ "$(jq -r '.automatic' <<<"$restored_snapshot")" == "$original_automatic" ]] \
|
||||||
|
|| fail 'night-light automatic schedule was not restored'
|
||||||
|
night_light_snapshot=""
|
||||||
|
|
||||||
printf 'Panama action IPC contract: PASS\n'
|
printf 'Panama action IPC contract: PASS\n'
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ set -euo pipefail
|
|||||||
|
|
||||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
installer="$repo_dir/setup/scripts/link-vicinae-scripts"
|
installer="$repo_dir/setup/scripts/link-vicinae-scripts"
|
||||||
|
dotfile_installer="$repo_dir/setup/scripts/link-dotfiles"
|
||||||
|
top_level_installer="$repo_dir/install"
|
||||||
work="$(mktemp -d /tmp/panama-command-install.XXXXXX)"
|
work="$(mktemp -d /tmp/panama-command-install.XXXXXX)"
|
||||||
data_dir="$work/share/vicinae"
|
data_dir="$work/share/vicinae"
|
||||||
fake_bin="$work/bin"
|
fake_bin="$work/bin"
|
||||||
@@ -20,6 +22,11 @@ cleanup() {
|
|||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
[[ -x "$installer" ]] || fail 'Vicinae script installer is missing or not executable'
|
[[ -x "$installer" ]] || fail 'Vicinae script installer is missing or not executable'
|
||||||
|
if rg -q 'setup/scripts/link-vicinae-scripts' "$dotfile_installer"; then
|
||||||
|
fail 'link-dotfiles also invokes the command installer'
|
||||||
|
fi
|
||||||
|
rg -Fq 'do "$script"; done' "$top_level_installer" \
|
||||||
|
|| fail 'top-level installer sources setup scripts into one shared shell'
|
||||||
|
|
||||||
mkdir -p "$data_dir/scripts/panama" "$fake_bin"
|
mkdir -p "$data_dir/scripts/panama" "$fake_bin"
|
||||||
printf 'user-owned\n' >"$data_dir/scripts/panama/keep.sh"
|
printf 'user-owned\n' >"$data_dir/scripts/panama/keep.sh"
|
||||||
@@ -37,12 +44,14 @@ PATH="$fake_bin:$PATH" PANAMA_PATH="$repo_dir" VICINAE_DATA_DIR="$data_dir" \
|
|||||||
PANAMA_VICINAE_TEST_LOG="$vicinae_log" "$installer" >/dev/null
|
PANAMA_VICINAE_TEST_LOG="$vicinae_log" "$installer" >/dev/null
|
||||||
|
|
||||||
target="$data_dir/scripts/panama"
|
target="$data_dir/scripts/panama"
|
||||||
backup="$data_dir/scripts/panama.pre-panama"
|
backup="$data_dir/backups/panama.pre-panama"
|
||||||
[[ -L "$target" ]] || fail 'Panama command directory was not linked'
|
[[ -L "$target" ]] || fail 'Panama command directory was not linked'
|
||||||
[[ "$(readlink -f "$target")" == "$(readlink -f "$repo_dir/config/local/share/vicinae/scripts")" ]] \
|
[[ "$(readlink -f "$target")" == "$(readlink -f "$repo_dir/config/local/share/vicinae/scripts")" ]] \
|
||||||
|| fail 'runtime command link points outside the tracked source'
|
|| fail 'runtime command link points outside the tracked source'
|
||||||
[[ -f "$backup/keep.sh" ]] || fail 'pre-existing user command directory was not preserved'
|
[[ -f "$backup/keep.sh" ]] || fail 'pre-existing user command directory was not preserved'
|
||||||
[[ "$(cat "$backup/keep.sh")" == user-owned ]] || fail 'preserved user command changed'
|
[[ "$(cat "$backup/keep.sh")" == user-owned ]] || fail 'preserved user command changed'
|
||||||
|
[[ ! -e "$data_dir/scripts/panama.pre-panama" ]] \
|
||||||
|
|| fail 'preserved commands remained inside Vicinae search paths'
|
||||||
|
|
||||||
expected_calls=$'vicinae <ping>\nvicinae <cmd> <launch> <core:reload-scripts>'
|
expected_calls=$'vicinae <ping>\nvicinae <cmd> <launch> <core:reload-scripts>'
|
||||||
[[ "$(cat "$vicinae_log")" == "$expected_calls" ]] \
|
[[ "$(cat "$vicinae_log")" == "$expected_calls" ]] \
|
||||||
@@ -55,7 +64,7 @@ PATH="$fake_bin:$PATH" PANAMA_PATH="$repo_dir" VICINAE_DATA_DIR="$data_dir" \
|
|||||||
PANAMA_VICINAE_TEST_LOG="$vicinae_log" "$installer" >/dev/null
|
PANAMA_VICINAE_TEST_LOG="$vicinae_log" "$installer" >/dev/null
|
||||||
[[ -L "$target" ]] || fail 'second install did not leave the command link intact'
|
[[ -L "$target" ]] || fail 'second install did not leave the command link intact'
|
||||||
[[ -f "$backup/keep.sh" ]] || fail 'second install disturbed the original backup'
|
[[ -f "$backup/keep.sh" ]] || fail 'second install disturbed the original backup'
|
||||||
[[ ! -e "$data_dir/scripts/panama.pre-panama.pre-panama" ]] \
|
[[ ! -e "$data_dir/backups/panama.pre-panama.pre-panama" ]] \
|
||||||
|| fail 'second install created a duplicate backup'
|
|| fail 'second install created a duplicate backup'
|
||||||
|
|
||||||
printf 'Panama command install contract: PASS\n'
|
printf 'Panama command install contract: PASS\n'
|
||||||
|
|||||||
Reference in New Issue
Block a user