# 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--` 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-- ├─ generiert debian/{control,changelog,rules,source/format,compat} ├─ debuild -us -uc -b (⚠ debuild fehlt im Image, s. P1) └─ .deb → WORKSPACE/rpms/// ``` **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 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.*