Skip to main content

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.

---