Browse Source

Patch Script für neue Verzeichnisse

master
Andre Knieschewski 2 weeks ago
parent
commit
324d2defba
  1. 300
      superx/WEB-INF/conf/edustore/db/bin/patch_apply.x
  2. 49
      superx/WEB-INF/conf/edustore/db/bin/patch_scripts_create.x

300
superx/WEB-INF/conf/edustore/db/bin/patch_apply.x

@ -1,82 +1,270 @@ @@ -1,82 +1,270 @@
#!/bin/bash
# SuperX Patch installieren (klassische Installation und Webapp-Struktur)
# Kompatibel mit den bisherigen Patch-ZIPs und patch_generate.xsl.
#
# Aufrufe:
# patch_apply.x patch_12345_superx_utf8.zip
# patch_apply.x patch_12345_superx_utf8.zip kenn,sos
# patch_apply.x patch_12345_superx_utf8.zip --webapp /pfad/zur/webapp/superx
# patch_apply.x patch_12345_superx_iso.zip --superx-dir /home/superx
#
# Voraussetzung: Die SuperX-Umgebung (z.B. SQL_ENV) ist vor dem Aufruf
# geladen oder die Pfade werden mit --webapp / --superx-dir angegeben.
# Die Datenbankbefehle und ihre Umgebung werden durch die Modulskripte benoetigt.
#Variablen:
set -o pipefail
export PATCH_DIR_FILE=$1
usage() {
cat <<'USAGE'
Aufruf: patch_apply.x PATCH_ZIP [MODUL1,MODUL2,...] [Optionen]
if test "$2#" != "#" ; then
export PATCH_MODULE_LIST_EINGABE=$2
declare -a PATCH_MODULE_LIST_PARAM=(`echo ${PATCH_MODULE_LIST_EINGABE[*]}| tr ',' '\n'`)
fi
Optionen:
--webapp PFAD SuperX-Webapp-Verzeichnis (WEBAPP)
--superx-dir PFAD SuperX-DB-/Modulverzeichnis (SUPERX_DIR)
--encoding WERT utf8 oder iso (sonst aus ZIP-Namen / Inhalt)
-h, --help Diese Hilfe anzeigen
if [[ $LANG == *utf* ]]
then
ENCODING=utf8
else
if [[ $LANG == *UTF* ]]
then
ENCODING=utf8
Die ZIP wird in das aktuelle Arbeitsverzeichnis entpackt; der Unterordner
mit der Patch-ID bleibt dort bestehen. Das Installationsprotokoll liegt
im aktuellen Verzeichnis als patch_<PATCH_ID>[_MANDANTENID].log.
Die reinen webapps_utf8.zip-Dateien sind nicht fuer patch_apply.x gedacht:
Sie werden direkt im Stammverzeichnis der SuperX-Webapp entpackt.
USAGE
}
fail() {
printf 'ERROR: %s\n' "$*" >&2
if [[ -n "${LOG:-}" ]]; then
printf 'ERROR: %s\n' "$*" >> "$LOG"
printf 'Protokoll: %s\n' "$LOG" >&2
fi
exit 1
}
PATCH_DIR_FILE=''
PATCH_MODULE_LIST_EINGABE=''
ENCODING_OPTION=''
WEBAPP_OPTION=''
SUPERX_DIR_OPTION=''
LOG=''
while (($#)); do
case "$1" in
--webapp|--superx-dir|--encoding)
(($# >= 2)) || fail "Wert fuer $1 fehlt."
case "$1" in
--webapp) WEBAPP_OPTION=$2 ;;
--superx-dir) SUPERX_DIR_OPTION=$2 ;;
--encoding) ENCODING_OPTION=$2 ;;
esac
shift 2
;;
--webapp=*) WEBAPP_OPTION=${1#*=}; shift ;;
--superx-dir=*) SUPERX_DIR_OPTION=${1#*=}; shift ;;
--encoding=*) ENCODING_OPTION=${1#*=}; shift ;;
-h|--help) usage; exit 0 ;;
--*) fail "Unbekannte Option: $1" ;;
*)
if [[ -z "$PATCH_DIR_FILE" ]]; then
PATCH_DIR_FILE=$1
elif [[ -z "$PATCH_MODULE_LIST_EINGABE" ]]; then
PATCH_MODULE_LIST_EINGABE=$1
else
ENCODING=iso
fi
fi
fail "Zu viele Parameter: $1"
fi
shift
;;
esac
done
[[ -n "$PATCH_DIR_FILE" ]] || { usage >&2; fail 'Bitte als ersten Parameter die Patch-ZIP angeben.'; }
[[ -z "$ENCODING_OPTION" || "$ENCODING_OPTION" == utf8 || "$ENCODING_OPTION" == iso ]] || fail '--encoding muss utf8 oder iso sein.'
#Testen ob unzip installiert ist
hash unzip 2>&- || { echo >&2 "Für dieses Script wird 'unzip' benötigt."; exit 1; }
for tool in unzip; do
command -v "$tool" >/dev/null 2>&1 || fail "Das Programm '$tool' wird benoetigt."
done
export PATCH_DIR=`pwd`
# Absoluten Pfad der ZIP bestimmen, ohne ihren Namen zu veraendern.
[[ -f "$PATCH_DIR_FILE" ]] || fail "Patch-ZIP nicht gefunden: $PATCH_DIR_FILE"
ZIP_BASENAME=$(basename -- "$PATCH_DIR_FILE")
ZIP_PARENT=$(cd -P -- "$(dirname -- "$PATCH_DIR_FILE")" && pwd -P) || fail 'ZIP-Verzeichnis nicht erreichbar.'
ZIP_FILE="$ZIP_PARENT/$ZIP_BASENAME"
PATCH_DIR=$(pwd -P) || fail 'Aktuelles Arbeitsverzeichnis konnte nicht bestimmt werden.'
export LOG=$PATCH_DIR_FILE$MANDANTENID.log
echo "start" >$LOG
# Patch-ID DIREKT aus dem Archiv lesen. Eine alte patch_version.txt im
# Arbeitsverzeichnis darf auf keinen Fall eine andere Installation ausloesen.
PATCH_ID=$(unzip -p "$ZIP_FILE" patch_version.txt) || fail 'patch_version.txt fehlt in der ZIP. Ist es eine reine Webapp-ZIP?'
PATCH_ID=${PATCH_ID//$'\r'/}
[[ "$PATCH_ID" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || fail "Ungueltige Patch-ID in der ZIP: $PATCH_ID"
#Test ob PatchID angegeben wurde
if [ "$PATCH_DIR_FILE" = "" ] ; then
echo "error: Bitte als ersten Parameter die Patchdatei angeben."
exit 1
# Log im Arbeitsverzeichnis; bei erneuter Ausfuehrung wird es ueberschrieben.
MANDANTEN_SUFFIX=''
if [[ -n "${MANDANTENID:-}" ]]; then
[[ "${MANDANTENID}" =~ ^[A-Za-z0-9._-]+$ ]] || fail 'MANDANTENID enthaelt ungueltige Zeichen fuer einen Log-Dateinamen.'
MANDANTEN_SUFFIX="_${MANDANTENID}"
fi
LOG="$PATCH_DIR/patch_${PATCH_ID}${MANDANTEN_SUFFIX}.log"
: > "$LOG" || fail "Protokolldatei kann nicht geschrieben werden: $LOG"
echo >>$LOG
echo "Starte Installation von Patch $PATCH_DIR_FILE" >>$LOG
echo >>$LOG
# Das Archiv nur im Patch-Verzeichnis entpacken und keine fremden Pfade
# ausserhalb <PATCH_ID>/ zulassen. Ein vorhandener Patch-Ordner darf kein
# Symlink sein.
unzip -tqq "$ZIP_FILE" >>"$LOG" 2>&1 || fail "ZIP-Archiv ist beschaedigt: $ZIP_FILE"
ZIP_LIST=$(unzip -Z -1 "$ZIP_FILE") || fail 'ZIP-Inhaltsverzeichnis kann nicht gelesen werden.'
while IFS= read -r entry; do
[[ -n "$entry" ]] || continue
case "$entry" in
patch_version.txt|"$PATCH_ID"/|"$PATCH_ID"/*) ;;
*) fail "Unerwarteter ZIP-Pfad (nur $PATCH_ID/ erlaubt): $entry" ;;
esac
case "/$entry" in
*/../*|*/./*|*/..|*/.) fail "Unsicherer ZIP-Pfad: $entry" ;;
esac
done <<< "$ZIP_LIST"
[[ ! -L "$PATCH_DIR/$PATCH_ID" ]] || fail "Patch-Verzeichnis ist ein Symlink: $PATCH_DIR/$PATCH_ID"
#Test ob Patch vorhanden
if test -f $PATCH_DIR_FILE ; then
echo "$PATCH_DIR_FILE wird nach $PATCH_DIR entpackt" >>$LOG
unzip -o $PATCH_DIR_FILE -d $PATCH_DIR >>$LOG 2>&1
# Die Auswahl aus dem ZIP-Dateinamen ist unabhaengig von LANG und verhindert,
# dass eine ISO-ZIP auf einem UTF-8-System versehentlich als UTF-8 gestartet wird.
if [[ -n "$ENCODING_OPTION" ]]; then
PATCH_ENCODING=$ENCODING_OPTION
elif [[ "$ZIP_BASENAME" == *_superx_iso.zip ]]; then
PATCH_ENCODING=iso
elif [[ "$ZIP_BASENAME" == *_superx_utf8.zip ]]; then
PATCH_ENCODING=utf8
else
echo "error: Die Datei $PATCH_DIR_FILE wurde nicht gefunden." >>$LOG
echo "Installation wird abgebrochen!" >>$LOG
exit 1
UTF_INSTALL="$PATCH_ID/patch_${PATCH_ID}_installieren_superx_utf8.sh"
ISO_INSTALL="$PATCH_ID/patch_${PATCH_ID}_installieren_superx_iso.sh"
if grep -Fxq -- "$UTF_INSTALL" <<< "$ZIP_LIST" && ! grep -Fxq -- "$ISO_INSTALL" <<< "$ZIP_LIST"; then
PATCH_ENCODING=utf8
elif grep -Fxq -- "$ISO_INSTALL" <<< "$ZIP_LIST" && ! grep -Fxq -- "$UTF_INSTALL" <<< "$ZIP_LIST"; then
PATCH_ENCODING=iso
else
fail 'Kodierung nicht eindeutig: bitte --encoding utf8 oder --encoding iso angeben.'
fi
fi
#Test ob patch_version.txt vorhanden
if test -f patch_version.txt ; then
export PATCH_ID=`cat patch_version.txt`
else
echo "error: Die Datei patch_version.txt wurde nicht gefunden." >>$LOG
echo "Installation wird abgebrochen!" >>$LOG
exit 1
INSTALL_REL="$PATCH_ID/patch_${PATCH_ID}_installieren_superx_${PATCH_ENCODING}.sh"
grep -Fxq -- "$INSTALL_REL" <<< "$ZIP_LIST" || fail "Installationsskript fehlt in ZIP: $INSTALL_REL"
# Optional eine Liste von Modulen (wie bisher als zweiter Parameter) annehmen.
# Die alten generierten Hauptskripte konnten Modulnamen wegen '-eq' nicht
# korrekt vergleichen und konnten Bash-Arrays nicht per export uebernehmen.
# Fuer genau diese Alt-Patches werden ausgewaehlte Module direkt gestartet.
declare -a PATCH_MODULE_LIST=()
if [[ -n "$PATCH_MODULE_LIST_EINGABE" ]]; then
IFS=',' read -r -a raw_modules <<< "$PATCH_MODULE_LIST_EINGABE"
for raw in "${raw_modules[@]}"; do
module=${raw#"${raw%%[![:space:]]*}"}
module=${module%"${module##*[![:space:]]}"}
[[ "$module" =~ ^[A-Za-z0-9_][A-Za-z0-9_-]*$ ]] || fail "Ungueltiger Modulname: $raw"
PATCH_MODULE_LIST+=("$module")
done
((${#PATCH_MODULE_LIST[@]})) || fail 'Leere Modul-Auswahl.'
# Alle angeforderten Module vorab pruefen, damit keine Teilinstallation
# beginnt, wenn eines davon gar nicht im Patch enthalten ist.
for module in "${PATCH_MODULE_LIST[@]}"; do
MODUL_REL="$PATCH_ID/${module}_patch_${PATCH_ID}_superx_${PATCH_ENCODING}.sh"
grep -Fxq -- "$MODUL_REL" <<< "$ZIP_LIST" || fail "Modul $module ist nicht in diesem Patch enthalten."
done
fi
# WEBAPP und SUPERX_DIR aus expliziten Argumenten oder Umgebung bestimmen.
# In einer Webapp-Struktur liegt SUPERX_DIR unter WEB-INF/conf/edustore.
[[ -z "$WEBAPP_OPTION" ]] || WEBAPP=$WEBAPP_OPTION
[[ -z "$SUPERX_DIR_OPTION" ]] || SUPERX_DIR=$SUPERX_DIR_OPTION
# Ein explizit uebergebenes Ziel hat Vorrang vor ggf. alten Umgebungswerten.
# Fuer Sonderstrukturen koennen beide Pfade explizit gesetzt werden.
if [[ -n "$WEBAPP_OPTION" && -z "$SUPERX_DIR_OPTION" && -d "$WEBAPP/WEB-INF/conf/edustore/db" ]]; then
SUPERX_DIR="$WEBAPP/WEB-INF/conf/edustore"
fi
if [[ -n "$SUPERX_DIR_OPTION" && -z "$WEBAPP_OPTION" ]]; then
if [[ "$SUPERX_DIR" == */WEB-INF/conf/edustore ]]; then
WEBAPP=${SUPERX_DIR%/WEB-INF/conf/edustore}
else
WEBAPP="$SUPERX_DIR/webserver/tomcat/webapps/superx"
fi
fi
if [[ -z "${WEBAPP:-}" && -n "${SUPERX_DIR:-}" ]]; then
if [[ "$SUPERX_DIR" == */WEB-INF/conf/edustore ]]; then
WEBAPP=${SUPERX_DIR%/WEB-INF/conf/edustore}
else
WEBAPP="$SUPERX_DIR/webserver/tomcat/webapps/superx"
fi
fi
if [[ -z "${SUPERX_DIR:-}" && -n "${WEBAPP:-}" && -d "$WEBAPP/WEB-INF/conf/edustore/db" ]]; then
SUPERX_DIR="$WEBAPP/WEB-INF/conf/edustore"
fi
[[ -n "${SUPERX_DIR:-}" && -d "$SUPERX_DIR/db" ]] || fail "SUPERX_DIR/db nicht gefunden: ${SUPERX_DIR:-<nicht gesetzt>}"
[[ -n "${WEBAPP:-}" && -d "$WEBAPP/WEB-INF" ]] || fail "WEBAPP/WEB-INF nicht gefunden: ${WEBAPP:-<nicht gesetzt>}"
SUPERX_DIR=$(cd -P -- "$SUPERX_DIR" && pwd -P) || fail 'SUPERX_DIR nicht erreichbar.'
WEBAPP=$(cd -P -- "$WEBAPP" && pwd -P) || fail 'WEBAPP nicht erreichbar.'
export PATCH_DIR_FILE PATCH_DIR PATCH_ID PATCH_MODULE_LIST_EINGABE SUPERX_DIR WEBAPP LOG
#Test ob PatchVerzeichnis richtig angelegt wurde
if test ! -d "$PATCH_DIR"/"$PATCH_ID" ; then
echo "error: Das Verzeichnis $PATCH_DIR/$PATCH_ID wurde nicht gefunden." >>$LOG
echo "Eventuell wurde das Paket nicht richtig entpackt." >>$LOG
echo "Installation wird abgebrochen!" >>$LOG
exit 1
# Das neue, generierte Patchskript verwendet rsync zum Kopieren der Dateien.
# Ein alter Patch benoetigt rsync nicht, kann also weiterhin ohne es laufen.
if unzip -p "$ZIP_FILE" "$INSTALL_REL" | grep -Fq '# Installationsskript eines SuperX-Patches'; then
command -v rsync >/dev/null 2>&1 || fail "'rsync' wird fuer diesen Patch benoetigt."
fi
echo
echo
printf 'Patch: %s\nPatch-ID: %s\nKodierung: %s\nSUPERX_DIR: %s\nWEBAPP: %s\nArbeitsverzeichnis: %s\n' \
"$ZIP_FILE" "$PATCH_ID" "$PATCH_ENCODING" "$SUPERX_DIR" "$WEBAPP" "$PATCH_DIR" | tee -a "$LOG"
if [[ -n "$PATCH_MODULE_LIST_EINGABE" ]]; then
printf 'Ausgewaehlte Module: %s\n' "$PATCH_MODULE_LIST_EINGABE" | tee -a "$LOG"
fi
$PATCH_DIR/$PATCH_ID/patch_"$PATCH_ID"_installieren_superx_$ENCODING.sh >>$LOG 2>&1
# Vorhandene Unterordner bleiben fuer eine erneute Installation erhalten,
# muessen aber frei von Symlinks sein (kein Schreiben in fremde Verzeichnisse).
if [[ -d "$PATCH_DIR/$PATCH_ID" ]] && [[ -n "$(find "$PATCH_DIR/$PATCH_ID" -type l -print -quit)" ]]; then
fail "Vorhandenes Patch-Verzeichnis enthaelt Symlinks: $PATCH_DIR/$PATCH_ID"
fi
printf 'Entpacke ZIP nach %s ...\n' "$PATCH_DIR" | tee -a "$LOG"
unzip -o "$ZIP_FILE" -d "$PATCH_DIR" >> "$LOG" 2>&1 || fail 'Entpacken des Patch-ZIPs fehlgeschlagen.'
INSTALL_SCRIPT="$PATCH_DIR/$INSTALL_REL"
[[ -f "$INSTALL_SCRIPT" && ! -L "$INSTALL_SCRIPT" ]] || fail "Installationsskript nicht gefunden: $INSTALL_SCRIPT"
# Aeltere Hauptskripte rufen Modulskripte direkt auf. Auch ZIPs, bei denen
# die Ausfuehrungsrechte nicht mitgespeichert wurden, sollen funktionieren.
while IFS= read -r member; do
case "$member" in
"$PATCH_ID/"*"_patch_${PATCH_ID}_superx_${PATCH_ENCODING}.sh")
[[ -f "$PATCH_DIR/$member" && ! -L "$PATCH_DIR/$member" ]] || fail "Modulskript ungueltig: $member"
chmod u+x -- "$PATCH_DIR/$member" || fail "Modulskript kann nicht ausfuehrbar gemacht werden: $member"
;;
esac
done <<< "$ZIP_LIST"
printf 'Starte Installation ...\n' | tee -a "$LOG"
INSTALL_STATUS=0
echo >>$LOG
echo "Installation von Patch $PATCH_DIR_FILE abgeschlossen." >>$LOG
echo >>$LOG
# Selektiver Aufruf von Alt-Patches: direkter Aufruf der Module, um den
# bisherigen Fehler mit numerischem Stringvergleich (-eq) zu umgehen.
if ((${#PATCH_MODULE_LIST[@]})) && grep -Fq 'PATCH_MODULE_LIST_PARAM[@]' "$INSTALL_SCRIPT"; then
printf 'Altes Patch-Format erkannt: ausgewaehlte Module werden direkt gestartet.\n' | tee -a "$LOG"
for module in "${PATCH_MODULE_LIST[@]}"; do
MODUL_REL="$PATCH_ID/${module}_patch_${PATCH_ID}_superx_${PATCH_ENCODING}.sh"
if ! grep -Fxq -- "$MODUL_REL" <<< "$ZIP_LIST"; then
fail "Modul $module ist nicht in diesem Patch enthalten."
fi
printf 'Installiere Modul %s ...\n' "$module" | tee -a "$LOG"
bash "$PATCH_DIR/$MODUL_REL" 2>&1 | tee -a "$LOG"
INSTALL_STATUS=${PIPESTATUS[0]}
((INSTALL_STATUS == 0)) || break
done
else
bash "$INSTALL_SCRIPT" 2>&1 | tee -a "$LOG"
INSTALL_STATUS=${PIPESTATUS[0]}
fi
if ((INSTALL_STATUS != 0)); then
fail "Installation fehlgeschlagen (Exitcode $INSTALL_STATUS)."
fi
echo "Script beendet, untersuche $LOG auf Fehler:"
cat $LOG | grep -i error
# Aeltere generierte Installationsskripte melden manche Fehler nur im Text
# und liefern trotzdem Exitcode 0. Diese offensichtlichen Fehler erkennen.
if grep -Eiq '(^|[[:space:]])error[[:space:]]*:' "$LOG"; then
fail 'Im Installationsprotokoll wurden Fehlermeldungen gefunden.'
fi
printf 'Installation von Patch %s erfolgreich abgeschlossen.\nProtokoll: %s\n' "$PATCH_ID" "$LOG" | tee -a "$LOG"
exit 0

49
superx/WEB-INF/conf/edustore/db/bin/patch_scripts_create.x

@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
#!/bin/bash
# Script das aus einer XML-Datei Patch Script erzeugt
#(c) 2011 Andre Knieschewski
PATCH_ID=$1
PATCH_DIR=$2
if [ "$PATCH_ID" == "" ] ; then
echo "Bitte Patch ID angeben!"
exit 1
fi
if [ "$WEBAPP" == "" ] ; then
#in SuperX 3.5 ist webapp immer hier:
WEBAPP=$SUPERX_DIR/webserver/tomcat/webapps/superx
fi
if [ "$PATCH_DIR" == "" ]
then
if test -d /home/superx/git/superx/superx/WEB-INF/patch ; then
PATCH_DIR=/home/superx/git/superx/superx/WEB-INF/patch
else
echo "Bitte Patch Dir angeben!"
echo "Aufruf:"
echo "patch_scripts_create.x <<PATCH_ID>> <<PATCH_DIR>>"
exit 1
fi
fi
if test ! -f $PATCH_DIR/xml/patch_$PATCH_ID.xml ; then
echo "XML Datei $PATCH_DIR/xml/patch_$PATCH_ID.xml nicht gefunden!"
exit 1
fi
echo "Erzeuge Patch-Scripte"
echo "Pfad: $PATCH_DIR"
echo
ant -f $SUPERX_DIR/db/conf/patch_scripts_create_ant.xml -DPATCH_DIR=$PATCH_DIR -DPATCH_ID=$PATCH_ID
cd $PATCH_DIR/patch_tmp
patch_"$PATCH_ID"_kopieren.x
mv $PATCH_ID/*"$PATCH_ID"*.htm $PATCH_DIR/patch_archive
rm -R $PATCH_ID
#rm patch_"$PATCH_ID"_kopieren.x
#rm patch_version.txt
mv patch_"$PATCH_ID"*.zip $PATCH_DIR/patch_archive
Loading…
Cancel
Save