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

13 KiB
Raw Blame History

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
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.
    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.