#!/usr/bin/env bash # # PDF OCR Hotfolder — gemeinsame Shell-Funktionen # # Wird von install.sh und update.sh gesourct: # source "$SCRIPT_DIR/lib/common.sh" # # Diese Datei fuehrt beim Sourcen NICHTS aus, was das System anfasst — sie # enthaelt nur Definitionen und Vorgabewerte. Alle Pfade sind ueber die # Umgebung ueberschreibbar, damit sich die Funktionen gegen eine Fake-Umgebung # testen lassen (siehe PDF_OCR_UPDATE_LIB_ONLY in update.sh). # # Die Datei wird bei Installation und Update nach $INSTALL_DIR/lib/ kopiert, # damit auch ein Lauf ausserhalb des Repos sie findet. # # shellcheck shell=bash # Mehrfaches Sourcen ist harmlos, aber unnoetig. if [ -n "${PDF_OCR_COMMON_LOADED:-}" ]; then # shellcheck disable=SC2317 # 'exit' greift nur, wenn die Datei nicht gesourct wurde return 0 2>/dev/null || exit 0 fi PDF_OCR_COMMON_LOADED=1 # ============================================================ # Ausgabe # ============================================================ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERROR]${NC} $*"; } log_step() { echo -e "\n${BLUE}==>${NC} $*"; } # Bricht ab, wenn nicht root. $1 = der Aufruf, der gemeint ist. require_root() { if [ "${EUID:-$(id -u)}" -ne 0 ]; then log_error "Bitte als root ausfuehren: ${1:-sudo $0}" exit 1 fi } # ============================================================ # Installations-Layout — einzige Quelle der Wahrheit # ============================================================ : "${INSTALL_DIR:=/opt/pdf-ocr-hotfolder}" : "${CONFIG_DIR:=/etc/pdf-ocr-hotfolder}" : "${DATA_ROOT:=/var/lib/pdf-ocr-hotfolder}" : "${SYSTEMD_DIR:=/etc/systemd/system}" : "${DEFAULT_USER:=pdfocr}" SERVICE_TEMPLATE="pdf-ocr-hotfolder@.service" LXC_DROPIN_DIR="$SYSTEMD_DIR/${SERVICE_TEMPLATE}.d" # shellcheck disable=SC2034 # wird von install.sh und update.sh genutzt LXC_DROPIN="$LXC_DROPIN_DIR/lxc-compat.conf" # Pfad dieser Datei relativ zum Repo- bzw. Installationsverzeichnis. update.sh # schneidet damit die Paketliste aus der Repo-Fassung heraus (siehe unten). # shellcheck disable=SC2034 # wird von update.sh genutzt COMMON_LIB_REL="lib/common.sh" # ============================================================ # System-Pakete # ============================================================ # Der folgende Block wird von update.sh aus DIESER Datei herausgeschnitten # (sed auf die BEGIN/END-Marken) und dort ausgewertet: beim Update soll die # Liste aus dem Repo gelten, nicht die vielleicht aeltere, bereits gesourcte # aus dem Installationsverzeichnis. Die Marken und der Funktionsname duerfen # sich deshalb nicht aendern, ohne update.sh anzupassen. # --- BEGIN apt-packages (wird von update.sh extrahiert) --- pdf_ocr_apt_packages() { cat <<'PKGLIST' python3 python3-venv python3-pip tesseract-ocr tesseract-ocr-deu tesseract-ocr-eng ghostscript qpdf unpaper pngquant icc-profiles-free ca-certificates curl PKGLIST } # --- END apt-packages --- # ============================================================ # Python / venv # ============================================================ # major.minor des uebergebenen Interpreters; leer, wenn er nicht laeuft. py_mm() { local py="$1" "$py" -c 'import sys; print("%d.%d" % sys.version_info[:2])' 2>/dev/null || true } # major.minor aus pyvenv.cfg (version = / version_info =); leer, wenn unlesbar. pyvenv_cfg_mm() { local cfg="$1/pyvenv.cfg" [ -f "$cfg" ] || return 0 sed -n 's/^[[:space:]]*version\(_info\)\?[[:space:]]*=[[:space:]]*\([0-9]\+\.[0-9]\+\).*/\2/p' "$cfg" | head -n1 } # Prueft die venv gegen das aktuelle System-Python. # Setzt VENV_ISSUES (Array) und gibt 0 zurueck, wenn alles passt. # # Drei Faelle fuehren zum Neubau: (1) der Interpreter der venv laeuft gar nicht # mehr (toter Symlink nach einem Distributions-Upgrade, systemd: 203/EXEC), # (2) er laeuft noch, ist aber eine andere Version als das System-Python # (Debian 12 -> 13), (3) pyvenv.cfg und Interpreter widersprechen sich. # Keine Versionsnummer ist hier hartcodiert. VENV_ISSUES=() venv_is_healthy() { local venv="$1" local sys_mm venv_mm cfg_mm VENV_ISSUES=() if [ ! -d "$venv" ]; then VENV_ISSUES+=("venv-Verzeichnis fehlt: $venv") return 1 fi if [ ! -x "$venv/bin/python" ]; then VENV_ISSUES+=("$venv/bin/python fehlt oder ist nicht ausfuehrbar") return 1 fi venv_mm="$(py_mm "$venv/bin/python")" if [ -z "$venv_mm" ]; then VENV_ISSUES+=("$venv/bin/python laeuft nicht (toter Symlink nach einem Distributions-Upgrade?)") return 1 fi sys_mm="$(py_mm "$(command -v python3 || echo /usr/bin/python3)")" if [ -z "$sys_mm" ]; then VENV_ISSUES+=("System-python3 laeuft nicht — venv-Pruefung nicht moeglich") return 1 fi if [ "$venv_mm" != "$sys_mm" ]; then VENV_ISSUES+=("venv haengt an Python $venv_mm, das System liefert Python $sys_mm") return 1 fi cfg_mm="$(pyvenv_cfg_mm "$venv")" if [ -n "$cfg_mm" ] && [ "$cfg_mm" != "$venv_mm" ]; then VENV_ISSUES+=("pyvenv.cfg nennt Python $cfg_mm, der Interpreter meldet $venv_mm") return 1 fi return 0 } # Gibt die von venv_is_healthy gesammelten Befunde als Warnungen aus. report_venv_issues() { local issue for issue in "${VENV_ISSUES[@]:-}"; do [ -n "$issue" ] || continue log_warn " - $issue" done }