diff --git a/ANALYSE_UBUNTU26_BUILD_SCRIPTS.md b/ANALYSE_UBUNTU26_BUILD_SCRIPTS.md new file mode 100644 index 000000000..ffa0c4a9f --- /dev/null +++ b/ANALYSE_UBUNTU26_BUILD_SCRIPTS.md @@ -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--` 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.*