diff --git a/containers/searxng/scripts/searxng_install_hooks.sh b/containers/searxng/scripts/searxng_install_hooks.sh index dab2a8f..d507643 100644 --- a/containers/searxng/scripts/searxng_install_hooks.sh +++ b/containers/searxng/scripts/searxng_install_hooks.sh @@ -1,14 +1,15 @@ #!/bin/bash -# SearxNG install hooks — wait for settings.yml, apply theme, restart. +# SearXNG install hooks — wait for settings.yml, apply theme, restart. searxng_install_post_start() { local app_name="$1" + local searxng_settings="$containers_dir$app_name/searxng-data/settings.yml" local searxng_timeout=10 local searxng_counter=0 - while [ ! -f "$containers_dir$app_name/searxng-data/settings.yml" ]; do + while [ ! -f "$searxng_settings" ]; do if [ "$searxng_counter" -ge "$searxng_timeout" ]; then isNotice "File not found after 10 seconds. Exiting..." return 0 @@ -18,9 +19,65 @@ searxng_install_post_start() searxng_counter=$((searxng_counter + 1)) done - local result - result=$(runFileOp sed -i "s/simple_style: auto/simple_style: $CFG_SEARXNG_THEME/" "$containers_dir$app_name/searxng-data/settings.yml") - checkSuccess "Changing from light mode to dark mode to avoid eye strain installs" + # SearXNG validates this against a fixed set and refuses to start on anything + # else, so a typo in the config would take the whole app down rather than just + # look wrong. Check it here instead. + local searxng_theme="${CFG_SEARXNG_THEME:-auto}" + case "$searxng_theme" in + auto|light|dark|black) ;; + *) + isNotice "CFG_SEARXNG_THEME='$searxng_theme' is not one of auto|light|dark|black — leaving the theme at SearXNG's default." + return 0 + ;; + esac + + # The edit runs INSIDE the container, for two reasons the old `runFileOp sed` + # on the host could not satisfy: + # + # 1. Ownership. The entrypoint chowns this file to searxng:searxng (uid 977) + # on first start, mode 644 — so the host-side docker user cannot write to + # it at all. + # 2. Key path. The old sed replaced `simple_style: auto`, which only exists + # in SearXNG's full bundled settings.yml. The file generated here is the + # minimal `use_default_settings: true` form and has no ui: block at all, + # so the substitution matched nothing and CFG_SEARXNG_THEME had never had + # any effect on any install. + # + # The setting lives at ui.theme_args.simple_style. All three shapes are + # handled so this stays correct on a reinstall over existing data (where the + # key is already present) and if someone has hand-added their own ui: block — + # appending a second one would be a duplicate YAML key and SearXNG would + # refuse to load it. + local searxng_container="${app_name}-service" + local searxng_result + searxng_result=$(runFileOp docker exec -i "$searxng_container" sh -s "$searxng_theme" <<'SEARXNG_THEME_EOS' +set -e +theme="$1" +f=/etc/searxng/settings.yml +[ -f "$f" ] || exit 1 + +if grep -qE '^[[:space:]]*simple_style:' "$f"; then + # Already set (reinstall over existing data): update in place, keeping + # whatever indentation it currently sits at. + sed -i -E "s/^([[:space:]]*)simple_style:.*/\1simple_style: $theme/" "$f" +elif grep -qE '^ui:[[:space:]]*$' "$f"; then + # A ui: block exists but carries no theme_args — nest ours inside it rather + # than appending a second ui:, which would be a duplicate YAML key. awk, not + # `sed a\`, because busybox sed does not expand \n in appended text. + awk -v t="$theme" ' + /^ui:[[:space:]]*$/ { print; print " theme_args:"; print " simple_style: " t; next } + { print } + ' "$f" > "$f.lp.tmp" + cat "$f.lp.tmp" > "$f" + rm -f "$f.lp.tmp" +else + # The normal case for a LibrePortal install: the generated file is the + # minimal use_default_settings form with no ui: block at all. + printf '\nui:\n theme_args:\n simple_style: %s\n' "$theme" >> "$f" +fi +SEARXNG_THEME_EOS +) + checkSuccess "Applying SearXNG theme '$searxng_theme'" dockerComposeRestart $app_name } diff --git a/scripts/cli/commands/updater/cli_updater_verify.sh b/scripts/cli/commands/updater/cli_updater_verify.sh index 96f6454..a7fdb5e 100644 --- a/scripts/cli/commands/updater/cli_updater_verify.sh +++ b/scripts/cli/commands/updater/cli_updater_verify.sh @@ -25,8 +25,40 @@ # conservative and is NOT sufficient for a stepped upgrade — the engine refuses # to ladder an app that has not declared a real one. -# Container name for an app's primary service, matching the compose convention. -_updaterPrimaryContainer() { printf '%s-service' "${1//_/-}"; } +# Container name for an app's ANCHOR service — the one whose image carries the +# app's own version. Read from the compose rather than assumed, because +# "-service" is a convention and not every app follows it: matrix names its +# anchor service matrix-synapse and stoat names its api, so the assumption +# inspected a container that does not exist, found no state at all, and the +# generic verifier could only ever time out on exactly the stateful apps that +# most need verifying. Falls back to the convention when there is no compose. +_updaterPrimaryContainer() { + local app="$1" + local compose="${containers_dir%/}/$app/docker-compose.yml" + local fallback; fallback="$(printf '%s-service' "${app//_/-}")" + [ -f "$compose" ] || { printf '%s' "$fallback"; return 0; } + + local up; up="$(printf '%s' "$app" | tr '[:lower:]' '[:upper:]')" + # The service block that owns the bare _VERSION_TAG sentinel, then that + # block's container_name (compose's own answer for what the container is + # called). Service name is the fallback: compose defaults to it. + local name + name="$(awk -v key="#LIBREPORTAL|${up}_VERSION_TAG|" ''' + /^[[:space:]]{2,4}[a-zA-Z0-9_-]+:[[:space:]]*(#|$)/ { + s=$1; sub(/:.*/,"",s); gsub(/[[:space:]]/,"",s) + if (found && cname=="") { print svc; exit } + if (found) exit + svc=s; cname="" + } + index($0,key) { found=1 } + found && /^[[:space:]]*container_name:/ { + cname=$2; gsub(/["']/,"",cname); print cname; exit + } + END { if (found && cname=="") print svc } + ''' "$compose" 2>/dev/null | head -1 | tr -d "[:space:]")" + + [ -n "$name" ] && printf '%s' "$name" || printf '%s' "$fallback" +} # Generic health: running, not restarting, healthcheck (if any) reporting # healthy, and STILL true after a settle period — a crash-loop looks perfect