diff --git a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/Jenkinsfile b/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/Jenkinsfile deleted file mode 100644 index fb6ae9bb1..000000000 --- a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/Jenkinsfile +++ /dev/null @@ -1,153 +0,0 @@ -// Release pipeline for the Qt6-migrated legatus validation-scope branch -// (story/release-validation-scope): TetraIF, Z, Lts/Common (+ -// Lts/Proxies/TrainingAreaBase) -> 5 release DEB packages. -// -// Workspace layout (checked out by Jenkins, outer pipeline repo): -// / -// external/ -// qt-migration-legatus/qt6-after/qt6-migrated-legatus/ <- LEGATUS_ROOT -// Dockerfile (prebuilt build image recipe) -// new_docker_build.sh (local build driver) -// rpmbuild/make_rpm_ubuntu26.py (in-tree packaging) -// jenkins-ci-rme/ (this pipeline) -// -// The build container image is the prebuilt image built from the in-tree -// Dockerfile; it is built on the agent when not present (RebuildImage -// forces a fresh build). - -def project = 'guez' -def legatusRoot = 'qt-migration-legatus/qt6-after/qt6-migrated-legatus' -def imageName = 'legatus-qt6:1.0' - -properties([ - disableConcurrentBuilds(), - parameters([ - string(name: 'OsVersions', defaultValue: '26.04', description: 'Comma-separated Ubuntu base versions, all built in parallel'), - string(name: 'LtsVersion', defaultValue: '1.0', description: 'LTS version (major.minor) passed to make_rpm_ubuntu26.py --version'), - booleanParam(name: 'ClearWorkspace', defaultValue: false, description: 'Clear entire workspace on all nodes used for build'), - booleanParam(name: 'PublishArtifactRepo', defaultValue: true, description: 'Upload produced DEBs to the internal artifact repository'), - booleanParam(name: 'RebuildImage', defaultValue: false, description: 'Rebuild the prebuilt build image from the in-tree Dockerfile (default: reuse when present)'), - booleanParam(name: 'RunCoverage', defaultValue: true, description: 'Build the release scope with -O0 --coverage, run ctest, collect the lcov report and archive it') - ]) -]) - -env.GIT_TERMINAL_PROMPT = '0' -env.LTS_VERSION = "${params.LtsVersion}" -env.ARTIFACTREPO = 'https://internal-repo.sl.defence-elec.de' - -// OS versions this build covers; every build is isolated under -// rpms/${project}/${osVersion} so concurrent OS builds never collide. -def osVersions = params.OsVersions.split(',').collect { it.trim() }.findAll { it } - -def builds = [:] -osVersions.each { osVersion -> - def rpmsDir = "rpms/${project}/${osVersion}" - - builds["${project} (${osVersion})"] = { - stage("Prepare ${project} (${osVersion})") { - sh "rm -rf ${rpmsDir}" - sh "mkdir -p ${rpmsDir}" - } - - stage("Prepare build image ${project} (${osVersion})") { - if (params.RebuildImage) { - sh "docker rmi ${imageName} || true" - } - // The in-tree driver owns the Dockerfile build args (APT_PACKAGES, - // QT_VERSION, ...) - single source of truth. - sh """ - if docker image inspect ${imageName} >/dev/null 2>&1; then - echo "Reusing existing prebuilt image ${imageName}" - else - echo "Building prebuilt image ${imageName} from the in-tree Dockerfile..." - cd ${legatusRoot} && bash ./new_docker_build.sh --build-prebuilt-image --docker-image ${imageName} - fi - """ - } - - stage("Build DEB ${project} (${osVersion})") { - def buildContainer = docker.image("${imageName}") - def guezMode = (project == 'guez') ? 'ON' : 'OFF' - - def dockerOpts = "--init --shm-size=2g" + - " -v ${WORKSPACE}:/workspace" + - " -e WORKSPACE=/workspace" + - " -e PROJECT_BASE_DIR=/workspace" + - " -e PROJECT=${project}" + - " -e OS_VERSION=${osVersion}" + - " -e LTS_VERSION=${LTS_VERSION}" + - " -e GUEZ_MODE=${guezMode}" + - " -e BUILD_NUMBER=${env.BUILD_NUMBER}" + - " -e BUILD_TAG=${env.BUILD_TAG}" - - buildContainer.inside(dockerOpts) { - sh "bash /workspace/${legatusRoot}/jenkins-ci-rme/jenkins_builder_ubuntu26.sh" - } - } - - stage("Coverage ${project} (${osVersion})") { - if (!params.RunCoverage) { - echo "Coverage skipped for ${project} (OS ${osVersion}, RunCoverage=false)" - return - } - // The driver (run on the agent, same pattern as the image-build - // stage) builds the scope with -O0 --coverage, runs ctest and - // collects the lcov report into the workspace mount. - sh "cd ${legatusRoot} && bash ./new_docker_build.sh --docker-image ${imageName} --run-coverage --coverage-output-dir ${WORKSPACE}/coverage/${project}/${osVersion}" - archiveArtifacts artifacts: "coverage/${project}/${osVersion}/**", allowEmptyArchive: true - } - - stage("Publish ${project} (${osVersion})") { - if (params.PublishArtifactRepo) { - withCredentials([usernamePassword(credentialsId: 'internal-repo-uploader', - usernameVariable: 'CURL_USER', - passwordVariable: 'CURL_PASS')]) { - sh """ - export CURL_CRED="\${CURL_USER}:\${CURL_PASS}" - export PROJECT='${project}' - export OS_VERSION='${osVersion}' - export LTS_VERSION='${LTS_VERSION}' - export BUILD_NUMBER='${env.BUILD_NUMBER}' - export ARTIFACTREPO='${env.ARTIFACTREPO}' - export ARTIFACTFOLDER='${project}' - bash ${legatusRoot}/jenkins-ci-rme/jenkins_publisher_ubuntu26.sh - """ - } - - def tdsUrl = readFile("url-${project}-${osVersion}.txt").trim() - def tdsVersion = readFile("tdsversion-${project}-${osVersion}.txt").trim() - def link = """${project} ${tdsVersion} (OS ${osVersion})""" - currentBuild.description = currentBuild.description ? "${currentBuild.description}
${link}" : link - } else { - echo "Artifact-repo publish skipped for ${project} (OS ${osVersion}, PublishArtifactRepo=false)" - } - } - } -} - -try { - stage("Initialization") { - if (params.ClearWorkspace) { - cleanWs() - checkout([ - $class: 'GitSCM', - branches: scm.branches, - doGenerateSubmoduleConfigurations: false, - extensions: [[$class: 'SubmoduleOption', disableSubmodules: false, parentCredentials: true, recursiveSubmodules: true, reference: '', trackingSubmodules: false]], - userRemoteConfigs: scm.userRemoteConfigs - ]) - } - echo "Legatus Qt6 release build initialized — branch '${env.BRANCH_NAME}', project: ${project}, LTS ${env.LTS_VERSION}, OS version(s): ${osVersions.join(', ')}" - } - - parallel builds - - stage("Finalization") { - echo "Legatus Qt6 release build completed — project: ${project} (LTS ${env.LTS_VERSION}), OS version(s): ${osVersions.join(', ')}" - } - - currentBuild.result = 'SUCCESS' -} catch (e) { - currentBuild.result = 'FAILURE' - throw e -} diff --git a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/README.md b/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/README.md deleted file mode 100644 index 01429f39a..000000000 --- a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# jenkins-ci-rme — release pipeline for the Qt6 validation-scope branch - -In-tree copy of the Jenkins CI flow, adapted so the release pipeline depends -only on files inside this source tree: - -| File | Purpose | -|---|---| -| `Jenkinsfile` | Jenkins pipeline: prepare the prebuilt image (in-tree `Dockerfile`), run the builder inside the container, publish the DEBs to the artifact repo | -| `jenkins_builder_ubuntu26.sh` | Runs **inside** the build container: stages the workspace, runs the in-tree `rpmbuild/make_rpm_ubuntu26.py`, copies the DEBs to the packages-out mount | -| `jenkins_publisher_ubuntu26.sh` | Runs on the Jenkins agent: uploads the DEBs from `${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/` to the internal artifact repository | -| `release-16-10-2026.sh` | Local driver: the same flow without Jenkins, through the in-tree `new_docker_build.sh` | - -## Not included (superseded) - -- `jenkins_builder.sh` / `jenkins_publisher.sh` — openSUSE/RPM flow, not used - by this branch (DEB/Ubuntu 26.04 only) -- `Dockerfile-15.1` / `Dockerfile-ubuntu26.04` / `Dockerfile-ubuntu26-qt6` — - old image recipes; the prebuilt build image is built from the in-tree - `Dockerfile` (one level up) -- `jenkins_notifier.sh` — Bitbucket build-status notification, not part of - this project - -## Adaptations vs. the outer-repo copy - -- Packaging uses the **in-tree** `rpmbuild/make_rpm_ubuntu26.py` - (was `${WORKSPACE}/rpmbuild` from the outer repo) -- The prebuilt build image is built from the **in-tree** `Dockerfile` via - `new_docker_build.sh --build-prebuilt-image` (was a pre-pulled harbor - image) — build args stay in `new_docker_build.sh` (single source of truth) -- `MIGRATE_PIPELINE_ROOT` is no longer needed: `new_docker_build.sh` - derives it from its own location -- DEB output path: `${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/` (Jenkins - convention); the packages-out copy is skipped when that directory is the - make_rpm output dir (same device:inode guard as in `new_docker_build.sh`) -- Publisher uploads `${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/` directly — - `make_rpm_ubuntu26.py` writes the DEBs there without a TDS subfolder -- The post-publish Cleanup stage was dropped: the DEBs are kept under - `${WORKSPACE}/rpms/...` (the documented output location) - -## Local run - -```bash -cd qt6-migrated-legatus -bash ./jenkins-ci-rme/release-16-10-2026.sh -# DEBs: /rpms/guez/26.04/ -``` - -## Jenkins setup - -The job SCM must be the outer pipeline repository (the Jenkinsfile lives in -the `qt-migration-legatus` submodule; point the job's script path at -`qt-migration-legatus/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/Jenkinsfile`). -Required Jenkins credential: `internal-repo-uploader` (username/password for -the artifact repository). diff --git a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_builder_ubuntu26.sh b/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_builder_ubuntu26.sh deleted file mode 100755 index 55567e50e..000000000 --- a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_builder_ubuntu26.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash -# -# Build the LTS DEB packages for the Qt6-migrated legatus release -# (validation scope: TetraIF, Z, Lts/Common + Lts/Proxies/TrainingAreaBase) -# for Ubuntu 26.04. -# -# Runs inside the prebuilt build container (built from the in-tree -# Dockerfile) with the pipeline workspace mounted at /workspace. -# Packaging is done by the IN-TREE rpmbuild copy -# (qt-migration-legatus/qt6-after/qt6-migrated-legatus/rpmbuild/), so the -# release flow needs no files outside the source tree. -# -# Required environment (set by the Jenkinsfile or `docker run -e ...`): -# PROJECT LTS flavor: guez -# OS_VERSION Ubuntu version, e.g. 26.04 -# LTS_VERSION Major.minor LTS version, e.g. 1.0 -# GUEZ_MODE ON | OFF — cmake -DGUEZ_MODE -# WORKSPACE Container workspace path (/workspace) -# PROJECT_BASE_DIR Staging root inside the container (/workspace) -# BUILD_NUMBER Build number (used as release in the DEB version) -# BUILD_TAG Build tag -# -# IMPORTANT: Source files under git management must NEVER be deleted. -# Only the temporary staging directory (deb_stage) is removed. - -set -eo pipefail - -: "${PROJECT:?PROJECT must be set}" -: "${OS_VERSION:?OS_VERSION must be set}" -: "${LTS_VERSION:?LTS_VERSION must be set}" -: "${GUEZ_MODE:?GUEZ_MODE must be set}" -: "${WORKSPACE:?WORKSPACE must be set}" -: "${PROJECT_BASE_DIR:?PROJECT_BASE_DIR must be set}" - -echo "Building LTS ${LTS_VERSION}-${BUILD_NUMBER:-?} DEB for project '${PROJECT}' (Ubuntu ${OS_VERSION})." -echo "PROJECT_BASE_DIR=${PROJECT_BASE_DIR}" - -# Stage workspace as a clean copy under PROJECT_BASE_DIR/deb_stage. -STAGE_DIR="${PROJECT_BASE_DIR}/deb_stage" -rm -rf "${STAGE_DIR}" -mkdir -p "${STAGE_DIR}" -tar --exclude='./rpms' --exclude='./.git' --exclude='./build' \ - --exclude='./deb_build_tmp' --exclude='./deb_stage' --exclude='./packages-out' \ - -cf - -C "${WORKSPACE}" . | tar -xf - -C "${STAGE_DIR}" - -export VERSION_DATE -VERSION_DATE=$(date +%Y-%m-%d) - -# Real CMake project root inside the staged tree (the in-tree source) -SOURCE_DIR="${STAGE_DIR}/qt-migration-legatus/qt6-after/qt6-migrated-legatus" -if [ ! -f "${SOURCE_DIR}/CMakeLists.txt" ] || [ ! -f "${SOURCE_DIR}/rpmbuild/make_rpm_ubuntu26.py" ]; then - echo "ERROR: staged source incomplete under ${SOURCE_DIR} (CMakeLists.txt or rpmbuild/make_rpm_ubuntu26.py missing)" >&2 - exit 1 -fi - -# Output is isolated per OS version so parallel OS builds of the same -# project never collide -cd "${SOURCE_DIR}/rpmbuild" -python3 make_rpm_ubuntu26.py -c LTS \ - --project_name "${PROJECT}" \ - --version "${LTS_VERSION}" \ - --output_dir "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" \ - --source_dir "${SOURCE_DIR}" \ - --cmake_build_flags "-DUSE_IPO=ON -DUSE_UNITY_BUILD=ON -DGUEZ_MODE=${GUEZ_MODE} -DBUILD_WLS=ON -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/postgresql/ -DRELEASE_BUILD=ON" \ - --build_number "${BUILD_NUMBER:-1}" \ - --release_scope - -PACKAGE_OUT_DIR=/workspace/packages-out -mkdir -p "${PACKAGE_OUT_DIR}" -shopt -s nullglob -for deb in "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/"*.deb; do - base="$(basename "${deb}")" - if [[ -e "${PACKAGE_OUT_DIR}/${base}" ]] && - [[ "$(stat -c '%d:%i' "${deb}")" == "$(stat -c '%d:%i' "${PACKAGE_OUT_DIR}/${base}")" ]]; then - continue - fi - cp -f "${deb}" "${PACKAGE_OUT_DIR}/" -done -shopt -u nullglob - -echo "DEB packages produced for '${PROJECT}' (Ubuntu ${OS_VERSION}):" -ls -lhR "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" -echo "DEB packages copied to ${PACKAGE_OUT_DIR}:" -ls -lh "${PACKAGE_OUT_DIR}/" diff --git a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_publisher_ubuntu26.sh b/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_publisher_ubuntu26.sh deleted file mode 100755 index 494948ed6..000000000 --- a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/jenkins_publisher_ubuntu26.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -# -# Upload the produced DEBs to the internal artifact repository and emit two -# helper files for the Jenkinsfile to consume (named per project + OS -# version): -# ${WORKSPACE}/url-${PROJECT}-${OS_VERSION}.txt — browseable URL of the uploaded folder -# ${WORKSPACE}/tdsversion-${PROJECT}-${OS_VERSION}.txt — full version string (LTS-build) -# -# Adapted for the in-tree flow: make_rpm_ubuntu26.py writes the DEBs -# directly under ${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/ (no TDS -# subfolder), so that directory is uploaded as-is. -# -# Required environment (set by the Jenkinsfile / withCredentials): -# PROJECT LTS flavor: guez -# OS_VERSION Ubuntu base version, e.g. 26.04 -# LTS_VERSION Major.minor LTS version, e.g. 1.0 -# BUILD_NUMBER Build number (release component of the artifact name) -# WORKSPACE Jenkins workspace path -# ARTIFACTREPO Base URL of the internal repo (no trailing slash) -# ARTIFACTFOLDER Subfolder under cts-rpms/ (project name, e.g. guez) -# CURL_CRED user:password for the upload (Jenkins credential) -# - -set -eo pipefail - -: "${PROJECT:?PROJECT must be set}" -: "${OS_VERSION:?OS_VERSION must be set}" -: "${LTS_VERSION:?LTS_VERSION must be set}" -: "${BUILD_NUMBER:?BUILD_NUMBER must be set}" -: "${WORKSPACE:?WORKSPACE must be set}" -: "${ARTIFACTREPO:?ARTIFACTREPO must be set}" -: "${ARTIFACTFOLDER:?ARTIFACTFOLDER must be set}" -: "${CURL_CRED:?CURL_CRED must be set}" - -tds_folder_name="${PROJECT}-TDS-${LTS_VERSION}-${BUILD_NUMBER}" -tds_folder_path="${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}" -tds_artifact_store="${ARTIFACTREPO}/repository/cts-rpms/${ARTIFACTFOLDER}/${OS_VERSION}/${tds_folder_name}" - -if [ ! -d "${tds_folder_path}" ]; then - echo "ERROR: expected package folder not found: ${tds_folder_path}" >&2 - exit 1 -fi - -shopt -s nullglob -uploaded=0 -for file in "${tds_folder_path}"/*; do - [ -f "${file}" ] || continue - # Upload .deb, .dsc, .changes, .buildinfo files - if [[ "${file}" == *.deb ]] || [[ "${file}" == *.dsc ]] || [[ "${file}" == *.changes ]] || [[ "${file}" == *.buildinfo ]]; then - name=$(basename "${file}") - echo "Uploading: ${name}" - curl --fail --silent --show-error \ - --user "${CURL_CRED}" \ - --upload-file "${file}" \ - "${tds_artifact_store}/${name}" - uploaded=$((uploaded + 1)) - fi -done -shopt -u nullglob - -if [ "${uploaded}" -eq 0 ]; then - echo "ERROR: no files uploaded from ${tds_folder_path}" >&2 - exit 1 -fi - -echo "Uploaded ${uploaded} file(s) to ${tds_artifact_store}/" - -# Per-(project, OS) filenames so concurrent publish stages don't clobber each -# other's helper files; the Jenkinsfile reads back the matching names. -echo "${ARTIFACTREPO}/service/rest/repository/browse/cts-rpms/${ARTIFACTFOLDER}/${OS_VERSION}/${tds_folder_name}/" > "${WORKSPACE}/url-${PROJECT}-${OS_VERSION}.txt" -echo "${LTS_VERSION}-${BUILD_NUMBER}" > "${WORKSPACE}/tdsversion-${PROJECT}-${OS_VERSION}.txt" diff --git a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/release-16-10-2026.sh b/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/release-16-10-2026.sh deleted file mode 100755 index facc6e82b..000000000 --- a/qt6-after/qt6-migrated-legatus/jenkins-ci-rme/release-16-10-2026.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env bash -# -# Local release pipeline for the Qt6-migrated legatus validation scope -# (TetraIF, Z, Lts/Common + Lts/Proxies/TrainingAreaBase). -# -# Runs the in-tree new_docker_build.sh: -# - builds the prebuilt Docker image from the in-tree Dockerfile when the -# image is not present yet -# - builds the release scope, runs ctest and produces the release DEB -# packages with the in-tree rpmbuild script -# - collects the lcov code-coverage report (--run-coverage; set -# DRYRUN_COVERAGE=OFF to skip) -# -# The DEB packages land in ${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/ -# (Jenkins-style layout; locally WORKSPACE is the pipeline root). -# -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LEGATUS_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" -PIPELINE_ROOT="$(cd "${LEGATUS_ROOT}/../../.." && pwd)" - -# Release build configuration (Jenkins-style variables) -export WORKSPACE="${PIPELINE_ROOT}" -export PROJECT="${PROJECT:-guez}" -export OS_VERSION="${OS_VERSION:-26.04}" -export LTS_VERSION="${LTS_VERSION:-1.0}" -export GUEZ_MODE="${GUEZ_MODE:-ON}" -export BUILD_NUMBER="${BUILD_NUMBER:-$(date +%Y%m%d-%H%M%S)}" -export BUILD_TAG="${BUILD_TAG:-release-qt6-first}" - -DOCKER_IMAGE="${DOCKER_IMAGE:-legatus-qt6:1.0}" - -log_info() { - printf 'INFO: %s\n' "$*" -} - -log_info "=== Qt6 Release Pipeline ===" -log_info "Pipeline root: ${PIPELINE_ROOT}" -log_info "Legatus root: ${LEGATUS_ROOT}" -log_info "Docker image: ${DOCKER_IMAGE}" -log_info "Build number: ${BUILD_NUMBER}" -log_info "Build tag: ${BUILD_TAG}" -log_info "Package output: ${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" - -cd "${LEGATUS_ROOT}" - -# Build the prebuilt image from the in-tree Dockerfile when not present yet -# (--build-prebuilt-image builds the image and exits) -if ! docker image inspect "${DOCKER_IMAGE}" >/dev/null 2>&1; then - log_info "Prebuilt image not found - building it from the in-tree Dockerfile..." - bash ./new_docker_build.sh --build-prebuilt-image --docker-image "${DOCKER_IMAGE}" -fi - -# Release scope build + ctest + DEB production (in-tree rpmbuild) -bash ./new_docker_build.sh \ - --docker-image "${DOCKER_IMAGE}" \ - --run-jenkins-builder \ - --package-output-dir "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" \ - --project "${PROJECT}" \ - --lts-version "${LTS_VERSION}" \ - --build-number "${BUILD_NUMBER}" \ - --build-tag "${BUILD_TAG}" - -# Code coverage (lcov) - mirrors the Jenkins Coverage stage. Set -# DRYRUN_COVERAGE=OFF for a fast local DEB-only run. -DRYRUN_COVERAGE="${DRYRUN_COVERAGE:-ON}" -if [[ "${DRYRUN_COVERAGE}" == "ON" ]]; then - bash ./new_docker_build.sh \ - --docker-image "${DOCKER_IMAGE}" \ - --run-coverage \ - --coverage-output-dir "${WORKSPACE}/coverage/${PROJECT}/${OS_VERSION}" -else - log_info "Coverage skipped (DRYRUN_COVERAGE=OFF)" -fi - -log_info "=== Release Pipeline Complete ===" diff --git a/qt6-after/qt6-migrated-legatus/new_docker_build.sh b/qt6-after/qt6-migrated-legatus/new_docker_build.sh deleted file mode 100755 index 78998169a..000000000 --- a/qt6-after/qt6-migrated-legatus/new_docker_build.sh +++ /dev/null @@ -1,647 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# ----------------------------------------------------------------------------- -# Build helper for the release validation-scope branch of qt-migrated-legatus -# -# Builds only the release scope (TetraIF, Z/src, Lts/Common + -# Lts/Proxies/TrainingAreaBase) inside the prebuilt Docker image and -# optionally runs the Jenkins builder to produce the release DEB packages. -# -# - Resolves MIGRATE_PIPELINE_ROOT (exported variable, .envrc, or derived -# from the script location) for the workspace and external mounts -# - Uses a prebuilt Docker image with all build dependencies installed -# (build it from ./Dockerfile via --build-prebuilt-image) -# - Optional deletion of the prebuilt Docker image via --delete-prebuilt-image -# - Optional DEB package production via the in-tree rpmbuild/ -# make_rpm_ubuntu26.py (self-contained - no outer-repo dependencies) -# - Uses a temporary container-side script for robust execution -# ----------------------------------------------------------------------------- - -usage() { - cat <<'EOF' -Usage: ./new_docker_build.sh [options] - -Builds the release validation scope inside the prebuilt Docker image: - RELEASE_BUILD=ON (fixed) - TetraIF, Z, Lts/Common (+ TrainingAreaBase) - ctest runs for the release scope test executables (Lts/Common + Z) - -Options: - --docker-image IMAGE Docker image name to use/build/delete - (default: legatus-qt6:1.0) - --build-prebuilt-image Build the prebuilt Docker image (from ./Dockerfile) - and exit. To run the build with it, run the script - again with --docker-image - --delete-prebuilt-image Delete the configured Docker image and exit - -Package production options (RPM/DEB): - --run-jenkins-builder Build the release DEB packages inside the container - using the in-tree rpmbuild/make_rpm_ubuntu26.py - --package-output-dir DIR Directory to mount for package output (default: ./packages-out) - --lts-version VERSION LTS version for package (default: 1.0) - --project NAME Project name for package (default: guez) - --build-number NUM Build number for package (default: 1) - --build-tag TAG Build tag for package (default: manual-build) - -Coverage options (lcov): - --run-coverage Build the release scope with -O0 --coverage, run ctest - and collect an lcov coverage report (mutually - exclusive with --run-jenkins-builder) - --coverage-output-dir DIR Directory to mount for coverage output - (default: ./coverage-out) - -Environment variable overrides: - BUILD_PREBUILT_IMAGE=ON|OFF - DELETE_PREBUILT_IMAGE=ON|OFF - DOCKER_IMAGE= - RUN_JENKINS_BUILDER=ON|OFF - PACKAGE_OUTPUT_DIR= - LTS_VERSION= - PROJECT= - GUEZ_MODE=ON|OFF - BUILD_NUMBER= - BUILD_TAG= - RUN_COVERAGE=ON|OFF - COVERAGE_OUTPUT_DIR= - -MIGRATE_PIPELINE_ROOT resolution (highest precedence first): - 1. exported MIGRATE_PIPELINE_ROOT (e.g. from a Jenkinsfile) - 2. MIGRATE_PIPELINE_ROOT set by .envrc in this directory - 3. derived from the script location (three levels up) - -Examples: - ./new_docker_build.sh --build-prebuilt-image --docker-image legatus-qt6:1.0 - ./new_docker_build.sh --docker-image legatus-qt6:1.0 - ./new_docker_build.sh --delete-prebuilt-image --docker-image legatus-qt6:1.0 - ./new_docker_build.sh --docker-image legatus-qt6:1.0 \ - --run-jenkins-builder \ - --package-output-dir "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" - ./new_docker_build.sh --docker-image legatus-qt6:1.0 \ - --run-coverage \ - --coverage-output-dir "${WORKSPACE}/coverage/${PROJECT}/${OS_VERSION}/" -EOF -} - -log_info() { - printf 'INFO: %s\n' "$*" -} - -log_error() { - printf 'ERROR: %s\n' "$*" >&2 -} - -die() { - log_error "$*" - exit 1 -} - -require_command() { - local cmd="$1" - command -v "$cmd" >/dev/null 2>&1 || die "Required command not found: ${cmd}" -} - -require_file() { - local path="$1" - local label="$2" - [[ -f "$path" ]] || die "${label} not found: ${path}" -} - -require_directory() { - local path="$1" - local label="$2" - [[ -d "$path" ]] || die "${label} directory not found: ${path}" -} - -require_non_empty() { - local value="$1" - local name="$2" - [[ -n "$value" ]] || die "Required variable ${name} is not set or empty" -} - -normalize_on_off() { - local value="$1" - local name="$2" - - case "${value^^}" in - ON|OFF) - printf '%s\n' "${value^^}" - ;; - *) - die "Invalid value for ${name}: ${value}. Expected ON or OFF" - ;; - esac -} - -join_by() { - local delimiter="$1" - shift || true - local first=1 - local arg - - for arg in "$@"; do - if [[ $first -eq 1 ]]; then - printf '%s' "$arg" - first=0 - else - printf '%s%s' "$delimiter" "$arg" - fi - done -} - -cleanup_temp_dir() { - local dir="${1:-}" - if [[ -n "$dir" && -d "$dir" ]]; then - rm -rf "$dir" - fi -} - -delete_prebuilt_image() { - local image_name="$1" - - if docker image inspect "$image_name" >/dev/null 2>&1; then - log_info "Deleting Docker image: ${image_name}" - docker rmi "$image_name" - log_info "Docker image deleted successfully: ${image_name}" - else - log_info "Docker image does not exist, nothing to delete: ${image_name}" - fi -} - -APT_PACKAGES=( - build-essential - cmake - libboost-dev - libboost-all-dev - libjson-glib-dev - libgeographiclib-dev - ninja-build - libkf6texttemplate-dev - libpoppler-dev - libpoppler-qt6-dev - libqt6core6 - libqt6gui6 - libqt6widgets6 - libqt6sql6 - libqt6sql6-psql - libqt6test6 - qt6-base-dev - qt6-l10n-tools - qt6-serialport-dev - qt6-svg-dev - qt6-tools-dev-tools - qt6-tools-dev - qt6-websockets-dev - libgtest-dev - libpq-dev - postgresql-server-dev-all - git - python3-pip - # Code coverage (genhtml ships in the same package) - lcov - # Packaging tools for RPM/DEB build - rpm - debhelper - dpkg-dev - fakeroot - devscripts -) - -# Release scope targets: TetraIF + Z components + Lts/Common libraries -# and the release-scope test executables (Lts/Common + Z) -RELEASE_BUILD_TARGETS=( - # TetraIF module targets (CoPrtCnv / LogView / PrtCnv) - CoPrtCnv - LogViewLogger - LogView - PrtCnvLib - PrtCnv - # Z module targets - NGLLogger - nglapplication - nglcompression - nglcoreapplication - ngldb - nglguiapplication - nglsettings - nglsingleapplication - nglsinglecoreapplication - ngltools - ngltranslator - nglwidgets - qtsingleapplication - qtsinglecoreapplication - wms_json_ds - tcpserver - # Lts/Common library targets (for tests) - LtsCoordTrans - LtsLicence - MockCoordTrans - # Test executables for release scope modules - # Note: grantlee_parser_smoke excluded - requires ktexttemplate_defaulttags plugin (not in release scope) - aes_crypt_test - ngltools_qt_smoke - lts_coord_trans_unit_test - test_nglpdfwidget - # TetraIF unit tests (TetraIF/unit-test) - coprtcnv_unit_test - logview_unit_test - prtcnv_unit_test -) - -APT_PACKAGES_STRING="$(join_by ' ' "${APT_PACKAGES[@]}")" - -build_prebuilt_image() { - local image_name="$1" - local dockerfile="Dockerfile" - - require_file "${dockerfile}" "Prebuilt-image Dockerfile" - - # The Dockerfile has no COPY/ADD, so an empty build context is fine - - # this avoids tarring the source tree into the build context. - local tmp_dir - tmp_dir="$(mktemp -d)" - - trap 'cleanup_temp_dir "$tmp_dir"' RETURN - - log_info "Building prebuilt Docker image: ${image_name} (Dockerfile: ${dockerfile})" - docker build -t "${image_name}" \ - -f "${dockerfile}" \ - --build-arg APT_PACKAGES="${APT_PACKAGES_STRING}" \ - --build-arg QT_VERSION="${QT_VERSION}" \ - --build-arg QT_ARCH="${QT_ARCH}" \ - --build-arg QT_BASE_DIR="${QT_BASE_DIR}" \ - "${tmp_dir}" - log_info "Prebuilt Docker image created successfully: ${image_name}" -} - -require_command docker - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -MIGRATE_PIPELINE_ROOT_DEFAULT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" -PIPELINE_ROOT_EXPORTED="${MIGRATE_PIPELINE_ROOT:-}" - -if [[ -f ".envrc" ]]; then - set -a - source ".envrc" - set +a -fi - -# An explicitly exported MIGRATE_PIPELINE_ROOT (Jenkinsfile) wins over .envrc -if [[ -n "${PIPELINE_ROOT_EXPORTED}" ]]; then - MIGRATE_PIPELINE_ROOT="${PIPELINE_ROOT_EXPORTED}" -else - MIGRATE_PIPELINE_ROOT="${MIGRATE_PIPELINE_ROOT:-${MIGRATE_PIPELINE_ROOT_DEFAULT}}" -fi - -# Fixed configuration for the release validation-scope branch -RELEASE_BUILD=ON -RUN_CTEST=ON -BUILD_PREBUILT_IMAGE="${BUILD_PREBUILT_IMAGE:-OFF}" -DELETE_PREBUILT_IMAGE="${DELETE_PREBUILT_IMAGE:-OFF}" -# Jenkins builder options for RPM/DEB package production -RUN_JENKINS_BUILDER="${RUN_JENKINS_BUILDER:-OFF}" -PACKAGE_OUTPUT_DIR="${PACKAGE_OUTPUT_DIR:-./packages-out}" -# Code coverage (lcov) -RUN_COVERAGE="${RUN_COVERAGE:-OFF}" -COVERAGE_OUTPUT_DIR="${COVERAGE_OUTPUT_DIR:-./coverage-out}" -LTS_VERSION="${LTS_VERSION:-1.0}" -PROJECT="${PROJECT:-guez}" -GUEZ_MODE="${GUEZ_MODE:-ON}" -BUILD_NUMBER="${BUILD_NUMBER:-1}" -BUILD_TAG="${BUILD_TAG:-manual-build}" -export QT_VERSION="${QT_VERSION:-6.10.2}" -export QT_ARCH="${QT_ARCH:-linux_gcc_64}" -# aqtinstall uses 'linux_gcc_64' but creates directory 'gcc_64' -export QT_ARCH_DIR="${QT_ARCH_DIR:-gcc_64}" -export QT_BASE_DIR="${QT_BASE_DIR:-/opt/Qt}" - -while [[ $# -gt 0 ]]; do - case "$1" in - --build-prebuilt-image) - BUILD_PREBUILT_IMAGE=ON - ;; - --delete-prebuilt-image) - DELETE_PREBUILT_IMAGE=ON - ;; - --docker-image) - shift - [[ $# -gt 0 ]] || die "--docker-image requires an image name" - DOCKER_IMAGE="$1" - ;; - --run-jenkins-builder) - RUN_JENKINS_BUILDER=ON - ;; - --package-output-dir) - shift - [[ $# -gt 0 ]] || die "--package-output-dir requires a directory path" - PACKAGE_OUTPUT_DIR="$1" - ;; - --run-coverage) - RUN_COVERAGE=ON - ;; - --coverage-output-dir) - shift - [[ $# -gt 0 ]] || die "--coverage-output-dir requires a directory path" - COVERAGE_OUTPUT_DIR="$1" - ;; - --lts-version) - shift - [[ $# -gt 0 ]] || die "--lts-version requires a version string" - LTS_VERSION="$1" - ;; - --project) - shift - [[ $# -gt 0 ]] || die "--project requires a project name" - PROJECT="$1" - ;; - --build-number) - shift - [[ $# -gt 0 ]] || die "--build-number requires a build number" - BUILD_NUMBER="$1" - ;; - --build-tag) - shift - [[ $# -gt 0 ]] || die "--build-tag requires a build tag" - BUILD_TAG="$1" - ;; - -h|--help) - usage - exit 0 - ;; - *) - usage - die "Unknown option: $1" - ;; - esac - shift -done - -BUILD_PREBUILT_IMAGE="$(normalize_on_off "$BUILD_PREBUILT_IMAGE" "BUILD_PREBUILT_IMAGE")" -DELETE_PREBUILT_IMAGE="$(normalize_on_off "$DELETE_PREBUILT_IMAGE" "DELETE_PREBUILT_IMAGE")" -RUN_JENKINS_BUILDER="$(normalize_on_off "$RUN_JENKINS_BUILDER" "RUN_JENKINS_BUILDER")" -RUN_COVERAGE="$(normalize_on_off "$RUN_COVERAGE" "RUN_COVERAGE")" - -if [[ "${RUN_COVERAGE}" == "ON" && "${RUN_JENKINS_BUILDER}" == "ON" ]]; then - die "--run-coverage is mutually exclusive with --run-jenkins-builder" -fi - -# Default for the Docker image name -DOCKER_IMAGE="${DOCKER_IMAGE:-legatus-qt6:1.0}" - -# Export variables for Docker container -export RELEASE_BUILD RUN_CTEST BUILD_PREBUILT_IMAGE DELETE_PREBUILT_IMAGE DOCKER_IMAGE RUN_JENKINS_BUILDER PACKAGE_OUTPUT_DIR RUN_COVERAGE COVERAGE_OUTPUT_DIR LTS_VERSION PROJECT GUEZ_MODE BUILD_NUMBER BUILD_TAG - -require_non_empty "${DOCKER_IMAGE}" "DOCKER_IMAGE" - -if [[ "${DELETE_PREBUILT_IMAGE}" == "ON" ]]; then - delete_prebuilt_image "${DOCKER_IMAGE}" - exit 0 -fi - -require_non_empty "${MIGRATE_PIPELINE_ROOT:-}" "MIGRATE_PIPELINE_ROOT" -require_directory "${MIGRATE_PIPELINE_ROOT}" "MIGRATE_PIPELINE_ROOT" - -WORKSPACE_ROOT_HOST="${MIGRATE_PIPELINE_ROOT}" -PROJECT_DIR_HOST="${WORKSPACE_ROOT_HOST}/qt-migration-legatus/qt6-after/qt6-migrated-legatus" - -require_directory "${PROJECT_DIR_HOST}" "Project directory" - -log_info "RELEASE_BUILD=${RELEASE_BUILD}" -log_info "RUN_CTEST=${RUN_CTEST}" -log_info "BUILD_PREBUILT_IMAGE=${BUILD_PREBUILT_IMAGE}" -log_info "DELETE_PREBUILT_IMAGE=${DELETE_PREBUILT_IMAGE}" -log_info "DOCKER_IMAGE=${DOCKER_IMAGE}" -log_info "RUN_JENKINS_BUILDER=${RUN_JENKINS_BUILDER}" -log_info "PACKAGE_OUTPUT_DIR=${PACKAGE_OUTPUT_DIR}" -log_info "RUN_COVERAGE=${RUN_COVERAGE}" -log_info "COVERAGE_OUTPUT_DIR=${COVERAGE_OUTPUT_DIR}" -log_info "LTS_VERSION=${LTS_VERSION}" -log_info "PROJECT=${PROJECT}" -log_info "GUEZ_MODE=${GUEZ_MODE}" -log_info "BUILD_NUMBER=${BUILD_NUMBER}" -log_info "BUILD_TAG=${BUILD_TAG}" -log_info "MIGRATE_PIPELINE_ROOT=${MIGRATE_PIPELINE_ROOT}" -log_info "PROJECT_DIR_HOST=${PROJECT_DIR_HOST}" - -if [[ "${BUILD_PREBUILT_IMAGE}" == "ON" ]]; then - build_prebuilt_image "${DOCKER_IMAGE}" - - log_info "Prebuilt image was built successfully." - log_info "To run the build with it, run:" - printf ' ./new_docker_build.sh --docker-image %q\n' "${DOCKER_IMAGE}" - exit 0 -fi - -RELEASE_BUILD_TARGETS_STRING="$(join_by ' ' "${RELEASE_BUILD_TARGETS[@]}")" - -HOST_TEMP_DIR="$(mktemp -d)" -CONTAINER_SCRIPT_HOST="${HOST_TEMP_DIR}/run-build-inside-container.sh" -cleanup_all() { - cleanup_temp_dir "${HOST_TEMP_DIR}" -} -trap cleanup_all EXIT - -cat > "${CONTAINER_SCRIPT_HOST}" <<'EOF' -#!/usr/bin/env bash -set -euo pipefail - -# Fixed configuration for the release validation-scope branch -RELEASE_BUILD="${RELEASE_BUILD:-ON}" -RUN_CTEST="${RUN_CTEST:-ON}" -# Packaging variables -RUN_JENKINS_BUILDER="${RUN_JENKINS_BUILDER:-OFF}" -RUN_COVERAGE="${RUN_COVERAGE:-OFF}" -LTS_VERSION="${LTS_VERSION:-1.0}" -PROJECT="${PROJECT:-guez}" -GUEZ_MODE="${GUEZ_MODE:-ON}" -BUILD_NUMBER="${BUILD_NUMBER:-1}" -BUILD_TAG="${BUILD_TAG:-manual-build}" -RELEASE_BUILD_TARGETS="${RELEASE_BUILD_TARGETS:-}" -QT_VERSION="${QT_VERSION:-6.10.2}" -QT_ARCH="${QT_ARCH:-linux_gcc_64}" -QT_ARCH_DIR="${QT_ARCH_DIR:-gcc_64}" -QT_BASE_DIR="${QT_BASE_DIR:-/opt/Qt}" - -log_info() { - printf 'INFO: %s\n' "$*" -} - -log_error() { - printf 'ERROR: %s\n' "$*" >&2 -} - -log_info "Using prebuilt Docker image: all build dependencies are baked in" - -export QT_QPA_PLATFORM=offscreen - -cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus - -rm -rf build4 -mkdir -p build4 -cd build4 - -COV_CMAKE_ARGS=() -if [[ "${RUN_COVERAGE}" == "ON" ]]; then - COV_CMAKE_ARGS=( - "-DCMAKE_C_FLAGS_RELEASE=-O0 -g --coverage -DNDEBUG -fPIC" - "-DCMAKE_CXX_FLAGS_RELEASE=-O0 -g --coverage -DNDEBUG -fPIC" - "-DCMAKE_EXE_LINKER_FLAGS=--coverage" - "-DCMAKE_SHARED_LINKER_FLAGS=--coverage" - ) -fi -cmake .. \ - -DBUILD_TESTING=ON \ - -DRELEASE_BUILD="${RELEASE_BUILD}" \ - -DCMAKE_CXX_STANDARD=17 \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH="${QT_BASE_DIR}/${QT_VERSION}/${QT_ARCH_DIR}:/usr/local" \ - "${COV_CMAKE_ARGS[@]}" - -read -r -a RELEASE_TARGETS_ARRAY <<< "${RELEASE_BUILD_TARGETS}" - -log_info "Building release scope targets: ${RELEASE_TARGETS_ARRAY[*]}" -make -j8 "${RELEASE_TARGETS_ARRAY[@]}" 2>&1 | tee release_build.log - -if [[ "${RUN_CTEST}" == "ON" ]]; then - log_info "Running CTest" - ctest --test-dir . --output-on-failure || CTEST_RESULT=$? - if [[ "${CTEST_RESULT:-0}" -ne 0 ]]; then - log_info "CTest completed with failures (exit code: ${CTEST_RESULT})" - fi -else - log_info "Skipping CTest" -fi - -if [[ "${RUN_COVERAGE}" == "ON" ]]; then - log_info "=== Code coverage (lcov) ===" - COVOUT=/workspace/coverage-out - SRCROOT=/workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus - mkdir -p "${COVOUT}" - - COV_IGNORE=(--ignore-errors mismatch,inconsistent,unused) - lcov --capture --directory . --external "${COV_IGNORE[@]}" \ - --rc branch_coverage=1 \ - --output-file "${COVOUT}/raw.info" - lcov --extract "${COVOUT}/raw.info" \ - "${SRCROOT}/TetraIF/*" \ - "${SRCROOT}/Z/src/*" \ - "${SRCROOT}/Lts/Common/*" \ - "${SRCROOT}/Lts/Proxies/TrainingAreaBase/*" \ - "${COV_IGNORE[@]}" \ - --rc branch_coverage=1 \ - --output-file "${COVOUT}/scoped.info" - lcov --remove "${COVOUT}/scoped.info" \ - "*/unit-test/*" \ - "*CommonUnitTestsPlaceholder*" \ - "*/UnitTests/*" \ - "*/tests/*" \ - "*/test_*" \ - "*_test.cpp" \ - "*_test.h" \ - "*_unit_test*" \ - "${COV_IGNORE[@]}" \ - --rc branch_coverage=1 \ - --output-file "${COVOUT}/coverage.info" - lcov --summary "${COVOUT}/coverage.info" "${COV_IGNORE[@]}" --rc branch_coverage=1 \ - > "${COVOUT}/coverage_summary.txt" - genhtml "${COVOUT}/coverage.info" \ - --output-directory "${COVOUT}/html" \ - "${COV_IGNORE[@]}" \ - --branch-coverage --legend \ - --rc branch_coverage=1 - log_info "Coverage report written to ${COVOUT} (host: ${COVERAGE_OUTPUT_DIR})" - cat "${COVOUT}/coverage_summary.txt" -fi - -# DEB package production with the in-tree rpmbuild script -if [[ "${RUN_JENKINS_BUILDER}" == "ON" ]]; then - log_info "=== DEB Package Production (in-tree rpmbuild) ===" - - OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | cut -d'"' -f2) - STAGE_DIR=/workspace/deb_stage - STAGED_SOURCE_DIR="${STAGE_DIR}/qt-migration-legatus/qt6-after/qt6-migrated-legatus" - - log_info "Staging workspace to ${STAGE_DIR}" - rm -rf "${STAGE_DIR}" - mkdir -p "${STAGE_DIR}" - tar --exclude='./rpms' --exclude='./.git' --exclude='./build' \ - --exclude='./deb_build_tmp' --exclude='./deb_stage' --exclude='./packages-out' \ - -cf - -C /workspace . | tar -xf - -C "${STAGE_DIR}" - - if [[ ! -f "${STAGED_SOURCE_DIR}/CMakeLists.txt" || ! -f "${STAGED_SOURCE_DIR}/rpmbuild/make_rpm_ubuntu26.py" ]]; then - log_error "Staged source incomplete under ${STAGED_SOURCE_DIR} (CMakeLists.txt or rpmbuild/make_rpm_ubuntu26.py missing)" - exit 1 - fi - - log_info "Running ${STAGED_SOURCE_DIR}/rpmbuild/make_rpm_ubuntu26.py with:" - log_info " PROJECT=${PROJECT}" - log_info " OS_VERSION=${OS_VERSION}" - log_info " LTS_VERSION=${LTS_VERSION}" - log_info " GUEZ_MODE=${GUEZ_MODE}" - log_info " BUILD_NUMBER=${BUILD_NUMBER}" - log_info " BUILD_TAG=${BUILD_TAG}" - - cd "${STAGED_SOURCE_DIR}/rpmbuild" - if python3 make_rpm_ubuntu26.py -c LTS \ - --project_name "${PROJECT}" \ - --version "${LTS_VERSION}" \ - --output_dir "/workspace/rpms/${PROJECT}/${OS_VERSION}/" \ - --source_dir "${STAGED_SOURCE_DIR}" \ - --cmake_build_flags "-DUSE_IPO=ON -DUSE_UNITY_BUILD=ON -DGUEZ_MODE=${GUEZ_MODE} -DBUILD_WLS=ON -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/postgresql/ -DRELEASE_BUILD=ON" \ - --build_number "${BUILD_NUMBER}" \ - --release_scope; then - log_info "Package build completed successfully" - else - log_error "Package build failed (exit code: $?)" - exit 1 - fi - - # Copy produced DEB packages to the packages-out - DEST_DIR=/workspace/packages-out - mkdir -p "${DEST_DIR}" - shopt -s nullglob - for deb in "/workspace/rpms/${PROJECT}/${OS_VERSION}/"*.deb; do - base="$(basename "${deb}")" - if [[ -e "${DEST_DIR}/${base}" ]] && - [[ "$(stat -c '%d:%i' "${deb}")" == "$(stat -c '%d:%i' "${DEST_DIR}/${base}")" ]]; then - continue - fi - cp -f "${deb}" "${DEST_DIR}/" - done - shopt -u nullglob - log_info "DEB packages available in ${DEST_DIR} (host: ${PACKAGE_OUTPUT_DIR:-unknown}):" - ls -lh "${DEST_DIR}/" -else - log_info "Skipping DEB package production" -fi -EOF - -chmod +x "${CONTAINER_SCRIPT_HOST}" - -docker run --rm \ - -e MIGRATE_PIPELINE_ROOT \ - -e LANG \ - -e LC_ALL \ - -e RELEASE_BUILD \ - -e RUN_CTEST \ - -e RUN_JENKINS_BUILDER \ - -e RUN_COVERAGE \ - -e COVERAGE_OUTPUT_DIR \ - -e PACKAGE_OUTPUT_DIR \ - -e LTS_VERSION \ - -e PROJECT \ - -e GUEZ_MODE \ - -e BUILD_NUMBER \ - -e BUILD_TAG \ - -e QT_VERSION \ - -e QT_ARCH \ - -e QT_ARCH_DIR \ - -e QT_BASE_DIR \ - -e RELEASE_BUILD_TARGETS="${RELEASE_BUILD_TARGETS_STRING}" \ - -v "${WORKSPACE_ROOT_HOST}:/workspace" \ - -v "${MIGRATE_PIPELINE_ROOT}/external:/workspace/external:ro" \ - -v "${CONTAINER_SCRIPT_HOST}:/tmp/run-build-inside-container.sh:ro" \ - -v "${PACKAGE_OUTPUT_DIR}:/workspace/packages-out" \ - -v "${COVERAGE_OUTPUT_DIR}:/workspace/coverage-out" \ - "${DOCKER_IMAGE}" \ - bash /tmp/run-build-inside-container.sh diff --git a/qt6-after/qt6-migrated-legatus/rpmbuild/make_rpm_ubuntu26.py b/qt6-after/qt6-migrated-legatus/rpmbuild/make_rpm_ubuntu26.py deleted file mode 100755 index ca3973a06..000000000 --- a/qt6-after/qt6-migrated-legatus/rpmbuild/make_rpm_ubuntu26.py +++ /dev/null @@ -1,526 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- -""" -DEB package builder for Ubuntu 26.04 - Qt6 Release -Creates 5 separate DEB packages as per customer requirements: -1. qt6-release-runtime - binaries and libraries from S -2. qt6-release-sources - Qt6 C++ sources from S -3. qt6-release-ctest-runtime - CTest executables -4. qt6-release-ctest-sources - CTest source files -5. qt6-release-build-pipeline - Dockerfiles, build scripts, CI/CD files -""" - -import argparse -import fnmatch -import os -import shutil -import subprocess -import sys -from email.utils import formatdate - -SKIP_DIRS = {'build', 'cmake-build-debug', 'cmake-build-release', 'deb_build_tmp'} -SOURCE_EXTENSIONS = ('.cpp', '.h', '.hpp', '.cc', '.cxx', '.hxx') -PIPELINE_FILES = [ - "new_docker_build.sh", - "Dockerfile", - "jenkins-ci-rme/Jenkinsfile", - "jenkins-ci-rme/jenkins_builder_ubuntu26.sh", - "jenkins-ci-rme/jenkins_publisher_ubuntu26.sh", - "jenkins-ci-rme/release-16-10-2026.sh", - "rpmbuild/make_rpm_ubuntu26.py", - "CMakeLists.txt", -] - - -def verbose(): - verb = os.getenv("EMERGE_VERBOSE") - if verb is not None and verb.isdigit() and int(verb) > 0: - return int(verb) - return 0 - - -def debug(message): - if verbose() >= 1: - print(f"debug: {message}") - return True - - -def info(message): - print(f"info: {message}") - return True - - -def warning(message): - print(f"warning: {message}") - return True - - -def error(message): - die(message) - - -def die(message): - print(f"emerge fatal error: {message}", file=sys.stderr) - sys.exit(1) - - -def run(cmd, label, env=None): - """Run a shell command, print its output and die on failure.""" - debug(f"Executing: {cmd}") - ret = subprocess.run(cmd, shell=True, env=env, capture_output=True, text=True) - if ret.returncode != 0: - print(ret.stdout) - print(ret.stderr) - die(f"{label} with code {ret.returncode}") - - -def remove_directory(path): - if os.path.exists(path): - shutil.rmtree(path) - - -def is_dds_file(filepath): - """True if the path is DDS-related and must be excluded.""" - return 'dds' in filepath.lower() - - -def prune_dirs(dirs, root, file_filter): - """Prune hidden/build dirs in-place (and dirs matching file_filter).""" - dirs[:] = [d for d in dirs - if not d.startswith('.') - and d not in SKIP_DIRS - and (file_filter is None or not file_filter(os.path.join(root, d)))] - - -def copy_src_dir_to_dest_dir(src_dir, dest_dir, file_filter=None): - """Copy the source tree, skipping hidden/build dirs and filtered files.""" - os.makedirs(dest_dir, exist_ok=True) - for root, dirs, files in os.walk(src_dir): - prune_dirs(dirs, root, file_filter) - for file in files: - src_file = os.path.join(root, file) - if file_filter and file_filter(src_file): - continue - dest_file = os.path.join(dest_dir, os.path.relpath(src_file, src_dir)) - os.makedirs(os.path.dirname(dest_file), exist_ok=True) - shutil.copy2(src_file, dest_file) - - -def find_test_module_source(pkg_dir, test_name, release_dirs): - """Module dir (relative to pkg_dir) whose CMakeLists defines test_name, or None.""" - for rel_dir in release_dirs: - module_dir = os.path.join(pkg_dir, rel_dir) - if not os.path.exists(module_dir): - continue - for root, dirs, files in os.walk(module_dir): - prune_dirs(dirs, root, None) - if 'CMakeLists.txt' not in files: - continue - try: - with open(os.path.join(root, 'CMakeLists.txt')) as f: - content = f.read() - except Exception: - continue - if f'ADD_EXECUTABLE({test_name}' in content or f'ADD_TEST(NAME {test_name}' in content: - return os.path.relpath(root, pkg_dir) - return None - - -def find_test_executables(pkg_dir, release_dirs): - """(executable, module) pairs for the test executables in build4/bin/.""" - test_executables = [] - build_bin_dir = os.path.join(pkg_dir, "build4", "bin") - if not os.path.exists(build_bin_dir): - warning(f"Build bin directory not found: {build_bin_dir}") - return test_executables - for filename in os.listdir(build_bin_dir): - file_path = os.path.join(build_bin_dir, filename) - if not (os.path.isfile(file_path) and os.access(file_path, os.X_OK)): - continue - if 'test' not in filename.lower(): - continue - module_path = find_test_module_source(pkg_dir, filename, release_dirs) - if module_path: - test_executables.append((file_path, module_path)) - debug(f" Found test executable: {filename} from {module_path}") - else: - debug(f" Skipping test executable (no module found): {filename}") - return test_executables - - -def find_test_sources(pkg_dir, release_dirs): - """Relative paths of test source files (name containing 'test', .cpp/.h).""" - test_sources = [] - for rel_dir in release_dirs: - module_dir = os.path.join(pkg_dir, rel_dir) - if not os.path.exists(module_dir): - continue - for root, dirs, files in os.walk(module_dir): - prune_dirs(dirs, root, None) - for filename in files: - if 'test' in filename.lower() and filename.endswith(('.cpp', '.h')): - file_path = os.path.join(root, filename) - rel_path = os.path.relpath(file_path, pkg_dir) - test_sources.append(rel_path) - debug(f" Found test source: {rel_path}") - return test_sources - - -def write_deb_file(deb_dir, name, content, executable=False): - """Write a debian/* file and log its creation.""" - path = os.path.join(deb_dir, name) - with open(path, "w") as f: - f.write(content) - if executable: - os.chmod(path, 0o755) - info(f"Created {path}") - - -def create_debian_control(deb_dir, package_name, version, build_number, description, - depends="", section="devel"): - write_deb_file(deb_dir, "control", f"""Source: {package_name} -Section: {section} -Priority: optional -Maintainer: Legatus Team -Build-Depends: debhelper (>= 13), cmake, qt6-base-dev, qt6-tools-dev -Standards-Version: 4.6.0 - -Package: {package_name} -Architecture: any -Depends: ${{shlibs:Depends}}, ${{misc:Depends}}{", " + depends if depends else ""} -Description: {description} - Legatus Qt6 Release Package - This package is part of the Legatus Qt6 migration release. -""") - - -def create_debian_changelog(deb_dir, package_name, version, build_number): - write_deb_file(deb_dir, "changelog", f"""{package_name} ({version}-{build_number}) unstable; urgency=medium - - * Qt6 Release Build - - -- Legatus Team {formatdate(localtime=True)} -""") - - -def create_debian_rules(deb_dir, cmake_flags="", skip_tests=False): - test_override = """ -override_dh_auto_test: - # Tests skipped for this package type -""" if skip_tests else "" - write_deb_file(deb_dir, "rules", f"""#!/usr/bin/make -f -%: - dh $@ --buildsystem=cmake - -override_dh_auto_configure: - dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release {cmake_flags} - -override_dh_auto_build: - dh_auto_build --parallel - -override_dh_auto_install: - dh_auto_install --destdir=debian/tmp -{test_override}""", executable=True) - - -def create_debian_rules_nobuild(deb_dir, skip_shlibdeps=False): - content = """#!/usr/bin/make -f -%: - dh $@ - -override_dh_auto_build: - # No build step needed - pre-built files only - -override_dh_auto_configure: - # No configure step needed - pre-built files only - -override_dh_auto_install: - dh_auto_install -""" - if skip_shlibdeps: - content += """ -override_dh_shlibdeps: - # Skip shlibdeps for test executables - Qt6 deps are external system packages -""" - write_deb_file(deb_dir, "rules", content, executable=True) - - -def create_debian_install(deb_dir, install_lines): - install_file = os.path.join(deb_dir, "install") - with open(install_file, "w") as f: - for line in install_lines: - f.write(line + "\n") - info(f"Created {install_file} with {len(install_lines)} entries") - - -def create_manifest(output_dir, package_name, pkg_dir): - """Write the manifest of package contents (from the DEB, or the pkg dir).""" - manifest_file = os.path.join(output_dir, "manifests", f"{package_name}.manifest") - os.makedirs(os.path.dirname(manifest_file), exist_ok=True) - deb_file = next((os.path.join(output_dir, f) for f in os.listdir(output_dir) - if f.startswith(package_name) and f.endswith(".deb")), None) - manifest_lines = [] - if deb_file and os.path.exists(deb_file): - result = subprocess.run(["dpkg-deb", "--contents", deb_file], - capture_output=True, text=True) - if result.returncode == 0: - # dpkg-deb --contents: "-rw-r--r-- root/root 1234 2024-01-01 00:00 ./path" - for line in result.stdout.strip().split("\n"): - parts = line.split() - if len(parts) >= 6: - file_path = parts[-1] - if file_path.startswith("./"): - file_path = file_path[2:] - elif file_path.startswith("/"): - file_path = file_path[1:] - if file_path: - manifest_lines.append(file_path) - elif os.path.exists(pkg_dir): - info(f"Warning: DEB file not found for {package_name}, scanning directory instead") - for root, dirs, files in os.walk(pkg_dir): - for file in files: - manifest_lines.append(os.path.relpath(os.path.join(root, file), pkg_dir)) - manifest_lines.sort() - with open(manifest_file, "w") as f: - for line in manifest_lines: - f.write(line + "\n") - info(f"Created manifest: {manifest_file} ({len(manifest_lines)} entries)") - return manifest_lines - - -def validate_package_contents(package_name, manifest_lines, allowed_patterns, forbidden_patterns=None): - """Validate package contents against the allowlist/forbidden list.""" - errors = [] - warnings = [] - for file_path in manifest_lines: - if file_path.endswith('/'): - continue - if forbidden_patterns: - for pattern in forbidden_patterns: - if fnmatch.fnmatch(file_path, pattern): - errors.append(f"FORBIDDEN file in {package_name}: {file_path} (matches {pattern})") - allowed = bool(allowed_patterns) and any(fnmatch.fnmatch(file_path, p) for p in allowed_patterns) - if not allowed and allowed_patterns: - warnings.append(f"Unexpected file in {package_name}: {file_path}") - for err in errors: - error(f"Validation error: {err}") - if errors: - return False - for warn in warnings: - warning(f"Validation warning: {warn}") - return True - - -def build_deb(pkg_name, pkg_dir, output_dir, version, build_number, - cmake_flags="", nobuild=False, skip_tests=False, skip_shlibdeps=False, - install_lines=None, description="", section="devel", depends=""): - """Build one DEB package (with or without a cmake build) and move its artifacts.""" - info(f"Building DEB package {'(no-build): ' if nobuild else ''}{pkg_name}") - deb_dir = os.path.join(pkg_dir, "debian") - os.makedirs(deb_dir) - create_debian_control(deb_dir, pkg_name, version, build_number, description, depends, section) - create_debian_changelog(deb_dir, pkg_name, version, build_number) - if nobuild: - create_debian_rules_nobuild(deb_dir, skip_shlibdeps=skip_shlibdeps) - else: - create_debian_rules(deb_dir, cmake_flags, skip_tests) - os.makedirs(os.path.join(deb_dir, "source")) - with open(os.path.join(deb_dir, "source", "format"), "w") as f: - f.write("3.0 (quilt)\n") - with open(os.path.join(deb_dir, "compat"), "w") as f: - f.write("13\n") - if install_lines: - create_debian_install(deb_dir, install_lines) - - info(f"Running debuild for {pkg_name}...") - os.chdir(pkg_dir) - env = os.environ.copy() - env["DEB_BUILD_OPTIONS"] = "parallel=$(nproc)" - run("debuild -us -uc -b", f"debuild failed for {pkg_name}", env=env) - - parent_dir = os.path.dirname(pkg_dir) - for f in os.listdir(parent_dir): - if f.endswith((".deb", ".dsc", ".changes", ".buildinfo")): - src = os.path.join(parent_dir, f) - dst = os.path.join(output_dir, f) - if os.path.exists(dst): - os.remove(dst) - shutil.move(src, output_dir) - info(f"Moved {f} to {output_dir}") - return True - - -def source_install_lines(pkg_dir, release_dirs): - lines = [] - for rel_dir in release_dirs: - src_dir = os.path.join(pkg_dir, rel_dir) - if not os.path.exists(src_dir): - continue - for root, dirs, files in os.walk(src_dir): - dirs[:] = [d for d in dirs if not d.startswith('.')] - for file in files: - if os.path.splitext(file)[1].lower() in SOURCE_EXTENSIONS or file == "CMakeLists.txt": - rel_path = os.path.relpath(os.path.join(root, file), pkg_dir) - lines.append(f"{rel_path} {os.path.join('usr/src', os.path.dirname(rel_path))}/") - return lines - - -def ctest_runtime_install_lines(pkg_dir, release_dirs): - lines = [] - for exe_path, module_path in find_test_executables(pkg_dir, release_dirs): - lines.append(f"{os.path.relpath(exe_path, pkg_dir)} usr/lib/ctest/") - info(f" Including test executable: {os.path.basename(exe_path)} from {module_path}") - for ctest_file in ("build4/CTestTestfile.cmake", "build4/DartConfiguration.tcl", "build4/Testing/TAG"): - if os.path.exists(os.path.join(pkg_dir, ctest_file)): - lines.append(f"{ctest_file} usr/lib/ctest/") - return lines - - -def test_sources_install_lines(pkg_dir, release_dirs): - return [f"{rel_path} {os.path.dirname(rel_path)}/" for rel_path in find_test_sources(pkg_dir, release_dirs)] - - -def pipeline_install_lines(pkg_dir): - lines = [] - for pipeline_file in PIPELINE_FILES: - if os.path.exists(os.path.join(pkg_dir, pipeline_file)): - lines.append(f"{pipeline_file} {os.path.join('usr/src/pipeline', os.path.dirname(pipeline_file))}/") - info(f" Added pipeline file: {pipeline_file}") - return lines - - -def build_nobuild_package(name, source_dir, build_base, output_dir, version, build_number, - description, prepare, allowed_patterns, forbidden_patterns, - file_filter=None, skip_shlibdeps=False, section="devel"): - """Stage the source tree, build a no-build DEB and validate its contents.""" - info(f"\n=== Building {name} ===") - pkg_dir = os.path.join(build_base, f"{name}-{version}") - os.makedirs(pkg_dir) - copy_src_dir_to_dest_dir(source_dir, pkg_dir, file_filter=file_filter) - build_deb(pkg_name=name, pkg_dir=pkg_dir, output_dir=output_dir, - version=version, build_number=build_number, nobuild=True, - skip_shlibdeps=skip_shlibdeps, install_lines=prepare(pkg_dir), - description=description, section=section) - manifest = create_manifest(output_dir, name, pkg_dir) - validate_package_contents(name, manifest, allowed_patterns, forbidden_patterns) - - -def build_all_debs(source_dir, output_dir, version, build_number, cmake_flags): - """Build the 5 DEB packages: build once from the source tree, then package.""" - info("========================================") - info("Building 5 DEB packages for Qt6 Release") - info("========================================") - os.makedirs(output_dir, exist_ok=True) - os.makedirs(os.path.join(output_dir, "manifests"), exist_ok=True) - build_base = os.path.join(source_dir, "deb_build_tmp") - remove_directory(build_base) - os.makedirs(build_base) - release_dirs = ["TetraIF", "Z/src", "Lts/Common"] - - # Step 1: build once from the full source tree - info("\n=== Step 1: Building from full source tree ===") - build_dir = os.path.join(source_dir, "build") - os.makedirs(build_dir, exist_ok=True) - os.chdir(build_dir) - info("Running CMake configuration...") - run(f"cmake -DCMAKE_BUILD_TYPE=Release {cmake_flags} ..", "CMake configuration failed") - info("Running build...") - run(f"make -j$(nproc)", "Build failed") - info("Build completed successfully") - - # Package 1: qt6-release-runtime (binaries and libraries, built via debuild) - info("\n=== Building qt6-release-runtime ===") - pkg1_dir = os.path.join(build_base, f"qt6-release-runtime-{version}") - os.makedirs(pkg1_dir) - # FULL source tree (needed for debian/rules cmake reference) - copy_src_dir_to_dest_dir(source_dir, pkg1_dir) - # Install from all component install paths: ALL -> bin/, lib/ ; SV/ ; WS/ - install_lines_1 = [ - "usr/bin/* usr/bin/", - "usr/lib/*.so* usr/lib/", - "usr/SV/bin/* usr/bin/", - "usr/SV/lib/*.so* usr/lib/", - "usr/WS/bin/* usr/bin/", - "usr/WS/lib/*.so* usr/lib/", - ] - build_deb(pkg_name="qt6-release-runtime", pkg_dir=pkg1_dir, output_dir=output_dir, - version=version, build_number=build_number, cmake_flags=cmake_flags, - skip_tests=True, install_lines=install_lines_1, - description="Qt6 Release Runtime - binaries and libraries from release scope S", - section="libs") - manifest_1 = create_manifest(output_dir, "qt6-release-runtime", pkg1_dir) - validate_package_contents("qt6-release-runtime", manifest_1, - allowed_patterns=["usr/bin/*", "usr/lib/*", "usr/SV/*", "usr/WS/*", "usr/share/doc/*", "debian/*"], - forbidden_patterns=["*.cpp", "*.h", "*.hpp", "tests/*", "jenkins/*", "Dockerfile*"]) - - # Package 2: qt6-release-sources (release-scope sources, DDS excluded) - build_nobuild_package( - "qt6-release-sources", source_dir, build_base, output_dir, version, build_number, - description="Qt6 Release Sources - C++ source files from release scope S", - prepare=lambda pkg_dir: source_install_lines(pkg_dir, release_dirs), - allowed_patterns=["usr/src/*", "usr/share/doc/*", "debian/*"], - forbidden_patterns=["build/*", "tests/*", "jenkins/*"], - file_filter=is_dds_file) - - # Package 3: qt6-release-ctest-runtime (test executables from release scope) - build_nobuild_package( - "qt6-release-ctest-runtime", source_dir, build_base, output_dir, version, build_number, - description="Qt6 Release CTest Runtime - executable test programs from release scope", - prepare=lambda pkg_dir: ctest_runtime_install_lines(pkg_dir, release_dirs), - allowed_patterns=["usr/lib/ctest/*", "usr/share/doc/*", "debian/*"], - forbidden_patterns=["*.cpp", "*.h", "jenkins/*"], - skip_shlibdeps=True) - - # Package 4: qt6-release-ctest-sources (test source files from release scope) - build_nobuild_package( - "qt6-release-ctest-sources", source_dir, build_base, output_dir, version, build_number, - description="Qt6 Release CTest Sources - test source files from release scope", - prepare=lambda pkg_dir: test_sources_install_lines(pkg_dir, release_dirs), - allowed_patterns=["Lts/*", "TetraIF/*", "Z/*", "usr/share/doc/*", "debian/*"], - forbidden_patterns=["build/*", "jenkins/*"]) - - # Package 5: qt6-release-build-pipeline (Docker, Jenkins, CMake, packaging scripts) - build_nobuild_package( - "qt6-release-build-pipeline", source_dir, build_base, output_dir, version, build_number, - description="Qt6 Release Build Pipeline - Docker, Jenkins, CMake, and packaging scripts", - prepare=pipeline_install_lines, - allowed_patterns=["usr/src/pipeline/*", "usr/share/doc/*", "debian/*"], - forbidden_patterns=["*.cpp", "*.h", "tests/*"]) - - # Cleanup - os.chdir(source_dir) - remove_directory(build_base) - - info("\n========================================") - info(f"DEB package build completed: {output_dir}") - info("Generated packages:") - for f in os.listdir(output_dir): - if f.endswith(".deb"): - info(f" - {f}") - info("========================================") - - -def main(): - parser = argparse.ArgumentParser(description="Build DEB packages for Legatus Qt6 Release") - parser.add_argument("-c", "--config", required=True, help="Config type (LTS)") - parser.add_argument("--project_name", required=True, help="Project name (qatar|ahtc|guez)") - parser.add_argument("--version", required=True, help="Version (Major.minor)") - parser.add_argument("--output_dir", required=True, help="Output directory for packages") - parser.add_argument("--source_dir", required=True, help="Source directory path") - parser.add_argument("--cmake_build_flags", default="", help="CMake build flags") - parser.add_argument("--build_number", default="1", help="Build number") - parser.add_argument("--release_scope", action="store_true", help="Only include release scope files") - - args = parser.parse_args() - info(f"Building {args.config} package for {args.project_name} v{args.version}") - info(f"Output directory: {args.output_dir}") - info(f"Source directory: {args.source_dir}") - info(f"CMake flags: {args.cmake_build_flags}") - info(f"Release scope: {args.release_scope}") - build_all_debs(source_dir=args.source_dir, output_dir=args.output_dir, - version=args.version, build_number=args.build_number, - cmake_flags=args.cmake_build_flags) - - -if __name__ == "__main__": - main()