The main sweep — ~260 call sites across ~100 files move from string
concatenation on a single root to appDir/storageAppDirs/storageAppConfigs.
On a single-root install the resolved paths are identical, so this is a
no-op until a location is registered.
Enumerators were the interesting half. `for d in "$containers_dir"/*/`
appears in the menus, the registry/artifact scanners and the DNS setup —
and a shell glob cannot list a rootless 751 tree at all, which is the
same bug config_find_file.sh already documents in a comment. Routing them
through storageAppDirs (which enumerates as the owning user) fixes that
alongside the multi-root work.
Three places needed judgement rather than substitution:
db_app_scan.sh deletes database rows and port allocations for apps whose
folder is missing, and reaps "empty" app dirs. With a storage location
unmounted, every app on it looks exactly like that. Each of those
branches now gates on appStorageAvailable first — an app on an unplugged
drive is skipped with a notice, never deleted.
instance_create.sh rewrites cloned hooks so an instance touches its own
directory instead of the base app's. Its sed matched ${containers_dir}<type>,
which this sweep just replaced with $(appDir <type>) — so it would have
silently stopped redirecting, and an instance would have written to the
original's files (the adguard auth adapter case its own comment warns
about). Now matches both appDir forms, verified against bare, quoted,
unrelated-app, legacy and prose cases.
peer_shell/peer_pull streamed and extracted relative to the primary root.
Both now use the app's own root, and peer_shell keeps a single-root
fallback since it runs as a restricted SSH shell with no LibrePortal env.
Also fixes a pre-existing bug found on the way: webui_app_config.sh
tested "$containers_dir/frontend/data/last_update", one level short of the
real tree under the libreportal app dir, so the WebUI refresh trigger
after a config update has never once fired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
3.4 KiB
Bash
84 lines
3.4 KiB
Bash
#!/bin/bash
|
|
|
|
# SearXNG install hooks — wait for settings.yml, apply theme, restart.
|
|
|
|
searxng_install_post_start()
|
|
{
|
|
local app_name="$1"
|
|
|
|
local searxng_settings="$(appDir "$app_name")/searxng-data/settings.yml"
|
|
local searxng_timeout=10
|
|
local searxng_counter=0
|
|
while [ ! -f "$searxng_settings" ]; do
|
|
if [ "$searxng_counter" -ge "$searxng_timeout" ]; then
|
|
isNotice "File not found after 10 seconds. Exiting..."
|
|
return 0
|
|
fi
|
|
isNotice "Waiting for the file to appear..."
|
|
read -t 1
|
|
searxng_counter=$((searxng_counter + 1))
|
|
done
|
|
|
|
# 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
|
|
}
|