Adds rpm builder readme
Entire-Checkpoint: 01M4DXA2QYJCTNSCZXZM63D2MF
This commit is contained in:
1 file changed
+213
@@ -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.*
|
||||
Reference in new issue
Block a user