Adds rpm builder readme

Entire-Checkpoint: 01M4DXA2QYJCTNSCZXZM63D2MF
This commit is contained in:
torsten committed 2026-10-08 14:05:09 +00:00
1 parent 5d0326d2b6
commit 0d48591be4
1 file changed
+213
+213
View File
@@ -0,0 +1,213 @@
# Analyse: Ubuntu-26.04-Build-Skripte
**Analysierte Dateien**
| Datei | Rolle |
|---|---|
| `jenkins-ci-rme/jenkins_builder_ubuntu26.sh` | Bash-Einstiegspunkt (Jenkins/Container) |
| `rpmbuild/make_rpm_ubuntu26.py` | Python-Builder, erzeugt das DEB-Paket |
**Kontext:** Beide Skripte sind die Ubuntu/DEB-Variante der ursprünglichen openSUSE/RPM-Pipeline
(`jenkins_builder.sh` + `make_rpm.py`) im Zuge der Qt6-Migration. Zielplattform ist Ubuntu 26.04
mit Qt 6.10.2 (via `aqtinstall` in `/opt/Qt`). Laut `jenkins-ci-rme/README-ubuntu-docker.md` ist die
Ubuntu-Infrastruktur „für zukünftige Ubuntu-Unterstützung vorbereitet" — sie ist also noch **nicht**
in die aktive Pipeline eingebunden (das `jenkins-ci-rme/Jenkinsfile` ruft weiterhin
`jenkins/jenkins_builder.sh` auf, nicht die `_ubuntu26`-Variante).
---
## 1. `jenkins_builder_ubuntu26.sh`
### 1.1 Zweck
Baut ein LTS-DEB-Paket für ein Projekt-Flavor (`qatar` | `ahtc` | `guez`) auf Ubuntu 26.04.
Es validiert die Umgebung, legt eine saubere Quell-Kopie an und delegiert die eigentliche
Paket-Erzeugung an `make_rpm_ubuntu26.py`.
### 1.2 Ablauf (Zeile für Zeile)
1. **`set -eo pipefail`** — strikte Fehlerbehandlung: Abbruch bei jedem Fehler, bei
nicht-Null-Exit-Code und bei Fehlern in Pipelines. Gutes Fundament.
2. **Umgebungs-Validierung** via `: "${VAR:?...}"` für `PROJECT`, `OS_VERSION`, `LTS_VERSION`,
`GUEZ_MODE`, `WORKSPACE`, `PROJECT_BASE_DIR`. Fehlt eine Variable, bricht das Skript sofort
mit klarem Fehler ab. `BUILD_NUMBER`/`BUILD_TAG` sind optional.
3. **`HOME=/home/builder`** + `mkdir -p` — setzt das Home-Verzeichnis (Kommentar: „running as
root in container").
4. **Quell-Staging:** `rm -rf "${PROJECT_BASE_DIR}"` und anschließende `tar`-Pipe
(`tar -cf - -C WORKSPACE . | tar -xf - -C PROJECT_BASE_DIR`) kopiert den Workspace als
saubere Kopie. Ausgeschlossen: `./rpms`, `./.git`, `./build`, `./deb_build_tmp`.
5. **`VERSION_DATE=$(date +%Y-%m-%d)`** wird exportiert.
6. **Aufruf des Python-Builder** aus `${WORKSPACE}/rpmbuild`:
```
python3 make_rpm_ubuntu26.py -c LTS \
--project_name "${PROJECT}" \
--version "${LTS_VERSION}" \
--output_dir "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" \
--cmake_build_flags "-DUSE_IPO=ON -DUSE_UNITY_BUILD=ON -DGUEZ_MODE=${GUEZ_MODE} \
-DBUILD_WLS=ON -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/postgresql/" \
--build_number "${BUILD_NUMBER:-1}"
```
7. **`ls -lhR`** des Output-Verzeichnisses zur Bestätigung.
### 1.3 Stärken
- Strikte, frühzeitige Validierung aller Pflicht-Variablen.
- `pipefail` macht die `tar`-Pipe fehlersicher.
- Output ist pro `Projekt/OS-Version` isoliert → parallele OS-Builds kollidieren nicht.
- Saubere Quell-Kopie ohne `.git`/`build`/`rpms`.
- `python3` statt `python` (robuster als im Original).
### 1.4 Befunde / Probleme
| # | Schwere | Befund |
|---|---|---|
| S1 | **Hoch** | **`PROJECT_BASE_DIR` wird nie verwendet.** Die `tar`-Staging-Kopie nach `PROJECT_BASE_DIR` ist toter Code: `make_rpm_ubuntu26.py` berechnet `source_dir` selbst als *Elternverzeichnis von `rpmbuild/`* (also `WORKSPACE`), nicht `PROJECT_BASE_DIR`. Die teure Kopie wird verworfen. |
| S2 | Mittel | **`VERSION_DATE`** wird exportiert, aber nirgends (auch nicht im Python-Skript) gelesen. |
| S3 | Mittel | **`BUILD_TAG`** wird im Header als „Required" dokumentiert, aber weder validiert noch an den Builder übergeben. |
| S4 | Mittel | **`HOME=/home/builder`** + Kommentar „running as root" widerspricht dem Dockerfile, das `USER ctc` mit Home `/shd/CTC/TOOLS` setzt. Inkonsistenz zwischen Skript und Image. |
| S5 | Niedrig | `rm -rf "${PROJECT_BASE_DIR}"` ist durch die `:?`-Prüfung abgesichert, aber ein `rm -rf` auf einer Umgebungsvariable bleibt ein Risiko, falls die Validierung je entfernt wird. |
---
## 2. `make_rpm_ubuntu26.py`
### 2.1 Zweck
Erzeugt ein DEB-Paket für Ubuntu 26.04, indem es eine `debian/`-Verzeichnisstruktur
(`control`, `changelog`, `rules`, `source/format`, `compat`) generiert und `debuild` ausführt.
Migriert von `make_rpm.py` (RPM).
### 2.2 Struktur & Funktionen
| Funktion | Zweck |
|---|---|
| `verbose()` / `debug()` / `info()` / `warning()` / `error()` / `die()` | Logging, gesteuert durch `EMERGE_VERBOSE` |
| `system(cmdstring, file)` | Shell-Ausführung via `subprocess.Popen` (stdout-Capture) |
| `get_os_name()` | Liest `PRETTY_NAME` aus `/etc/os-release` |
| `remove_directory(dest_dir)` | `shutil.rmtree` |
| `copy_src_dir_to_dest_dir(...)` | Rekursive Quell-Kopie mit optionalen Permissions |
| `create_debian_control(...)` | Generiert `debian/control` |
| `create_debian_changelog(...)` | Generiert `debian/changelog` |
| `create_debian_rules(...)` | Generiert `debian/rules` (chmod +x) |
| `build_deb(...)` | Orchestrierung: Temp-Dir, Quell-Kopie, `debian/`, `debuild`, Move, Cleanup |
| `main()` | `argparse`, bestimmt `source_dir`, ruft `build_deb` auf |
### 2.3 Ablauf `build_deb()`
1. `output_dir` anlegen.
2. `deb_build_tmp` unter `source_dir` anlegen (vorher entfernen).
3. Quelle nach `deb_build_tmp/legatus-<projekt>-<version>` kopieren.
4. `debian/` mit `control`, `changelog`, `rules`, `source/format` (`3.0 (quilt)`), `compat` (`13`) befüllen.
5. `os.chdir(pkg_dir)`, `DEB_BUILD_OPTIONS` setzen, `debuild -us -uc -b` ausführen.
6. Erzeugte Artefakte (`.deb`, `.dsc`, `.changes`, `.buildinfo`) nach `output_dir` verschieben.
7. Cleanup: `chdir` zurück, `deb_build_tmp` entfernen.
### 2.4 Stärken
- Klare, modulare Struktur mit getrennten `create_debian_*`-Helfern.
- Konsistentes Logging mit `die()` bei Fehlern.
- `debuild -us -uc -b` (unsigned, binary-only) — passend für CI ohne Signatur.
- Sauberes Cleanup des Temp-Build-Verzeichnisses.
- `subprocess.run` mit Return-Code-Check für `debuild`.
### 2.5 Befunde / Probleme
#### Kritisch (Build würde fehlschlagen / falsches Ergebnis)
| # | Schwere | Befund |
|---|---|---|
| P1 | **Kritisch** | **`debuild`/`debhelper`/`dpkg-dev` sind im Dockerfile nicht installiert.** Das Image installiert `rpm`, aber kein `debhelper`, `debuild` oder `dpkg-dev`. Der Aufruf `debuild -us -uc -b` schlägt mit „command not found" fehl. |
| P2 | **Kritisch** | **CMake-Flags werden nie in den Build übergeben.** `--cmake_build_flags` landet ausschließlich im `Description`-Text von `debian/control`. Die generierte `debian/rules` hardcodet nur `-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr`. Damit greifen `USE_IPO`, `USE_UNITY_BUILD`, `GUEZ_MODE`, `BUILD_WLS`, `PostgreSQL_TYPE_INCLUDE_DIR` **nicht** — das Paket wird mit falschen Build-Optionen gebaut. |
| P3 | **Kritisch** | **Kein `CMakeLists.txt` im Quell-Root.** `source_dir` ist der Repo-Root (Eltern von `rpmbuild/`), dort liegt aber kein `CMakeLists.txt` (das echte Projekt-Root ist `qt-migration-legatus/qt6-after/qt6-migrated-legatus/`). `dh --buildsystem=cmake` würde im konfigurierten Build-Verzeichnis scheitern. |
| P4 | **Kritisch** | **`DEB_BUILD_OPTIONS="parallel=$(nproc)"`** — es findet keine Shell-Expansion statt; debhelper erwartet eine Zahl (`parallel=N`). Der wörtliche String `$(nproc)` ist ungültig und führt zu einem Fehler bzw. wird ignoriert. |
#### Mittel
| # | Schwere | Befund |
|---|---|---|
| P5 | Mittel | **`--config` wird verlangt, aber weder validiert noch genutzt.** Es wird keine Config-Datei gelesen; der Wert wird nur geloggt. Im Original (`make_rpm.py`) hatte `-c` eine Bedeutung. |
| P6 | Mittel | **Changelog-Timestamp inkonsistent:** `datetime.now()` (lokale Zeit) mit hartkodiertem `+0000`. Ist die Container-TZ nicht UTC, ist der Zeitstempel falsch. |
| P7 | Mittel | **`Build-Depends` in `control` passt nicht zum Image:** `qt6-base-dev`/`libgeographic-dev` werden gelistet, das Image nutzt aber Qt aus `/opt/Qt` (aqtinstall) und `libgeographiclib-dev`. Misstreibend (bei `-b`-Build nicht für Dependency-Resolution relevant, aber irreführend). |
| P8 | Mittel | **`project_name` wird nicht validiert** (gegen `qatar|ahtc|guez`), ebenso nicht das `version`-Format. |
| P9 | Mittel | **Vollständige Repo-Kopie** (inkl. `external/` mit ArcGIS-SDK & RTI Connext, `jenkins/`, `rpmbuild/`) nach `deb_build_tmp` — sehr langsam und speicherintensiv. |
#### Niedrig / Code-Qualität
| # | Schwere | Befund |
|---|---|---|
| P10 | Niedrig | **Unbenutzte Imports:** `configparser`, `getpass`, `re`, `pathlib.Path`. |
| P11 | Niedrig | **Unbenutzte Funktionen:** `system()`, `get_os_name()`, `warning()`. |
| P12 | Niedrig | **„emerge"-Namensreste** aus dem RPM-Skript: `EMERGE_VERBOSE`, Fehlermeldung „emerge fatal error". |
| P13 | Niedrig | **Dateiname `make_rpm_ubuntu26.py`** baut ein DEB, kein RPM — irreführend. |
| P14 | Niedrig | **`debian/compat`-Datei ist deprecated** (debhelper ≥ 12); `13` ist überflüssig. |
| P15 | Niedrig | **`control`-`Description`-Fortsetzungszeilen** mit 3 statt 1 Leerzeichen eingerückt; fehlt `Standards-Version`/`Homepage` (Lintian-Warnungen). |
| P16 | Niedrig | **`copy_src_dir_to_dest_dir`:** `os.path.isfile(tmpdir)` prüft einen *Verzeichnis*-Pfad (Restcode); die `perm`-Logik prüft `os.path.isdir(f)` auf eine gerade kopierte *Datei* (immer `False`). |
| P17 | Niedrig | **`os.makedirs(tmpdir)`** ohne `exist_ok` nach `exists`-Check (Race, gering). |
| P18 | Niedrig | **`override_dh_auto_install: dh_auto_install`** ist ein no-op-Override (ohne Effekt). |
| P19 | Niedrig | **`.dsc`/`.changes`** werden zum Move geprüft, entstehen bei `-b` aber nicht (harmlos). |
| P20 | Niedrig | **`os.chdir(pkg_dir)`** ändert den Prozess-CWD; bei `debuild`-Fehler wird er nicht wiederhergestellt (Prozess beendet sich aber ohnehin). |
---
## 3. Zusammenspiel der beiden Skripte
```
Jenkins/Container
└─ jenkins_builder_ubuntu26.sh
├─ validiert ENV (PROJECT, OS_VERSION, LTS_VERSION, GUEZ_MODE, WORKSPACE, PROJECT_BASE_DIR)
├─ tar-Staging → PROJECT_BASE_DIR (⚠ toter Code, s. S1)
└─ python3 make_rpm_ubuntu26.py
├─ source_dir = Eltern(rpmbuild/) = WORKSPACE (⚠ ≠ PROJECT_BASE_DIR)
├─ kopiert WORKSPACE → deb_build_tmp/legatus-<proj>-<ver>
├─ generiert debian/{control,changelog,rules,source/format,compat}
├─ debuild -us -uc -b (⚠ debuild fehlt im Image, s. P1)
└─ .deb → WORKSPACE/rpms/<proj>/<os>/
```
**Kernproblem des Zusammenspiels:** Das Shell-Skript investiert in eine Staging-Kopie nach
`PROJECT_BASE_DIR`, die der Python-Builder ignoriert (P3/S1). Gleichzeitig erreicht der
Python-Builder die CMake-Flags nicht (P2) und baut aus einem Root ohne `CMakeLists.txt` (P3).
Die Pipeline ist daher in ihrem aktuellen Zustand **nicht funktionsfähig**.
---
## 4. Zusammenfassung der Befunde (nach Schwere)
| Schwere | Anzahl | IDs |
|---|---|---|
| 🔴 Kritisch | 4 | P1, P2, P3, P4 |
| 🟠 Hoch | 1 | S1 |
| 🟡 Mittel | 7 | S2, S3, S4, P5, P6, P7, P8, P9 |
| ⚪ Niedrig | 11 | P10–P20 |
> Hinweis: S2–S4 sind im Shell-Skript als „Mittel" eingestuft; P5–P9 im Python-Skript.
---
## 5. Empfehlungen (Priorität)
1. **P1:** `debhelper`, `dpkg-dev` (bietet `debuild`) in das Dockerfile aufnehmen
(`apt-get install -y debhelper dpkg-dev`).
2. **P2:** `--cmake_build_flags` in die generierte `debian/rules` einbetten, z. B.
```make
override_dh_auto_configure:
dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr <FLAGS>
```
(Flags sicher als Make-Variablen/Zeile injizieren).
3. **P3:** `source_dir` auf das echte CMake-Projekt-Root zeigen lassen (Parameter
`--source_dir` oder `PROJECT_BASE_DIR` tatsächlich nutzen) — und damit S1 auflösen,
indem das Shell-Skript `PROJECT_BASE_DIR` an den Builder übergibt.
4. **P4:** `DEB_BUILD_OPTIONS="parallel=$(nproc)"` durch eine echte Zahl ersetzen,
z. B. `env["DEB_BUILD_OPTIONS"] = f"parallel={os.cpu_count()}"`.
5. **S1/S2/S3:** Toten Code entfernen (`PROJECT_BASE_DIR`-Staging, `VERSION_DATE`,
`BUILD_TAG`-Doku) oder die Variablen tatsächlich nutzen.
6. **P5:** `--config` validieren (z. B. `choices=["LTS"]`) oder entfernen.
7. **P6:** Changelog-Timestamp mit `datetime.now(timezone.utc)` erzeugen.
8. **P7:** `Build-Depends` an das tatsächliche Image anpassen (Qt aus `/opt/Qt`,
`libgeographiclib-dev`).
9. **P9:** Quell-Kopie auf das eigentliche Projekt-Root beschränken (statt ganzes Repo
inkl. `external/`).
10. **P10–P20:** Code-Qualität aufräumen (unbenutzte Imports/Funktionen, „emerge"-Reste,
Dateiname, `compat`-Datei, `control`-Formatierung, `copy_src_dir_to_dest_dir`-Logik).
---
*Erstellt am 2026-10-08. Analyse basiert auf `jenkins-ci-rme/jenkins_builder_ubuntu26.sh`,
`rpmbuild/make_rpm_ubuntu26.py` sowie Kontext aus `jenkins-ci-rme/Jenkinsfile`,
`jenkins-ci-rme/Dockerfile-ubuntu26-qt6.dockerfile`, `jenkins-ci-rme/jenkins_builder.sh`
(Original) und der Repository-Struktur.*