diff --git a/config/dot/quickshell/scripts/panama-doctor b/config/dot/quickshell/scripts/panama-doctor index ca556ad..0d022b6 100755 --- a/config/dot/quickshell/scripts/panama-doctor +++ b/config/dot/quickshell/scripts/panama-doctor @@ -124,7 +124,6 @@ SYSTEMCTL_COMMANDS = { "hypridle": ("systemctl", "--user", "is-active", "--quiet", "hypridle.service"), "vicinae": ("systemctl", "--user", "is-active", "--quiet", "vicinae.service"), "pipewire": ("systemctl", "--user", "is-active", "--quiet", "pipewire.service"), - "nextcloud": ("systemctl", "--user", "is-active", "--quiet", "nextcloud.service"), # System-scope, not --user: RustDesk ships an enabled *system* service # (`rustdesk --service`, root-owned) that spawns the session --server and # --tray on its own -- see autostart.lua's comment on why Panama doesn't @@ -304,6 +303,16 @@ def service_check(check_id: str, title: str, service: str, config: DoctorConfig, return Check(check_id, group_for(check_id), title, "warning", "Service is not active.", action) +def process_check(check_id: str, title: str, process: str, config: DoctorConfig, action: Action | None = None) -> Check: + """Like service_check, for autostarted apps with no systemd unit behind them.""" + result = run_command(("pgrep", "-u", str(os.getuid()), "-x", process), config) + if result.state == "ok": + return Check(check_id, group_for(check_id), title, "ok", "Process is running.") + if result.state in {"missing", "unavailable"}: + return Check(check_id, group_for(check_id), title, "error", "Required process probe is unavailable.") + return Check(check_id, group_for(check_id), title, "warning", "Process is not running.", action) + + def ipc_target(config: DoctorConfig, target: str) -> CommandResult: result = run_command(("qs", "ipc", "show"), config) if result.state != "ok": @@ -408,9 +417,18 @@ def check_brightness(config: DoctorConfig) -> Check: def check_nextcloud(config: DoctorConfig) -> Check: - if not (config.config_home / "autostart" / "nextcloud.desktop").is_file(): + # The client's autostart entry is Title-cased ("Nextcloud.desktop") on + # current nextcloud-client packages, but that has changed case before -- + # match either so a future package update doesn't silently reintroduce + # this as "autostart is not configured" again. + autostart_dir = config.config_home / "autostart" + if not any(autostart_dir.glob("[Nn]extcloud.desktop")): return Check("integration.nextcloud", "integrations", "Nextcloud", "unconfigured", "Nextcloud autostart is not configured.") - return service_check("integration.nextcloud", "Nextcloud", "nextcloud", config, Action("open", "Open Nextcloud")) + # No systemd unit backs this (see the autostart.lua comment on why Panama + # doesn't start it as one): the client is a plain autostarted process, so + # check for the process directly instead of a systemctl service that was + # never going to exist. + return process_check("integration.nextcloud", "Nextcloud", "nextcloud", config, Action("open", "Open Nextcloud")) def check_rustdesk(config: DoctorConfig) -> Check: diff --git a/tests/quickshell/panama-doctor-contract.sh b/tests/quickshell/panama-doctor-contract.sh index 76147e7..9ab117c 100755 --- a/tests/quickshell/panama-doctor-contract.sh +++ b/tests/quickshell/panama-doctor-contract.sh @@ -86,7 +86,7 @@ EOF chmod +x "$bin_dir/panama-brightness" mkdir -p "$config_home/autostart" -touch "$config_home/autostart/nextcloud.desktop" +touch "$config_home/autostart/Nextcloud.desktop" for name in hypr quickshell uwsm vicinae; do ln -s "$repo_dir/config/dot/$name" "$config_home/$name" done @@ -209,14 +209,16 @@ check_status "$missing_qs" desktop.quickshell error mv "$bin_dir/qs.off" "$bin_dir/qs" # Optional integrations stay neutral until the user configures them. -rm "$config_home/autostart/nextcloud.desktop" +rm "$config_home/autostart/Nextcloud.desktop" unconfigured_nextcloud="$(run_doctor --json)" check_status "$unconfigured_nextcloud" integration.nextcloud unconfigured -touch "$config_home/autostart/nextcloud.desktop" +touch "$config_home/autostart/Nextcloud.desktop" -# A configured integration that stopped is actionable with an authored label, -# never an application name or command derived from probe output. -stopped_nextcloud="$(PANAMA_DOCTOR_FIXTURE_STOPPED=nextcloud.service run_doctor --json)" +# A configured integration whose process isn't running is actionable with an +# authored label, never an application name or command derived from probe +# output. Nextcloud has no systemd unit behind it, so this is a process +# check (PANAMA_DOCTOR_FIXTURE_PROCESSES), not a service check. +stopped_nextcloud="$(PANAMA_DOCTOR_FIXTURE_PROCESSES=nextcloud:missing run_doctor --json)" check_status "$stopped_nextcloud" integration.nextcloud warning jq -e '.checks[] | select(.id == "integration.nextcloud") | .action == {kind:"open", label:"Open Nextcloud", confirm:false}' \