Files
qt6-migration-pipeline/ANALYSE_UBUNTU26_BUILD_SCRIPTS.md
T
torsten 0d48591be4 Adds rpm builder readme
Entire-Checkpoint: 01M4DXA2QYJCTNSCZXZM63D2MF
2026-10-08 14:05:09 +00:00

214 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.*