3. Die Dateien im Einzelnen

3.1 `build.conf` 

 Liegt auf dem Builder und wird zusätzlich ins Paket kopiert, nach `/usr/share/scoreboard-system/build.conf`. Dadurch können die Maintainer-Skripte auf dem Zielrechner dieselben Werte lesen – Pfade und Listen stehen nur an dieser einen Stelle. 

 Die Datei ist von `set -a` … `set +a` umschlossen. Dadurch werden alle Zuweisungen exportiert, sodass nfpm als eigener Prozess sie in der `nfpm.yaml` als `${...}` einsetzen kann. Ohne das würde `source build.conf` nur Shell-Variablen setzen, die nfpm nie sieht. 

 Arrays exportiert `set -a` nicht – Bash kann das nicht. Das ist in Ordnung, denn Arrays braucht nur, wer die Datei sourct. 

 Aktiv genutzte Werte: 

 | Variable | Wird gelesen von | |---|---| | `PACKAGE_NAME` | `nfpm.yaml`, `preparepackage.sh` | | `PACKAGE_VERSION` | `nfpm.yaml`, `buildpackage.sh` | | `PACKAGE_ARCH` | `nfpm.yaml`, `buildpackage.sh` | | `JAVA_VERSION`, `JAVA_PACKAGE` | `postinstall.sh`, `nfpm.yaml` | | `INSTALL_PATH` | alle Maintainer-Skripte, `preparepackage.sh` | | `SERVICE_NAME` | `postinstall.sh`, `preremove.sh`, `preparepackage.sh` | | `BUILD_ROOT`, `SOURCE_DIR`, `PACKAGE_ROOT` | `preparepackage.sh`, `buildpackage.sh` | | die vier Verzeichnislisten | `preparepackage.sh`, `postinstall.sh` | | `TEMPLATE_FILES` | `preparepackage.sh`, `postinstall.sh` | 

   

 3.2 `preparepackage.sh` 

 Läuft auf dem Builder. Baut `package-root/` neu auf: 

 1. Prüft alle Pfade, bevor irgendetwas gelöscht wird 2. Löscht `package-root/` und legt es neu an 3. `REPLACE_DIRS` → `package-root/opt/scoreboard/` 4. `INITIAL_COPY_DIRS` → `package-root/usr/share/scoreboard-system/initial/` 5. `TEMPLATE_FILES` → `package-root/usr/share/scoreboard-system/templates/` 6. `systemd/scoreboard.service` → `.../systemd/` 7. Die vier Maintainer-Skripte → `.../scripts/` 8. `build.conf` → `.../` 

 Die Prüfungen in Schritt 1 sind der Grund, warum das Skript gefahrlos ein `rm -rf` enthalten darf: 

 - Alle Variablen müssen gesetzt sein - `PACKAGE_ROOT` muss tatsächlich unterhalb von `BUILD_ROOT` liegen - Weder `PACKAGE_ROOT` noch `BUILD_ROOT` dürfen im Live-Baum liegen - `SOURCE_DIR` darf nicht `/opt/scoreboard` selbst sein - Symlinks werden vorher aufgelöst, damit sie die Prüfung nicht   aushebeln 

 Zusätzlich wird geprüft, ob bei jedem Maintainer-Skript der Shebang in Zeile 1 steht. Steht davor ein Kommentar, kann der Kernel die Datei nicht als Bash starten und dpkg fällt still auf `/bin/sh` zurück. 

 3.3 `nfpm.yaml` 

 Beschreibt das Paket. `name`, `version`, `arch` und `depends` kommen per `${...}` aus der Umgebung, also aus der `build.conf`. 

 Die Pfade unter `contents:` sind bewusst **relativ**. Stünde dort `${PACKAGE_ROOT}/opt` und die Umgebung fehlte, würde nfpm das zu `/opt` auflösen und das echte `/opt` der Maschine einpacken. Deshalb muss nfpm aus `BUILD_ROOT` heraus aufgerufen werden – `buildpackage.sh` erledigt das. 

 Zwei Einträge: 

 | Aus `package-root` | Wird zu | |---|---| | `opt/` | `/opt` (also `/opt/scoreboard/{etc,lib,web}`) | | `usr/share/scoreboard-system/` | `/usr/share/scoreboard-system` | 

 3.4 `buildpackage.sh` 

 Klammer um den ganzen Build: 

 1. `build.conf` sourcen 2. `preparepackage.sh` aufrufen 3. Nach `BUILD_ROOT` wechseln und nfpm aufrufen 4. Prüfen, ob das erzeugte `.deb` wirklich die erwartete Version    meldet, sonst abbrechen 5. `install-package.sh` mit nach `dist/` legen 

 Schritt 4 ist die Kontrolle gegen genau den Fehler, mit dem das alles angefangen hat: eine Versionsnummer in der `build.conf`, die nicht im Paket ankommt. 

 Wenn du ein eigenes Build-Skript verwenden willst, muss es mindestens die Schritte 1 bis 3 in dieser Reihenfolge tun. 

 3.5 `scripts/preinstall.sh` → `preinst` 

 Läuft auf dem Zielrechner **vor** dem Entpacken. 

 Einziger Zweck ist eine einmalige Migration. Früher gehörte `tokens` zum Paket. Jetzt nicht mehr – und beim Upgrade auf die erste Version ohne diesen Eintrag betrachtet dpkg das Verzeichnis als verwaiste Paketdatei und löscht es, bevor `postinstall.sh` überhaupt startet. 

 Das Skript legt deshalb vorher unter `/opt/scoreboard/.pre-upgrade/` eine Sicherung an. Sie arbeitet mit Hardlinks und kostet praktisch keinen Platz. `postinstall.sh` holt sie zurück und räumt sie weg. 

 Sobald alle Zielrechner über diese Version hinaus sind, kann die Liste `MIGRATE_DIRS` oben im Skript geleert werden. 

 3.6 `scripts/postinstall.sh` → `postinst` 

 Läuft **nach** dem Entpacken und macht die eigentliche Einrichtung: 

 1. Prüft, ob `$1` überhaupt `configure` ist 2. Lädt `/usr/share/scoreboard-system/build.conf` 3. Prüft, ob Java vorhanden und alt genug ist 4. Legt die `CREATE_ONLY_DIRS` an 5. Legt die `INITIAL_COPY_DIRS` an – aber nur, wenn sie fehlen.    Reihenfolge: vorhanden → nichts tun; Sicherung aus `preinst`    vorhanden → zurückholen; sonst → Seed aus dem Paket 6. Kopiert fehlende `TEMPLATE_FILES`, vorhandene bleiben 7. Setzt die Ausführungsrechte auf die Start-/Stopp-Skripte 8. Installiert die systemd-Unit und startet den Dienst 

 Die `systemctl`-Aufrufe laufen nur, wenn systemd wirklich aktiv ist (`/run/systemd/system` existiert). In einem Container oder chroot würde sonst die ganze Installation daran scheitern. 

 3.7 `scripts/preremove.sh` → `prerm` 

 Läuft **vor** dem Entfernen von Dateien – und zwar auch bei jedem Upgrade. dpkg teilt den Grund über `$1` mit: 

 | `$1` | Verhalten | |---|---| | `upgrade` | Nur den Dienst stoppen. Sonst nichts. | | `remove` | Dienst stoppen und deaktivieren. | | alles andere | Nichts tun. | 

 Gelöscht wird in keinem Fall etwas. Die Paketdateien räumt dpkg selbst ab; alles andere sind Nutzdaten und bleiben stehen. 

 Das war die Stelle mit dem ursprünglichen Datenverlust: Das alte Skript wertete `$1` nicht aus und führte deshalb bei jedem Upgrade `rm -rf /opt/scoreboard` aus. 

 3.8 `scripts/postremove.sh` → `postrm` 

 Läuft **nach** dem Entfernen. Entfernt die systemd-Unit aus `/etc/systemd/system/` und lädt systemd neu – aber nur bei `remove` und `purge`. Bei `upgrade` muss die Unit liegen bleiben. 

 `/opt/scoreboard` wird auch bei `purge` nicht gelöscht, sondern nur ein Hinweis ausgegeben. Wer das anders möchte, findet die Stelle im Skript kommentiert. 

 Dieses Skript lädt die `build.conf` bewusst nicht: Zum Zeitpunkt von `postrm` hat dpkg die Paketdateien schon entfernt. 

 3.9 `install-package.sh` 

 Läuft auf dem **Zielrechner**, nicht auf dem Builder. 

 Der Grund für seine Existenz: Bei einem Upgrade führt dpkg das `prerm` des **bereits installierten** Pakets aus, nicht das aus dem neuen. Auf einer Maschine, auf der noch eine Version mit dem alten `preremove.sh` läuft, liefe also weiterhin `rm -rf /opt/scoreboard`, egal wie korrekt das neue Paket ist. Aus dem neuen Paket heraus lässt sich das nicht verhindern, weil zu diesem Zeitpunkt noch keine Zeile daraus gelaufen ist. 

 Ablauf: 

 1. Ist überhaupt etwas installiert? Wenn nein: direkt `dpkg -i` 2. Enthält das installierte `prerm` noch die gefährliche Zeile?    Wenn nein: direkt `dpkg -i` 3. Wenn ja: Sicherung nach `/var/backups/` anlegen 4. Das `prerm` gegen die Fassung aus dem neuen `.deb` tauschen,    die alte als `.vor-update` daneben legen 5. `dpkg -i` 

 Ab dem zweiten Update ist es ein reiner Durchläufer. Du kannst es deshalb dauerhaft verwenden und musst dir nicht merken, welche Maschine schon umgestellt ist. 

 ---