Fix a false Nextcloud health warning

Two compounding bugs: the check looked for an autostart entry named
"nextcloud.desktop", but current nextcloud-client packages ship it
Title-cased as "Nextcloud.desktop" -- a case-sensitive filesystem
never matched, so it always reported "autostart is not configured"
even with autostart genuinely on. Made the lookup case-insensitive so
a future package rename doesn't reintroduce this.

Second, even past that, it ran systemctl against "nextcloud.service" --
a unit that doesn't exist in either scope, because the client is a
plain autostarted process with no systemd unit behind it at all (same
reasoning as the RustDesk autostart.lua comment, different shape: no
service to query rather than the wrong scope). Added a process_check
helper alongside the existing service_check and switched Nextcloud to
it; confirmed live it now reports "Process is running."

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
This commit is contained in:
Gabriel Brown
2026-08-19 07:53:04 -04:00
parent 9bc771bcca
commit 8156fc47ca
2 changed files with 29 additions and 9 deletions
+21 -3
View File
@@ -124,7 +124,6 @@ SYSTEMCTL_COMMANDS = {
"hypridle": ("systemctl", "--user", "is-active", "--quiet", "hypridle.service"), "hypridle": ("systemctl", "--user", "is-active", "--quiet", "hypridle.service"),
"vicinae": ("systemctl", "--user", "is-active", "--quiet", "vicinae.service"), "vicinae": ("systemctl", "--user", "is-active", "--quiet", "vicinae.service"),
"pipewire": ("systemctl", "--user", "is-active", "--quiet", "pipewire.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 # System-scope, not --user: RustDesk ships an enabled *system* service
# (`rustdesk --service`, root-owned) that spawns the session --server and # (`rustdesk --service`, root-owned) that spawns the session --server and
# --tray on its own -- see autostart.lua's comment on why Panama doesn't # --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) 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: def ipc_target(config: DoctorConfig, target: str) -> CommandResult:
result = run_command(("qs", "ipc", "show"), config) result = run_command(("qs", "ipc", "show"), config)
if result.state != "ok": if result.state != "ok":
@@ -408,9 +417,18 @@ def check_brightness(config: DoctorConfig) -> Check:
def check_nextcloud(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 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: def check_rustdesk(config: DoctorConfig) -> Check:
+8 -6
View File
@@ -86,7 +86,7 @@ EOF
chmod +x "$bin_dir/panama-brightness" chmod +x "$bin_dir/panama-brightness"
mkdir -p "$config_home/autostart" 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 for name in hypr quickshell uwsm vicinae; do
ln -s "$repo_dir/config/dot/$name" "$config_home/$name" ln -s "$repo_dir/config/dot/$name" "$config_home/$name"
done done
@@ -209,14 +209,16 @@ check_status "$missing_qs" desktop.quickshell error
mv "$bin_dir/qs.off" "$bin_dir/qs" mv "$bin_dir/qs.off" "$bin_dir/qs"
# Optional integrations stay neutral until the user configures them. # 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)" unconfigured_nextcloud="$(run_doctor --json)"
check_status "$unconfigured_nextcloud" integration.nextcloud unconfigured 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, # A configured integration whose process isn't running is actionable with an
# never an application name or command derived from probe output. # authored label, never an application name or command derived from probe
stopped_nextcloud="$(PANAMA_DOCTOR_FIXTURE_STOPPED=nextcloud.service run_doctor --json)" # 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 check_status "$stopped_nextcloud" integration.nextcloud warning
jq -e '.checks[] | select(.id == "integration.nextcloud") jq -e '.checks[] | select(.id == "integration.nextcloud")
| .action == {kind:"open", label:"Open Nextcloud", confirm:false}' \ | .action == {kind:"open", label:"Open Nextcloud", confirm:false}' \