From 1064d9f06b110d212b3566949675476239e00aa2 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Thu, 2 Apr 2026 15:56:10 +0200 Subject: [PATCH 01/31] deb workflow added --- .github/workflows/create-release-deb.yml | 17 ++ scripts/create-deb-deploy.sh | 278 +++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 .github/workflows/create-release-deb.yml create mode 100755 scripts/create-deb-deploy.sh diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml new file mode 100644 index 0000000..ffb0f02 --- /dev/null +++ b/.github/workflows/create-release-deb.yml @@ -0,0 +1,17 @@ +name: Create Release and .deb Files Project + +on: + push: + tags: + - 'v*.*.*' + - 'v*.*.*-rc*' + +env: + GNUTLS_CPUID_OVERRIDE: 0x1 + +jobs: + create-release-ci-cd: + uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main + with: + package-name: "dls2" + deb-script-path: "scripts/create-deb-deploy.sh" diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh new file mode 100755 index 0000000..6a0f7b1 --- /dev/null +++ b/scripts/create-deb-deploy.sh @@ -0,0 +1,278 @@ +#!/usr/bin/env bash + +if [ -z "${BASH_VERSION:-}" ]; then + echo "ERROR: run this script with bash" + exit 1 +fi + +set -euo pipefail + +# ----------------------------------------------------------------------------- +# Build + package script (deployment CI on runner host) +# Produces: dls2__amd64.deb at repo root. +# ----------------------------------------------------------------------------- + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +ART_DIR="${ROOT_DIR}/deb_pipeline_artifacts" +BUILD_LOG="${ART_DIR}/build.log" + +VERSION="${VERSION_OVERRIDE:-0.0.0-local}" +DEB_CONTROL_VERSION="$(echo "${VERSION}" | sed -E 's/^[^0-9]*//')" +if [[ -z "${DEB_CONTROL_VERSION}" ]]; then + echo "ERROR: VERSION '${VERSION}' cannot be converted to a Debian control version" + exit 1 +fi + +PACKAGE_NAME="${PACKAGE_NAME:-dls2}" +MAINTAINER="${DEB_MAINTAINER:-Michele Pestarino }" +PACKAGE_DESCRIPTION="${DEB_DESCRIPTION:-DLS2 runtime package}" +DEB_DEPENDS="${DEB_DEPENDS:-python3, python3-psutil, libyaml-cpp0.8, libtinyxml2-10, libgtk-3-0, libcairo2, libglib2.0-0, libboost-filesystem1.83.0, libconsole-bridge1.0, libcap2-bin}" + +DEB_NAME="${PACKAGE_NAME}_${VERSION}_amd64.deb" +DEB_PATH="${ROOT_DIR}/${DEB_NAME}" +JOBS="${JOBS:-4}" +LIVE_BUILD_OUTPUT="${LIVE_BUILD_OUTPUT:-0}" +BUILD_VERBOSE="${BUILD_VERBOSE:-0}" +CLEAN_BUILD="${CLEAN_BUILD:-0}" +CMAKE_ARGS="${CMAKE_ARGS:-}" +BUILD_ARGS="${BUILD_ARGS:--j${JOBS}}" + +DEPLOY_FLAGS=( + DLS_DEPLOY_gazebo_sim + DLS_DEPLOY_pid_controller + DLS_DEPLOY_periodic_generator + DLS_DEPLOY_foot_traj_generator + DLS_DEPLOY_gait_timer + DLS_DEPLOY_terrain_estimator + DLS_DEPLOY_trunk_controller + DLS_DEPLOY_dls_keyboard + DLS_DEPLOY_dls_gamepad +) + +CMAKE_DEPLOY_ARGS=() +for flag in "${DEPLOY_FLAGS[@]}"; do + value="${!flag:-ON}" + CMAKE_DEPLOY_ARGS+=("-D${flag}=${value}") +done + +mkdir -p "${ART_DIR}" +rm -f "${DEB_PATH}" "${ART_DIR}/pkg_files.txt" "${BUILD_LOG}" + +run_pipeline() { + local build_dir="${ROOT_DIR}/build" + local stage_dir="${ROOT_DIR}/.deb_stage" + + cleanup_stage() { + rm -rf "${stage_dir}" "${ROOT_DIR}/stage" + } + trap cleanup_stage EXIT + + if [[ "${CLEAN_BUILD}" == "1" ]]; then + rm -rf "${build_dir}" + fi + rm -rf "${stage_dir}" + + # shellcheck disable=SC2206 + local cmake_user_args=(${CMAKE_ARGS}) + # shellcheck disable=SC2206 + local build_user_args=(${BUILD_ARGS}) + + cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ + "${CMAKE_DEPLOY_ARGS[@]}" \ + "${cmake_user_args[@]}" + + if [[ "${BUILD_VERBOSE}" == "1" ]]; then + cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose + else + cmake --build "${build_dir}" -- "${build_user_args[@]}" + fi + + # Expected setcap warnings during staged install are tolerated. + DESTDIR="${stage_dir}" cmake --install "${build_dir}" || true + + # Ensure robot description assets are packaged when available. + if [[ -d "${ROOT_DIR}/robots/aliengo/aliengo-description" ]]; then + mkdir -p "${stage_dir}/usr/include/aliengo_description" + for dir in gazebo launch meshes robcogen robots rviz urdfs yarf foxglove default_postures kinematics; do + if [[ -d "${ROOT_DIR}/robots/aliengo/aliengo-description/${dir}" ]]; then + cp -a "${ROOT_DIR}/robots/aliengo/aliengo-description/${dir}" "${stage_dir}/usr/include/aliengo_description/" + fi + done + fi + + strip "${stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true + strip "${stage_dir}/usr/bin/dls2/child_process_launcher" || true + strip "${stage_dir}/usr/lib/librobotlib.so" || true + + copy_into_stage() { + local src="$1" + local dst="${stage_dir}${src}" + [[ -f "${src}" ]] || return 0 + mkdir -p "$(dirname "${dst}")" + if [[ -L "${src}" ]]; then + cp -a --no-dereference "${src}" "${dst}" + local resolved + resolved="$(readlink -f "${src}" || true)" + if [[ -n "${resolved}" && "${resolved}" != "${src}" && -f "${resolved}" ]]; then + copy_into_stage "${resolved}" + fi + else + cp -a "${src}" "${dst}" + fi + } + + copy_ldd_closure() { + local target="$1" + [[ -e "${target}" ]] || return 0 + (ldd "${target}" 2>/dev/null || true) \ + | awk ' + /=> \// {print $3} + /^\// {print $1} + ' \ + | sort -u \ + | while IFS= read -r lib; do + [[ -f "${lib}" ]] || continue + case "$(basename "${lib}")" in + libfastdds.so*|libfastcdr.so*|libfastdds_statistics_backend.so*|libpinocchio*.so*|libcoal.so*) + continue + ;; + liburdfdom_model.so*|liburdfdom_model_state.so*|liburdfdom_sensor.so*|liburdfdom_world.so*) + continue + ;; + libgz-math*.so*|libgz-utils*.so*) + continue + ;; + esac + case "${lib}" in + /usr/local/lib/*) + copy_into_stage "${lib}" + ;; + *) + # Avoid bundling core distro libs from /lib and /usr/lib. + ;; + esac + done + } + + for p in /usr/local/lib/liburdfdom*.so*; do + for f in $p; do + [[ -e "${f}" ]] || continue + copy_into_stage "${f}" + done + done + + if [[ -d "${stage_dir}/usr/lib/dls2" ]]; then + while IFS= read -r sofile; do + copy_ldd_closure "${sofile}" + done < <(find "${stage_dir}/usr/lib/dls2" -type f -name '*.so*' | sort -u) + fi + if [[ -d "${stage_dir}/usr/bin/dls2" ]]; then + while IFS= read -r exe; do + copy_ldd_closure "${exe}" + done < <(find "${stage_dir}/usr/bin/dls2" -type f -perm -111 | sort -u) + fi + if [[ -x "${stage_dir}/usr/bin/dls" ]]; then + copy_ldd_closure "${stage_dir}/usr/bin/dls" + fi + + # Patch launcher script: + # - prioritize packaged runtime paths + # - make FastDDS cleanup best-effort + if [[ -f "${stage_dir}/usr/bin/dls" ]]; then + awk ' + NR == 1 { + print + print "export LD_LIBRARY_PATH=\"/opt/ros/jazzy/lib/x86_64-linux-gnu:/usr/local/lib:/usr/lib:${LD_LIBRARY_PATH:-}\"" + next + } + /fastdds shm clean/ { + print "command -v fastdds >/dev/null 2>&1 && fastdds shm clean > /dev/null 2>/dev/null || true" + print + next + } + { print } + ' "${stage_dir}/usr/bin/dls" > "${stage_dir}/usr/bin/dls.tmp" + mv "${stage_dir}/usr/bin/dls.tmp" "${stage_dir}/usr/bin/dls" + chmod +x "${stage_dir}/usr/bin/dls" + fi + + mkdir -p "${stage_dir}/etc/profile.d" "${stage_dir}/DEBIAN" + cat > "${stage_dir}/etc/profile.d/dls2.sh" << "EOPROFILE" +#!/bin/sh +export GZ_SIM_RESOURCE_PATH="/usr/local/share/dls-gazebo/worlds" +export DLS_SERVERS_PATH="/usr/include/dls2/util/messaging/servers.yaml" +export DLS_SAFETY_LAYER_PATH="/usr/include/dls2/supervisor/data/safety_layer.yaml" +export DLS_SCHEDULER_PATH="/usr/include/dls2/schedulers" +EOPROFILE + chmod +x "${stage_dir}/etc/profile.d/dls2.sh" + + cat > "${stage_dir}/DEBIAN/control" << EOCONTROL +Package: ${PACKAGE_NAME} +Version: ${DEB_CONTROL_VERSION} +Section: base +Priority: optional +Architecture: amd64 +Maintainer: ${MAINTAINER} +Depends: ${DEB_DEPENDS} +Description: ${PACKAGE_DESCRIPTION} +EOCONTROL + + cat > "${stage_dir}/DEBIAN/postinst" << 'EOPOSTINST' +#!/bin/sh +set -e + +if command -v setcap >/dev/null 2>&1; then + setcap cap_sys_nice=eip /usr/bin/dls2/dynamic_legged_systems_framework || true + setcap cap_sys_nice=eip /usr/bin/dls2/child_process_launcher || true +fi + +if command -v ldconfig >/dev/null 2>&1; then + ldconfig || true +fi + +exit 0 +EOPOSTINST + chmod 0755 "${stage_dir}/DEBIAN/postinst" + + dpkg-deb --build "${stage_dir}" "${DEB_NAME}" + + dpkg-deb -c "${DEB_NAME}" \ + | awk ' + $1 !~ /^d/ { + for (i = 1; i <= NF; i++) { + if ($i ~ /^\.\//) { + print $i + break + } + } + } + ' \ + | sed -E 's#^\./#/#; s#/$##; s#//+#/#g' \ + | sort -u > "${ART_DIR}/pkg_files.txt" +} + +echo "[build] building and packaging on host in ${ROOT_DIR}" +if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then + if ! run_pipeline 2>&1 | tee "${BUILD_LOG}"; then + echo "ERROR: build/package failed. See ${BUILD_LOG}" + tail -n 120 "${BUILD_LOG}" || true + exit 1 + fi +else + if ! run_pipeline > "${BUILD_LOG}" 2>&1; then + echo "ERROR: build/package failed. See ${BUILD_LOG}" + tail -n 120 "${BUILD_LOG}" || true + exit 1 + fi +fi + +if [[ ! -f "${DEB_PATH}" ]]; then + echo "ERROR: .deb not created at ${DEB_PATH}" + echo "See ${BUILD_LOG}" + tail -n 120 "${BUILD_LOG}" || true + exit 1 +fi + +echo "[build] OK: ${DEB_PATH}" +echo "${DEB_PATH}" From 585b9a4a4caf0b4bef40facb07075ab88d89a662 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 08:50:41 +0200 Subject: [PATCH 02/31] testing commit only --- .github/workflows/create-release-deb.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index ffb0f02..a312de6 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -5,6 +5,8 @@ on: tags: - 'v*.*.*' - 'v*.*.*-rc*' + pull_request: + branches: [ "main" ] env: GNUTLS_CPUID_OVERRIDE: 0x1 From 6be99cbf29af34c01f53ce5a4ca9921a137163b2 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 08:58:00 +0200 Subject: [PATCH 03/31] dummy commit --- .github/workflows/create-release-deb.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index a312de6..dde517d 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -11,6 +11,7 @@ on: env: GNUTLS_CPUID_OVERRIDE: 0x1 + jobs: create-release-ci-cd: uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main From 3f090d90db63bb29e4a548a1cdf8c60fbd66a511 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 09:40:56 +0200 Subject: [PATCH 04/31] create-deb-deploy: install prefix fix --- scripts/create-deb-deploy.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index 6a0f7b1..dbdb715 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -79,6 +79,7 @@ run_pipeline() { local build_user_args=(${BUILD_ARGS}) cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/ \ "${CMAKE_DEPLOY_ARGS[@]}" \ "${cmake_user_args[@]}" @@ -89,7 +90,7 @@ run_pipeline() { fi # Expected setcap warnings during staged install are tolerated. - DESTDIR="${stage_dir}" cmake --install "${build_dir}" || true + DESTDIR="${stage_dir}" cmake --install "${build_dir}" # Ensure robot description assets are packaged when available. if [[ -d "${ROOT_DIR}/robots/aliengo/aliengo-description" ]]; then From ac894e62035a666204366bfcf099d693ae427649 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 09:48:30 +0200 Subject: [PATCH 05/31] barebone-specific deb creation fix --- .github/workflows/create-release-deb.yml | 13 +++--- scripts/create-deb-deploy.sh | 57 ++++++++++++------------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index dde517d..5ae5510 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -2,19 +2,20 @@ name: Create Release and .deb Files Project on: push: - tags: - - 'v*.*.*' - - 'v*.*.*-rc*' - pull_request: - branches: [ "main" ] + tags: + - 'v*.*.*' + - 'v*.*.*-rc*' env: GNUTLS_CPUID_OVERRIDE: 0x1 - jobs: create-release-ci-cd: + permissions: + contents: write + packages: write uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" deb-script-path: "scripts/create-deb-deploy.sh" + secrets: inherit diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index dbdb715..e29b539 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -59,6 +59,14 @@ done mkdir -p "${ART_DIR}" rm -f "${DEB_PATH}" "${ART_DIR}/pkg_files.txt" "${BUILD_LOG}" +for required_dir in dls2 robotlib gluecode; do + if [[ ! -f "${ROOT_DIR}/${required_dir}/CMakeLists.txt" ]]; then + echo "ERROR: missing ${required_dir}/CMakeLists.txt under ${ROOT_DIR}." + echo "Hint: submodules are not checked out on this runner." + exit 1 + fi +done + run_pipeline() { local build_dir="${ROOT_DIR}/build" local stage_dir="${ROOT_DIR}/.deb_stage" @@ -89,19 +97,8 @@ run_pipeline() { cmake --build "${build_dir}" -- "${build_user_args[@]}" fi - # Expected setcap warnings during staged install are tolerated. DESTDIR="${stage_dir}" cmake --install "${build_dir}" - # Ensure robot description assets are packaged when available. - if [[ -d "${ROOT_DIR}/robots/aliengo/aliengo-description" ]]; then - mkdir -p "${stage_dir}/usr/include/aliengo_description" - for dir in gazebo launch meshes robcogen robots rviz urdfs yarf foxglove default_postures kinematics; do - if [[ -d "${ROOT_DIR}/robots/aliengo/aliengo-description/${dir}" ]]; then - cp -a "${ROOT_DIR}/robots/aliengo/aliengo-description/${dir}" "${stage_dir}/usr/include/aliengo_description/" - fi - done - fi - strip "${stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true strip "${stage_dir}/usr/bin/dls2/child_process_launcher" || true strip "${stage_dir}/usr/lib/librobotlib.so" || true @@ -128,7 +125,7 @@ run_pipeline() { [[ -e "${target}" ]] || return 0 (ldd "${target}" 2>/dev/null || true) \ | awk ' - /=> \// {print $3} + /=> \/ {print $3} /^\// {print $1} ' \ | sort -u \ @@ -150,7 +147,6 @@ run_pipeline() { copy_into_stage "${lib}" ;; *) - # Avoid bundling core distro libs from /lib and /usr/lib. ;; esac done @@ -177,9 +173,6 @@ run_pipeline() { copy_ldd_closure "${stage_dir}/usr/bin/dls" fi - # Patch launcher script: - # - prioritize packaged runtime paths - # - make FastDDS cleanup best-effort if [[ -f "${stage_dir}/usr/bin/dls" ]]; then awk ' NR == 1 { @@ -224,8 +217,12 @@ EOCONTROL set -e if command -v setcap >/dev/null 2>&1; then - setcap cap_sys_nice=eip /usr/bin/dls2/dynamic_legged_systems_framework || true - setcap cap_sys_nice=eip /usr/bin/dls2/child_process_launcher || true + if [ -f /usr/bin/dls2/dynamic_legged_systems_framework ]; then + setcap cap_sys_nice=eip /usr/bin/dls2/dynamic_legged_systems_framework || true + fi + if [ -f /usr/bin/dls2/child_process_launcher ]; then + setcap cap_sys_nice=eip /usr/bin/dls2/child_process_launcher || true + fi fi if command -v ldconfig >/dev/null 2>&1; then @@ -255,17 +252,21 @@ EOPOSTINST echo "[build] building and packaging on host in ${ROOT_DIR}" if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then - if ! run_pipeline 2>&1 | tee "${BUILD_LOG}"; then - echo "ERROR: build/package failed. See ${BUILD_LOG}" - tail -n 120 "${BUILD_LOG}" || true - exit 1 - fi + set +e + run_pipeline > >(tee "${BUILD_LOG}") 2>&1 + rc=$? + set -e else - if ! run_pipeline > "${BUILD_LOG}" 2>&1; then - echo "ERROR: build/package failed. See ${BUILD_LOG}" - tail -n 120 "${BUILD_LOG}" || true - exit 1 - fi + set +e + run_pipeline > "${BUILD_LOG}" 2>&1 + rc=$? + set -e +fi + +if [[ ${rc} -ne 0 ]]; then + echo "ERROR: build/package failed. See ${BUILD_LOG}" + tail -n 120 "${BUILD_LOG}" || true + exit ${rc} fi if [[ ! -f "${DEB_PATH}" ]]; then From 92924332a09ed89b221eb810c46066c8a1da674f Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 09:50:27 +0200 Subject: [PATCH 06/31] fixup! barebone-specific deb creation fix --- .github/workflows/create-release-deb.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 5ae5510..dc271e6 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -11,9 +11,6 @@ env: jobs: create-release-ci-cd: - permissions: - contents: write - packages: write uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" From 3d0d23c948e372c6b8e172d850346016d3048d49 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 09:54:52 +0200 Subject: [PATCH 07/31] fixup! fixup! barebone-specific deb creation fix --- .github/workflows/create-release-deb.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index dc271e6..166113c 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -15,4 +15,5 @@ jobs: with: package-name: "dls2" deb-script-path: "scripts/create-deb-deploy.sh" - secrets: inherit + secrets: + CICD_PAT: ${{ secrets.CICD_PAT }} From 0da1e63febaf8990be3b88aee9e8891b8333c0b2 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 10:07:00 +0200 Subject: [PATCH 08/31] create-release-deb: docker image provided --- .github/workflows/create-release-deb.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 166113c..803496a 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -15,5 +15,6 @@ jobs: with: package-name: "dls2" deb-script-path: "scripts/create-deb-deploy.sh" + container: "ghcr.io/iit-dlslab/dls2-dev:latest" secrets: - CICD_PAT: ${{ secrets.CICD_PAT }} + CICD_PAT: ${{ secrets.CICD_PAT }} From e1379d930ba3c6a4a322fab9e16a476c3f6e99e9 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Fri, 3 Apr 2026 10:32:55 +0200 Subject: [PATCH 09/31] create-deb-deploy: cleanup stage rm --- scripts/create-deb-deploy.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index e29b539..634681a 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -71,11 +71,6 @@ run_pipeline() { local build_dir="${ROOT_DIR}/build" local stage_dir="${ROOT_DIR}/.deb_stage" - cleanup_stage() { - rm -rf "${stage_dir}" "${ROOT_DIR}/stage" - } - trap cleanup_stage EXIT - if [[ "${CLEAN_BUILD}" == "1" ]]; then rm -rf "${build_dir}" fi From 550cccbfaf18c0f043810468ad8fccba48c17544 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Mon, 20 Apr 2026 09:57:07 +0200 Subject: [PATCH 10/31] create-deb-deploy: include headers flag added --- scripts/create-deb-deploy.sh | 86 ++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index 634681a..c8b5848 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -17,6 +17,52 @@ ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" ART_DIR="${ROOT_DIR}/deb_pipeline_artifacts" BUILD_LOG="${ART_DIR}/build.log" +usage() { + cat <<'EOF' +Usage: create-deb-deploy.sh [--with-headers | --without-headers] + +Options: + --with-headers Keep installed header files in the generated .deb. + --without-headers Exclude installed *.h, *.hpp, and *.tpp files from the .deb. + -h, --help Show this help message. + +Environment: + INCLUDE_HEADERS=1|0 Default header inclusion mode when no CLI flag is passed. +EOF +} + +INCLUDE_HEADERS="${INCLUDE_HEADERS:-1}" +while [[ $# -gt 0 ]]; do + case "$1" in + --with-headers) + INCLUDE_HEADERS="1" + shift + ;; + --without-headers) + INCLUDE_HEADERS="0" + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "ERROR: unknown argument '$1'" + usage + exit 1 + ;; + esac +done + +case "${INCLUDE_HEADERS}" in + 0|1) + ;; + *) + echo "ERROR: INCLUDE_HEADERS must be 0 or 1, got '${INCLUDE_HEADERS}'" + exit 1 + ;; +esac + VERSION="${VERSION_OVERRIDE:-0.0.0-local}" DEB_CONTROL_VERSION="$(echo "${VERSION}" | sed -E 's/^[^0-9]*//')" if [[ -z "${DEB_CONTROL_VERSION}" ]]; then @@ -27,7 +73,7 @@ fi PACKAGE_NAME="${PACKAGE_NAME:-dls2}" MAINTAINER="${DEB_MAINTAINER:-Michele Pestarino }" PACKAGE_DESCRIPTION="${DEB_DESCRIPTION:-DLS2 runtime package}" -DEB_DEPENDS="${DEB_DEPENDS:-python3, python3-psutil, libyaml-cpp0.8, libtinyxml2-10, libgtk-3-0, libcairo2, libglib2.0-0, libboost-filesystem1.83.0, libconsole-bridge1.0, libcap2-bin}" +DEB_DEPENDS="${DEB_DEPENDS:-python3, python3-psutil, libyaml-cpp0.8, libtinyxml2-10, libgtk-3-0t64 | libgtk-3-0, libcairo2, libglib2.0-0t64 | libglib2.0-0, libboost-filesystem1.83.0, libconsole-bridge1.0, libcap2-bin}" DEB_NAME="${PACKAGE_NAME}_${VERSION}_amd64.deb" DEB_PATH="${ROOT_DIR}/${DEB_NAME}" @@ -94,6 +140,13 @@ run_pipeline() { DESTDIR="${stage_dir}" cmake --install "${build_dir}" + if [[ "${INCLUDE_HEADERS}" == "0" && -d "${stage_dir}/usr/include" ]]; then + find "${stage_dir}/usr/include" -type f \ + \( -name '*.h' -o -name '*.hpp' -o -name '*.tpp' \) \ + -delete + find "${stage_dir}/usr/include" -depth -type d -empty -delete + fi + strip "${stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true strip "${stage_dir}/usr/bin/dls2/child_process_launcher" || true strip "${stage_dir}/usr/lib/librobotlib.so" || true @@ -228,6 +281,18 @@ exit 0 EOPOSTINST chmod 0755 "${stage_dir}/DEBIAN/postinst" + if ! find "${stage_dir}" -mindepth 1 \ + ! -path "${stage_dir}/DEBIAN" \ + ! -path "${stage_dir}/DEBIAN/*" \ + ! -path "${stage_dir}/etc" \ + ! -path "${stage_dir}/etc/profile.d" \ + ! -path "${stage_dir}/etc/profile.d/dls2.sh" \ + -print -quit | grep -q .; then + echo "ERROR: staged package payload is empty." + echo "Hint: cmake configure/build/install likely failed earlier, or the build cache points to a different source tree." + return 1 + fi + dpkg-deb --build "${stage_dir}" "${DEB_NAME}" dpkg-deb -c "${DEB_NAME}" \ @@ -246,16 +311,19 @@ EOPOSTINST } echo "[build] building and packaging on host in ${ROOT_DIR}" +echo "[build] include headers: ${INCLUDE_HEADERS}" if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then - set +e - run_pipeline > >(tee "${BUILD_LOG}") 2>&1 - rc=$? - set -e + if run_pipeline > >(tee "${BUILD_LOG}") 2>&1; then + rc=0 + else + rc=$? + fi else - set +e - run_pipeline > "${BUILD_LOG}" 2>&1 - rc=$? - set -e + if run_pipeline > "${BUILD_LOG}" 2>&1; then + rc=0 + else + rc=$? + fi fi if [[ ${rc} -ne 0 ]]; then From c349bafaadaa7856049cc4a5febab8580aad46d5 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Mon, 20 Apr 2026 17:09:01 +0200 Subject: [PATCH 11/31] create-release-deb: updated top-level workflow file --- .github/workflows/create-release-deb.yml | 35 +++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 803496a..0ec9f8b 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -9,8 +9,22 @@ on: env: GNUTLS_CPUID_OVERRIDE: 0x1 +permissions: + contents: write + packages: write + id-token: write + jobs: - create-release-ci-cd: + + build_test: + uses: iit-DLSLab/cicd_tools/.github/workflows/dls2_build_test.yml@main + with: + test-command: "ls" + secrets: + GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} + CICD_PAT: ${{ secrets.CICD_PAT }} + + release_deb: uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" @@ -18,3 +32,22 @@ jobs: container: "ghcr.io/iit-dlslab/dls2-dev:latest" secrets: CICD_PAT: ${{ secrets.CICD_PAT }} + + publish_image: + needs: release_deb + uses: iit-DLSLab/cicd_tools/.github/workflows/docker-publish.yml@main + with: + image_name: dls2-dev-deb + registry: ghcr.io + context: external-docker/dockerfiles/dls2-dev-deb + dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile + tag_override: ${{ needs.release_deb.outputs.version_tag }} + workflow_artifact_name: ${{ needs.release_deb.outputs.deb_workflow_artifact_name }} + artifact_download_path: external-docker/dockerfiles/dls2-dev-deb + extra_checkout_repository: iit-DLSLab/dls_docker + extra_checkout_ref: main + extra_checkout_path: external-docker + extra_build_args: | + DLS2_DEB_FILE=${{ needs.release_deb.outputs.deb_artifact_name }} + secrets: + CICD_PAT: ${{ secrets.CICD_PAT }} From 0a619ab9f1276cffa190337224489b97d6fc1339 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 10:47:13 +0200 Subject: [PATCH 12/31] create-deb-deploy: cleanup due to base image switch --- scripts/create-deb-deploy.sh | 101 ++++------------------------------- 1 file changed, 10 insertions(+), 91 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index c8b5848..55f30eb 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -84,24 +84,6 @@ CLEAN_BUILD="${CLEAN_BUILD:-0}" CMAKE_ARGS="${CMAKE_ARGS:-}" BUILD_ARGS="${BUILD_ARGS:--j${JOBS}}" -DEPLOY_FLAGS=( - DLS_DEPLOY_gazebo_sim - DLS_DEPLOY_pid_controller - DLS_DEPLOY_periodic_generator - DLS_DEPLOY_foot_traj_generator - DLS_DEPLOY_gait_timer - DLS_DEPLOY_terrain_estimator - DLS_DEPLOY_trunk_controller - DLS_DEPLOY_dls_keyboard - DLS_DEPLOY_dls_gamepad -) - -CMAKE_DEPLOY_ARGS=() -for flag in "${DEPLOY_FLAGS[@]}"; do - value="${!flag:-ON}" - CMAKE_DEPLOY_ARGS+=("-D${flag}=${value}") -done - mkdir -p "${ART_DIR}" rm -f "${DEB_PATH}" "${ART_DIR}/pkg_files.txt" "${BUILD_LOG}" @@ -129,7 +111,6 @@ run_pipeline() { cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/ \ - "${CMAKE_DEPLOY_ARGS[@]}" \ "${cmake_user_args[@]}" if [[ "${BUILD_VERBOSE}" == "1" ]]; then @@ -151,86 +132,24 @@ run_pipeline() { strip "${stage_dir}/usr/bin/dls2/child_process_launcher" || true strip "${stage_dir}/usr/lib/librobotlib.so" || true - copy_into_stage() { - local src="$1" - local dst="${stage_dir}${src}" - [[ -f "${src}" ]] || return 0 - mkdir -p "$(dirname "${dst}")" - if [[ -L "${src}" ]]; then - cp -a --no-dereference "${src}" "${dst}" - local resolved - resolved="$(readlink -f "${src}" || true)" - if [[ -n "${resolved}" && "${resolved}" != "${src}" && -f "${resolved}" ]]; then - copy_into_stage "${resolved}" - fi - else - cp -a "${src}" "${dst}" - fi - } - - copy_ldd_closure() { - local target="$1" - [[ -e "${target}" ]] || return 0 - (ldd "${target}" 2>/dev/null || true) \ - | awk ' - /=> \/ {print $3} - /^\// {print $1} - ' \ - | sort -u \ - | while IFS= read -r lib; do - [[ -f "${lib}" ]] || continue - case "$(basename "${lib}")" in - libfastdds.so*|libfastcdr.so*|libfastdds_statistics_backend.so*|libpinocchio*.so*|libcoal.so*) - continue - ;; - liburdfdom_model.so*|liburdfdom_model_state.so*|liburdfdom_sensor.so*|liburdfdom_world.so*) - continue - ;; - libgz-math*.so*|libgz-utils*.so*) - continue - ;; - esac - case "${lib}" in - /usr/local/lib/*) - copy_into_stage "${lib}" - ;; - *) - ;; - esac - done - } - - for p in /usr/local/lib/liburdfdom*.so*; do - for f in $p; do - [[ -e "${f}" ]] || continue - copy_into_stage "${f}" - done - done - - if [[ -d "${stage_dir}/usr/lib/dls2" ]]; then - while IFS= read -r sofile; do - copy_ldd_closure "${sofile}" - done < <(find "${stage_dir}/usr/lib/dls2" -type f -name '*.so*' | sort -u) - fi - if [[ -d "${stage_dir}/usr/bin/dls2" ]]; then - while IFS= read -r exe; do - copy_ldd_closure "${exe}" - done < <(find "${stage_dir}/usr/bin/dls2" -type f -perm -111 | sort -u) - fi - if [[ -x "${stage_dir}/usr/bin/dls" ]]; then - copy_ldd_closure "${stage_dir}/usr/bin/dls" - fi - if [[ -f "${stage_dir}/usr/bin/dls" ]]; then awk ' NR == 1 { print - print "export LD_LIBRARY_PATH=\"/opt/ros/jazzy/lib/x86_64-linux-gnu:/usr/local/lib:/usr/lib:${LD_LIBRARY_PATH:-}\"" + print "export LD_LIBRARY_PATH=\"/opt/ros/jazzy/lib/x86_64-linux-gnu:/usr/local/lib:/usr/lib:/usr/lib/dls2:/usr/lib/dls2/motion_generators:/usr/lib/dls2/controllers:/usr/lib/dls2/estimators:/usr/lib/dls2/messages:${LD_LIBRARY_PATH:-}\"" + print "export DLS_SERVERS_PATH=\"${DLS_SERVERS_PATH:-/usr/include/dls2/util/messaging/servers.yaml}\"" + print "export DLS_SAFETY_LAYER_PATH=\"${DLS_SAFETY_LAYER_PATH:-/usr/include/dls2/supervisor/data/safety_layer.yaml}\"" + print "export DLS_SCHEDULER_PATH=\"${DLS_SCHEDULER_PATH:-/usr/include/dls2/schedulers}\"" + print "export GZ_SIM_RESOURCE_PATH=\"${GZ_SIM_RESOURCE_PATH:-/usr/local/share/dls-gazebo/worlds}\"" next } /fastdds shm clean/ { print "command -v fastdds >/dev/null 2>&1 && fastdds shm clean > /dev/null 2>/dev/null || true" - print + next + } + /dynamic_legged_systems_framework / { + sub(/^[[:space:]]*/, "") + print "exec " $0 next } { print } From bb297f1c2c7eb11be4b136083fee633b051e5592 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 11:13:26 +0200 Subject: [PATCH 13/31] gluecode: submodule update --- gluecode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gluecode b/gluecode index 5c72480..6a4240d 160000 --- a/gluecode +++ b/gluecode @@ -1 +1 @@ -Subproject commit 5c7248011b17b410989462a46ccd218fb9b3485e +Subproject commit 6a4240d208987a088571df8014cd147f4005b7c4 From 4b26c4774a3f631813820259dfed134869990967 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 12:00:10 +0200 Subject: [PATCH 14/31] create-deb-deploy: skipping build if compiled code is available --- scripts/create-deb-deploy.sh | 48 ++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index 55f30eb..4ce6eb5 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -27,11 +27,13 @@ Options: -h, --help Show this help message. Environment: - INCLUDE_HEADERS=1|0 Default header inclusion mode when no CLI flag is passed. + INCLUDE_HEADERS=1|0 Default header inclusion mode when no CLI flag is passed. + REUSE_BUILD=auto|1|0 Reuse an existing build directory when possible. Defaults to auto. EOF } INCLUDE_HEADERS="${INCLUDE_HEADERS:-1}" +REUSE_BUILD="${REUSE_BUILD:-auto}" while [[ $# -gt 0 ]]; do case "$1" in --with-headers) @@ -63,6 +65,15 @@ case "${INCLUDE_HEADERS}" in ;; esac +case "${REUSE_BUILD}" in + auto|0|1) + ;; + *) + echo "ERROR: REUSE_BUILD must be auto, 0, or 1, got '${REUSE_BUILD}'" + exit 1 + ;; +esac + VERSION="${VERSION_OVERRIDE:-0.0.0-local}" DEB_CONTROL_VERSION="$(echo "${VERSION}" | sed -E 's/^[^0-9]*//')" if [[ -z "${DEB_CONTROL_VERSION}" ]]; then @@ -98,6 +109,7 @@ done run_pipeline() { local build_dir="${ROOT_DIR}/build" local stage_dir="${ROOT_DIR}/.deb_stage" + local reuse_existing_build="0" if [[ "${CLEAN_BUILD}" == "1" ]]; then rm -rf "${build_dir}" @@ -109,14 +121,35 @@ run_pipeline() { # shellcheck disable=SC2206 local build_user_args=(${BUILD_ARGS}) - cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/ \ - "${cmake_user_args[@]}" + if [[ "${CLEAN_BUILD}" != "1" && -f "${build_dir}/CMakeCache.txt" ]]; then + case "${REUSE_BUILD}" in + auto|1) + reuse_existing_build="1" + ;; + 0) + ;; + esac + fi + + if [[ "${REUSE_BUILD}" == "1" && "${reuse_existing_build}" != "1" ]]; then + echo "ERROR: REUSE_BUILD=1 was requested, but no reusable build cache was found in ${build_dir}." + echo "Hint: provide a prebuilt build/ artifact or set REUSE_BUILD=auto or 0." + return 1 + fi - if [[ "${BUILD_VERBOSE}" == "1" ]]; then - cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose + if [[ "${reuse_existing_build}" == "1" ]]; then + echo "[build] reusing existing build directory: ${build_dir}" else - cmake --build "${build_dir}" -- "${build_user_args[@]}" + echo "[build] configuring and compiling in: ${build_dir}" + cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/ \ + "${cmake_user_args[@]}" + + if [[ "${BUILD_VERBOSE}" == "1" ]]; then + cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose + else + cmake --build "${build_dir}" -- "${build_user_args[@]}" + fi fi DESTDIR="${stage_dir}" cmake --install "${build_dir}" @@ -231,6 +264,7 @@ EOPOSTINST echo "[build] building and packaging on host in ${ROOT_DIR}" echo "[build] include headers: ${INCLUDE_HEADERS}" +echo "[build] reuse build: ${REUSE_BUILD}" if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then if run_pipeline > >(tee "${BUILD_LOG}") 2>&1; then rc=0 From e2dc657d2cf3120641abca117d9beec938340160 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 12:05:53 +0200 Subject: [PATCH 15/31] create-release-deb: build artifact usage added --- .github/workflows/create-release-deb.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 0ec9f8b..b084e81 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -20,16 +20,19 @@ jobs: uses: iit-DLSLab/cicd_tools/.github/workflows/dls2_build_test.yml@main with: test-command: "ls" + output_workflow_artifact_name: build secrets: GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} CICD_PAT: ${{ secrets.CICD_PAT }} release_deb: + needs: build_test uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" deb-script-path: "scripts/create-deb-deploy.sh" container: "ghcr.io/iit-dlslab/dls2-dev:latest" + workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} secrets: CICD_PAT: ${{ secrets.CICD_PAT }} From 4e777786bc534957b663beb2bfa6964f91410bf1 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 13:57:54 +0200 Subject: [PATCH 16/31] create-release-deb: dockerfile update in docker-publish args --- .github/workflows/create-release-deb.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index b084e81..c395643 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -43,7 +43,7 @@ jobs: image_name: dls2-dev-deb registry: ghcr.io context: external-docker/dockerfiles/dls2-dev-deb - dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile + dockerfile: Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} workflow_artifact_name: ${{ needs.release_deb.outputs.deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb From 6e37b6f8b24133a701c475679456bbac7b326fec Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 14:25:23 +0200 Subject: [PATCH 17/31] create-deb-deploy: always-double deb creation added --- scripts/create-deb-deploy.sh | 190 ++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 81 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index 4ce6eb5..698bcc7 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -19,31 +19,19 @@ BUILD_LOG="${ART_DIR}/build.log" usage() { cat <<'EOF' -Usage: create-deb-deploy.sh [--with-headers | --without-headers] +Usage: create-deb-deploy.sh Options: - --with-headers Keep installed header files in the generated .deb. - --without-headers Exclude installed *.h, *.hpp, and *.tpp files from the .deb. -h, --help Show this help message. Environment: - INCLUDE_HEADERS=1|0 Default header inclusion mode when no CLI flag is passed. REUSE_BUILD=auto|1|0 Reuse an existing build directory when possible. Defaults to auto. EOF } -INCLUDE_HEADERS="${INCLUDE_HEADERS:-1}" REUSE_BUILD="${REUSE_BUILD:-auto}" while [[ $# -gt 0 ]]; do case "$1" in - --with-headers) - INCLUDE_HEADERS="1" - shift - ;; - --without-headers) - INCLUDE_HEADERS="0" - shift - ;; -h|--help) usage exit 0 @@ -56,15 +44,6 @@ while [[ $# -gt 0 ]]; do esac done -case "${INCLUDE_HEADERS}" in - 0|1) - ;; - *) - echo "ERROR: INCLUDE_HEADERS must be 0 or 1, got '${INCLUDE_HEADERS}'" - exit 1 - ;; -esac - case "${REUSE_BUILD}" in auto|0|1) ;; @@ -83,11 +62,16 @@ fi PACKAGE_NAME="${PACKAGE_NAME:-dls2}" MAINTAINER="${DEB_MAINTAINER:-Michele Pestarino }" -PACKAGE_DESCRIPTION="${DEB_DESCRIPTION:-DLS2 runtime package}" +RUNTIME_PACKAGE_NAME="${PACKAGE_NAME}-runtime" +FRAMEWORK_PACKAGE_NAME="${PACKAGE_NAME}-framework" +RUNTIME_PACKAGE_DESCRIPTION="${DEB_RUNTIME_DESCRIPTION:-DLS2 runtime package}" +FRAMEWORK_PACKAGE_DESCRIPTION="${DEB_FRAMEWORK_DESCRIPTION:-DLS2 framework package}" DEB_DEPENDS="${DEB_DEPENDS:-python3, python3-psutil, libyaml-cpp0.8, libtinyxml2-10, libgtk-3-0t64 | libgtk-3-0, libcairo2, libglib2.0-0t64 | libglib2.0-0, libboost-filesystem1.83.0, libconsole-bridge1.0, libcap2-bin}" -DEB_NAME="${PACKAGE_NAME}_${VERSION}_amd64.deb" -DEB_PATH="${ROOT_DIR}/${DEB_NAME}" +RUNTIME_DEB_NAME="${RUNTIME_PACKAGE_NAME}_${VERSION}_amd64.deb" +FRAMEWORK_DEB_NAME="${FRAMEWORK_PACKAGE_NAME}_${VERSION}_amd64.deb" +RUNTIME_DEB_PATH="${ROOT_DIR}/${RUNTIME_DEB_NAME}" +FRAMEWORK_DEB_PATH="${ROOT_DIR}/${FRAMEWORK_DEB_NAME}" JOBS="${JOBS:-4}" LIVE_BUILD_OUTPUT="${LIVE_BUILD_OUTPUT:-0}" BUILD_VERBOSE="${BUILD_VERBOSE:-0}" @@ -96,7 +80,12 @@ CMAKE_ARGS="${CMAKE_ARGS:-}" BUILD_ARGS="${BUILD_ARGS:--j${JOBS}}" mkdir -p "${ART_DIR}" -rm -f "${DEB_PATH}" "${ART_DIR}/pkg_files.txt" "${BUILD_LOG}" +rm -f \ + "${RUNTIME_DEB_PATH}" \ + "${FRAMEWORK_DEB_PATH}" \ + "${ART_DIR}/pkg_files_runtime.txt" \ + "${ART_DIR}/pkg_files_framework.txt" \ + "${BUILD_LOG}" for required_dir in dls2 robotlib gluecode; do if [[ ! -f "${ROOT_DIR}/${required_dir}/CMakeLists.txt" ]]; then @@ -108,13 +97,13 @@ done run_pipeline() { local build_dir="${ROOT_DIR}/build" - local stage_dir="${ROOT_DIR}/.deb_stage" + local base_stage_dir="${ROOT_DIR}/.deb_stage" local reuse_existing_build="0" if [[ "${CLEAN_BUILD}" == "1" ]]; then rm -rf "${build_dir}" fi - rm -rf "${stage_dir}" + rm -rf "${base_stage_dir}" "${ROOT_DIR}/.deb_stage_runtime" "${ROOT_DIR}/.deb_stage_framework" # shellcheck disable=SC2206 local cmake_user_args=(${CMAKE_ARGS}) @@ -152,20 +141,13 @@ run_pipeline() { fi fi - DESTDIR="${stage_dir}" cmake --install "${build_dir}" + DESTDIR="${base_stage_dir}" cmake --install "${build_dir}" - if [[ "${INCLUDE_HEADERS}" == "0" && -d "${stage_dir}/usr/include" ]]; then - find "${stage_dir}/usr/include" -type f \ - \( -name '*.h' -o -name '*.hpp' -o -name '*.tpp' \) \ - -delete - find "${stage_dir}/usr/include" -depth -type d -empty -delete - fi - - strip "${stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true - strip "${stage_dir}/usr/bin/dls2/child_process_launcher" || true - strip "${stage_dir}/usr/lib/librobotlib.so" || true + strip "${base_stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true + strip "${base_stage_dir}/usr/bin/dls2/child_process_launcher" || true + strip "${base_stage_dir}/usr/lib/librobotlib.so" || true - if [[ -f "${stage_dir}/usr/bin/dls" ]]; then + if [[ -f "${base_stage_dir}/usr/bin/dls" ]]; then awk ' NR == 1 { print @@ -186,33 +168,38 @@ run_pipeline() { next } { print } - ' "${stage_dir}/usr/bin/dls" > "${stage_dir}/usr/bin/dls.tmp" - mv "${stage_dir}/usr/bin/dls.tmp" "${stage_dir}/usr/bin/dls" - chmod +x "${stage_dir}/usr/bin/dls" + ' "${base_stage_dir}/usr/bin/dls" > "${base_stage_dir}/usr/bin/dls.tmp" + mv "${base_stage_dir}/usr/bin/dls.tmp" "${base_stage_dir}/usr/bin/dls" + chmod +x "${base_stage_dir}/usr/bin/dls" fi - mkdir -p "${stage_dir}/etc/profile.d" "${stage_dir}/DEBIAN" - cat > "${stage_dir}/etc/profile.d/dls2.sh" << "EOPROFILE" + mkdir -p "${base_stage_dir}/etc/profile.d" + cat > "${base_stage_dir}/etc/profile.d/dls2.sh" << "EOPROFILE" #!/bin/sh export GZ_SIM_RESOURCE_PATH="/usr/local/share/dls-gazebo/worlds" export DLS_SERVERS_PATH="/usr/include/dls2/util/messaging/servers.yaml" export DLS_SAFETY_LAYER_PATH="/usr/include/dls2/supervisor/data/safety_layer.yaml" export DLS_SCHEDULER_PATH="/usr/include/dls2/schedulers" EOPROFILE - chmod +x "${stage_dir}/etc/profile.d/dls2.sh" - - cat > "${stage_dir}/DEBIAN/control" << EOCONTROL -Package: ${PACKAGE_NAME} + chmod +x "${base_stage_dir}/etc/profile.d/dls2.sh" + + write_package_metadata() { + local stage_dir="$1" + local package_name="$2" + local package_description="$3" + mkdir -p "${stage_dir}/DEBIAN" + cat > "${stage_dir}/DEBIAN/control" << EOCONTROL +Package: ${package_name} Version: ${DEB_CONTROL_VERSION} Section: base Priority: optional Architecture: amd64 Maintainer: ${MAINTAINER} Depends: ${DEB_DEPENDS} -Description: ${PACKAGE_DESCRIPTION} +Description: ${package_description} EOCONTROL - cat > "${stage_dir}/DEBIAN/postinst" << 'EOPOSTINST' + cat > "${stage_dir}/DEBIAN/postinst" << 'EOPOSTINST' #!/bin/sh set -e @@ -231,39 +218,76 @@ fi exit 0 EOPOSTINST - chmod 0755 "${stage_dir}/DEBIAN/postinst" - - if ! find "${stage_dir}" -mindepth 1 \ - ! -path "${stage_dir}/DEBIAN" \ - ! -path "${stage_dir}/DEBIAN/*" \ - ! -path "${stage_dir}/etc" \ - ! -path "${stage_dir}/etc/profile.d" \ - ! -path "${stage_dir}/etc/profile.d/dls2.sh" \ - -print -quit | grep -q .; then - echo "ERROR: staged package payload is empty." - echo "Hint: cmake configure/build/install likely failed earlier, or the build cache points to a different source tree." - return 1 - fi + chmod 0755 "${stage_dir}/DEBIAN/postinst" + } + + package_variant() { + local variant="$1" + local include_headers="$2" + local package_name="$3" + local package_description="$4" + local deb_name="$5" + local pkg_list_path="$6" + local stage_dir="${ROOT_DIR}/.deb_stage_${variant}" + + cp -a "${base_stage_dir}" "${stage_dir}" + + if [[ "${include_headers}" == "0" && -d "${stage_dir}/usr/include" ]]; then + find "${stage_dir}/usr/include" -type f \ + \( -name '*.h' -o -name '*.hpp' -o -name '*.tpp' \) \ + -delete + find "${stage_dir}/usr/include" -depth -type d -empty -delete + fi + + write_package_metadata "${stage_dir}" "${package_name}" "${package_description}" + + if ! find "${stage_dir}" -mindepth 1 \ + ! -path "${stage_dir}/DEBIAN" \ + ! -path "${stage_dir}/DEBIAN/*" \ + ! -path "${stage_dir}/etc" \ + ! -path "${stage_dir}/etc/profile.d" \ + ! -path "${stage_dir}/etc/profile.d/dls2.sh" \ + -print -quit | grep -q .; then + echo "ERROR: staged package payload is empty for ${variant}." + echo "Hint: cmake configure/build/install likely failed earlier, or the build cache points to a different source tree." + return 1 + fi - dpkg-deb --build "${stage_dir}" "${DEB_NAME}" + dpkg-deb --build "${stage_dir}" "${deb_name}" - dpkg-deb -c "${DEB_NAME}" \ - | awk ' - $1 !~ /^d/ { - for (i = 1; i <= NF; i++) { - if ($i ~ /^\.\//) { - print $i - break + dpkg-deb -c "${deb_name}" \ + | awk ' + $1 !~ /^d/ { + for (i = 1; i <= NF; i++) { + if ($i ~ /^\.\//) { + print $i + break + } } } - } - ' \ - | sed -E 's#^\./#/#; s#/$##; s#//+#/#g' \ - | sort -u > "${ART_DIR}/pkg_files.txt" + ' \ + | sed -E 's#^\./#/#; s#/$##; s#//+#/#g' \ + | sort -u > "${pkg_list_path}" + } + + package_variant \ + "runtime" \ + "0" \ + "${RUNTIME_PACKAGE_NAME}" \ + "${RUNTIME_PACKAGE_DESCRIPTION}" \ + "${RUNTIME_DEB_NAME}" \ + "${ART_DIR}/pkg_files_runtime.txt" + + package_variant \ + "framework" \ + "1" \ + "${FRAMEWORK_PACKAGE_NAME}" \ + "${FRAMEWORK_PACKAGE_DESCRIPTION}" \ + "${FRAMEWORK_DEB_NAME}" \ + "${ART_DIR}/pkg_files_framework.txt" } echo "[build] building and packaging on host in ${ROOT_DIR}" -echo "[build] include headers: ${INCLUDE_HEADERS}" echo "[build] reuse build: ${REUSE_BUILD}" if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then if run_pipeline > >(tee "${BUILD_LOG}") 2>&1; then @@ -285,12 +309,16 @@ if [[ ${rc} -ne 0 ]]; then exit ${rc} fi -if [[ ! -f "${DEB_PATH}" ]]; then - echo "ERROR: .deb not created at ${DEB_PATH}" +if [[ ! -f "${RUNTIME_DEB_PATH}" || ! -f "${FRAMEWORK_DEB_PATH}" ]]; then + echo "ERROR: expected .deb files were not created:" + echo " - ${RUNTIME_DEB_PATH}" + echo " - ${FRAMEWORK_DEB_PATH}" echo "See ${BUILD_LOG}" tail -n 120 "${BUILD_LOG}" || true exit 1 fi -echo "[build] OK: ${DEB_PATH}" -echo "${DEB_PATH}" +echo "[build] OK: ${RUNTIME_DEB_PATH}" +echo "[build] OK: ${FRAMEWORK_DEB_PATH}" +echo "${RUNTIME_DEB_PATH}" +echo "${FRAMEWORK_DEB_PATH}" From c02199878231294d8345c6b41ea848534b03f72c Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 14:40:22 +0200 Subject: [PATCH 18/31] create-release-deb: framework/runtime image created from debs --- .github/workflows/create-release-deb.yml | 34 +++++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index c395643..7b2f180 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -15,8 +15,7 @@ permissions: id-token: write jobs: - - build_test: + build_test: uses: iit-DLSLab/cicd_tools/.github/workflows/dls2_build_test.yml@main with: test-command: "ls" @@ -33,24 +32,45 @@ jobs: deb-script-path: "scripts/create-deb-deploy.sh" container: "ghcr.io/iit-dlslab/dls2-dev:latest" workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} + artifact_download_path: "." + secrets: + GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} + CICD_PAT: ${{ secrets.CICD_PAT }} + + publish_runtime_image: + needs: release_deb + uses: iit-DLSLab/cicd_tools/.github/workflows/docker-publish.yml@main + with: + image_name: dls2-runtime + registry: ghcr.io + context: external-docker/dockerfiles/dls2-dev-deb + dockerfile: Dockerfile + tag_override: ${{ needs.release_deb.outputs.version_tag }} + workflow_artifact_name: ${{ needs.release_deb.outputs.runtime_deb_workflow_artifact_name }} + artifact_download_path: external-docker/dockerfiles/dls2-dev-deb + extra_checkout_repository: iit-DLSLab/dls_docker + extra_checkout_ref: main + extra_checkout_path: external-docker + extra_build_args: | + DLS2_DEB_FILE=${{ needs.release_deb.outputs.runtime_deb_artifact_name }} secrets: - CICD_PAT: ${{ secrets.CICD_PAT }} + CICD_PAT: ${{ secrets.CICD_PAT }} - publish_image: + publish_framework_image: needs: release_deb uses: iit-DLSLab/cicd_tools/.github/workflows/docker-publish.yml@main with: - image_name: dls2-dev-deb + image_name: dls2-framework registry: ghcr.io context: external-docker/dockerfiles/dls2-dev-deb dockerfile: Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} - workflow_artifact_name: ${{ needs.release_deb.outputs.deb_workflow_artifact_name }} + workflow_artifact_name: ${{ needs.release_deb.outputs.framework_deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb extra_checkout_repository: iit-DLSLab/dls_docker extra_checkout_ref: main extra_checkout_path: external-docker extra_build_args: | - DLS2_DEB_FILE=${{ needs.release_deb.outputs.deb_artifact_name }} + DLS2_DEB_FILE=${{ needs.release_deb.outputs.framework_deb_artifact_name }} secrets: CICD_PAT: ${{ secrets.CICD_PAT }} From 9281f96b003c191875296ba93da06b6b4750e2c2 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 15:10:49 +0200 Subject: [PATCH 19/31] create-release-deb: tmp branch name change --- .github/workflows/create-release-deb.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 7b2f180..c082184 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -49,7 +49,7 @@ jobs: workflow_artifact_name: ${{ needs.release_deb.outputs.runtime_deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb extra_checkout_repository: iit-DLSLab/dls_docker - extra_checkout_ref: main + extra_checkout_ref: deb extra_checkout_path: external-docker extra_build_args: | DLS2_DEB_FILE=${{ needs.release_deb.outputs.runtime_deb_artifact_name }} @@ -68,7 +68,7 @@ jobs: workflow_artifact_name: ${{ needs.release_deb.outputs.framework_deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb extra_checkout_repository: iit-DLSLab/dls_docker - extra_checkout_ref: main + extra_checkout_ref: deb extra_checkout_path: external-docker extra_build_args: | DLS2_DEB_FILE=${{ needs.release_deb.outputs.framework_deb_artifact_name }} From 4007321526d565a7a40dd0520f02506214509071 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 15:45:56 +0200 Subject: [PATCH 20/31] create-release-deb: explicit dockerfile path --- .github/workflows/create-release-deb.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index c082184..52e18f2 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -44,7 +44,7 @@ jobs: image_name: dls2-runtime registry: ghcr.io context: external-docker/dockerfiles/dls2-dev-deb - dockerfile: Dockerfile + dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} workflow_artifact_name: ${{ needs.release_deb.outputs.runtime_deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb @@ -53,6 +53,7 @@ jobs: extra_checkout_path: external-docker extra_build_args: | DLS2_DEB_FILE=${{ needs.release_deb.outputs.runtime_deb_artifact_name }} + force_latest_tag: true secrets: CICD_PAT: ${{ secrets.CICD_PAT }} @@ -63,7 +64,7 @@ jobs: image_name: dls2-framework registry: ghcr.io context: external-docker/dockerfiles/dls2-dev-deb - dockerfile: Dockerfile + dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} workflow_artifact_name: ${{ needs.release_deb.outputs.framework_deb_workflow_artifact_name }} artifact_download_path: external-docker/dockerfiles/dls2-dev-deb @@ -72,5 +73,6 @@ jobs: extra_checkout_path: external-docker extra_build_args: | DLS2_DEB_FILE=${{ needs.release_deb.outputs.framework_deb_artifact_name }} + force_latest_tag: true secrets: CICD_PAT: ${{ secrets.CICD_PAT }} From 42ab889c07d8d418229139b40b9a43eba4e7b103 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 17:31:31 +0200 Subject: [PATCH 21/31] create-release-deb: artifact_download_path update --- .github/workflows/create-release-deb.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 52e18f2..003e075 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -47,7 +47,7 @@ jobs: dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} workflow_artifact_name: ${{ needs.release_deb.outputs.runtime_deb_workflow_artifact_name }} - artifact_download_path: external-docker/dockerfiles/dls2-dev-deb + artifact_download_path: external-docker/dockerfiles/dls2-dev-deb/artifacts extra_checkout_repository: iit-DLSLab/dls_docker extra_checkout_ref: deb extra_checkout_path: external-docker @@ -67,7 +67,7 @@ jobs: dockerfile: external-docker/dockerfiles/dls2-dev-deb/Dockerfile tag_override: ${{ needs.release_deb.outputs.version_tag }} workflow_artifact_name: ${{ needs.release_deb.outputs.framework_deb_workflow_artifact_name }} - artifact_download_path: external-docker/dockerfiles/dls2-dev-deb + artifact_download_path: external-docker/dockerfiles/dls2-dev-deb/artifacts extra_checkout_repository: iit-DLSLab/dls_docker extra_checkout_ref: deb extra_checkout_path: external-docker From 65109b1b5cec651e649b53bf7c5589d686168f90 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Tue, 21 Apr 2026 17:40:13 +0200 Subject: [PATCH 22/31] create-deb-deploy: general script --- scripts/create-deb-deploy.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index 698bcc7..f33d7ba 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -87,7 +87,28 @@ rm -f \ "${ART_DIR}/pkg_files_framework.txt" \ "${BUILD_LOG}" -for required_dir in dls2 robotlib gluecode; do +readarray -t required_dirs < <( + awk ' + match($0, /^[[:space:]]*add_subdirectory[[:space:]]*\(([[:space:]]*"[^"]+"|[[:space:]]*[^#)[:space:]]+)/) { + dir = substr($0, RSTART, RLENGTH) + sub(/^[[:space:]]*add_subdirectory[[:space:]]*\(/, "", dir) + sub(/^[[:space:]]+/, "", dir) + sub(/^"/, "", dir) + sub(/"$/, "", dir) + sub(/[[:space:]].*$/, "", dir) + if (dir !~ /^\$/ && dir !~ /^\// && dir !~ /\.\./) { + print dir + } + } + ' "${ROOT_DIR}/CMakeLists.txt" | sort -u +) + +if [[ ${#required_dirs[@]} -eq 0 ]]; then + echo "ERROR: could not infer required source directories from ${ROOT_DIR}/CMakeLists.txt." + exit 1 +fi + +for required_dir in "${required_dirs[@]}"; do if [[ ! -f "${ROOT_DIR}/${required_dir}/CMakeLists.txt" ]]; then echo "ERROR: missing ${required_dir}/CMakeLists.txt under ${ROOT_DIR}." echo "Hint: submodules are not checked out on this runner." From f44118a16992d15def0e50921bde45ad07529514 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Wed, 22 Apr 2026 11:31:43 +0200 Subject: [PATCH 23/31] create-release-deb: using builtin deb creation script --- .github/workflows/create-release-deb.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 003e075..4a7e42c 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -29,7 +29,8 @@ jobs: uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" - deb-script-path: "scripts/create-deb-deploy.sh" + deb-script-source: builtin + builtin-deb-script-path: scripts/create-deb-deploy.sh container: "ghcr.io/iit-dlslab/dls2-dev:latest" workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} artifact_download_path: "." From 1cf88574791bf1e761515953a3a07020377ad47c Mon Sep 17 00:00:00 2001 From: mich-pest Date: Wed, 22 Apr 2026 13:56:37 +0200 Subject: [PATCH 24/31] create-release-deb: trying caller general deb creation script, deb validation step added --- .github/workflows/create-release-deb.yml | 43 +++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 4a7e42c..9672a61 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -29,8 +29,7 @@ jobs: uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" - deb-script-source: builtin - builtin-deb-script-path: scripts/create-deb-deploy.sh + deb-script-source: caller container: "ghcr.io/iit-dlslab/dls2-dev:latest" workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} artifact_download_path: "." @@ -38,8 +37,42 @@ jobs: GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} CICD_PAT: ${{ secrets.CICD_PAT }} - publish_runtime_image: + validate_deb: needs: release_deb + runs-on: ubuntu-24.04 + steps: + - name: Download runtime .deb artifact + uses: actions/download-artifact@v4 + with: + name: ${{ needs.release_deb.outputs.runtime_deb_workflow_artifact_name }} + path: runtime-deb + + - name: Download framework .deb artifact + uses: actions/download-artifact@v4 + with: + name: ${{ needs.release_deb.outputs.framework_deb_workflow_artifact_name }} + path: framework-deb + + - name: Validate packaged binaries + shell: bash + run: | + set -euo pipefail + + runtime_deb="runtime-deb/${{ needs.release_deb.outputs.runtime_deb_artifact_name }}" + framework_deb="framework-deb/${{ needs.release_deb.outputs.framework_deb_artifact_name }}" + + for deb in "$runtime_deb" "$framework_deb"; do + echo "Validating $deb" + if ! dpkg-deb -c "$deb" | grep -Fq './usr/bin/dls'; then + echo "ERROR: $deb does not contain /usr/bin/dls" + exit 1 + fi + done + + publish_runtime_image: + needs: + - release_deb + - validate_deb uses: iit-DLSLab/cicd_tools/.github/workflows/docker-publish.yml@main with: image_name: dls2-runtime @@ -59,7 +92,9 @@ jobs: CICD_PAT: ${{ secrets.CICD_PAT }} publish_framework_image: - needs: release_deb + needs: + - release_deb + - validate_deb uses: iit-DLSLab/cicd_tools/.github/workflows/docker-publish.yml@main with: image_name: dls2-framework From 524521923b43629df01496ad7d9324b030b27f0c Mon Sep 17 00:00:00 2001 From: mich-pest Date: Wed, 22 Apr 2026 15:01:34 +0200 Subject: [PATCH 25/31] create-release-deb: forcing fresh rebuild in deb creation --- .github/workflows/create-release-deb.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 9672a61..547c906 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -31,8 +31,6 @@ jobs: package-name: "dls2" deb-script-source: caller container: "ghcr.io/iit-dlslab/dls2-dev:latest" - workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} - artifact_download_path: "." secrets: GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} CICD_PAT: ${{ secrets.CICD_PAT }} From 073ecc9aa233831814dddd0c2e7a592a83d52711 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Wed, 22 Apr 2026 17:03:26 +0200 Subject: [PATCH 26/31] create-release-deb: additional debug prints added --- .github/workflows/create-release-deb.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 547c906..47a84f8 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -59,8 +59,22 @@ jobs: runtime_deb="runtime-deb/${{ needs.release_deb.outputs.runtime_deb_artifact_name }}" framework_deb="framework-deb/${{ needs.release_deb.outputs.framework_deb_artifact_name }}" + echo "Downloaded artifact contents:" + find runtime-deb framework-deb -maxdepth 2 -type f -print | sort + for deb in "$runtime_deb" "$framework_deb"; do echo "Validating $deb" + if [[ ! -f "$deb" ]]; then + echo "ERROR: expected package file not found: $deb" + exit 1 + fi + + echo "--- dpkg-deb --info $deb" + dpkg-deb --info "$deb" + + echo "--- matching entries in $deb" + dpkg-deb -c "$deb" | grep -E '\./usr/bin/dls($|/)|\./usr/local|^drwx.*/usr/bin/?$' || true + if ! dpkg-deb -c "$deb" | grep -Fq './usr/bin/dls'; then echo "ERROR: $deb does not contain /usr/bin/dls" exit 1 From c76b7c8f0ef0e43cbafeecf9322fd851914c2a11 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Wed, 22 Apr 2026 17:50:05 +0200 Subject: [PATCH 27/31] fixup! create-release-deb: additional debug prints added --- .github/workflows/create-release-deb.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 47a84f8..10feaa7 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -73,9 +73,14 @@ jobs: dpkg-deb --info "$deb" echo "--- matching entries in $deb" - dpkg-deb -c "$deb" | grep -E '\./usr/bin/dls($|/)|\./usr/local|^drwx.*/usr/bin/?$' || true - - if ! dpkg-deb -c "$deb" | grep -Fq './usr/bin/dls'; then + dpkg-deb -c "$deb" | awk ' + /\.\/*usr\/bin\/dls($|\/)/ || /\.\/*usr\/local/ || /^drwx.*\.\/usr\/bin\/?$/ { print } + ' + + if ! dpkg-deb -c "$deb" | awk ' + index($0, "./usr/bin/dls") { found=1 } + END { exit(found ? 0 : 1) } + '; then echo "ERROR: $deb does not contain /usr/bin/dls" exit 1 fi From e5386ad4bfb49b7efcca287f02776b2c2a406504 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Thu, 23 Apr 2026 08:52:00 +0200 Subject: [PATCH 28/31] create-release-deb: reverting fresh build test --- .github/workflows/create-release-deb.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 10feaa7..50778be 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -31,6 +31,8 @@ jobs: package-name: "dls2" deb-script-source: caller container: "ghcr.io/iit-dlslab/dls2-dev:latest" + workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} + artifact_download_path: "." secrets: GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} CICD_PAT: ${{ secrets.CICD_PAT }} From 26697c64d8c96e3b07bf2bff461519d035d3cde6 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Thu, 23 Apr 2026 09:21:20 +0200 Subject: [PATCH 29/31] create-deb-deploy: refreshing step added when build is provided --- scripts/create-deb-deploy.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh index f33d7ba..65c96cf 100755 --- a/scripts/create-deb-deploy.sh +++ b/scripts/create-deb-deploy.sh @@ -149,17 +149,19 @@ run_pipeline() { if [[ "${reuse_existing_build}" == "1" ]]; then echo "[build] reusing existing build directory: ${build_dir}" + echo "[build] refreshing generated install files and source-tree outputs for this workspace" else echo "[build] configuring and compiling in: ${build_dir}" - cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/ \ - "${cmake_user_args[@]}" - - if [[ "${BUILD_VERBOSE}" == "1" ]]; then - cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose - else - cmake --build "${build_dir}" -- "${build_user_args[@]}" - fi + fi + + cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/ \ + "${cmake_user_args[@]}" + + if [[ "${BUILD_VERBOSE}" == "1" ]]; then + cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose + else + cmake --build "${build_dir}" -- "${build_user_args[@]}" fi DESTDIR="${base_stage_dir}" cmake --install "${build_dir}" From 0aeb6f301d6c23b49afbb12255479f39ca06b26e Mon Sep 17 00:00:00 2001 From: mich-pest Date: Thu, 23 Apr 2026 10:23:28 +0200 Subject: [PATCH 30/31] create-release-deb: reverting to builtin deb creation script --- .github/workflows/create-release-deb.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-deb.yml b/.github/workflows/create-release-deb.yml index 50778be..7cb040c 100644 --- a/.github/workflows/create-release-deb.yml +++ b/.github/workflows/create-release-deb.yml @@ -29,7 +29,9 @@ jobs: uses: iit-DLSLab/cicd_tools/.github/workflows/create-release-deb.yml@main with: package-name: "dls2" - deb-script-source: caller + # deb-script-source: caller + deb-script-source: builtin + builtin-deb-script-path: scripts/create-deb-deploy.sh container: "ghcr.io/iit-dlslab/dls2-dev:latest" workflow_artifact_name: ${{ needs.build_test.outputs.build_workflow_artifact_name }} artifact_download_path: "." From 162abcd712eb20c523d443b331555d9b435db853 Mon Sep 17 00:00:00 2001 From: mich-pest Date: Thu, 23 Apr 2026 11:24:09 +0200 Subject: [PATCH 31/31] create-deb-deploy: project-specific script removed --- scripts/create-deb-deploy.sh | 347 ----------------------------------- 1 file changed, 347 deletions(-) delete mode 100755 scripts/create-deb-deploy.sh diff --git a/scripts/create-deb-deploy.sh b/scripts/create-deb-deploy.sh deleted file mode 100755 index 65c96cf..0000000 --- a/scripts/create-deb-deploy.sh +++ /dev/null @@ -1,347 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "${BASH_VERSION:-}" ]; then - echo "ERROR: run this script with bash" - exit 1 -fi - -set -euo pipefail - -# ----------------------------------------------------------------------------- -# Build + package script (deployment CI on runner host) -# Produces: dls2__amd64.deb at repo root. -# ----------------------------------------------------------------------------- - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" -ART_DIR="${ROOT_DIR}/deb_pipeline_artifacts" -BUILD_LOG="${ART_DIR}/build.log" - -usage() { - cat <<'EOF' -Usage: create-deb-deploy.sh - -Options: - -h, --help Show this help message. - -Environment: - REUSE_BUILD=auto|1|0 Reuse an existing build directory when possible. Defaults to auto. -EOF -} - -REUSE_BUILD="${REUSE_BUILD:-auto}" -while [[ $# -gt 0 ]]; do - case "$1" in - -h|--help) - usage - exit 0 - ;; - *) - echo "ERROR: unknown argument '$1'" - usage - exit 1 - ;; - esac -done - -case "${REUSE_BUILD}" in - auto|0|1) - ;; - *) - echo "ERROR: REUSE_BUILD must be auto, 0, or 1, got '${REUSE_BUILD}'" - exit 1 - ;; -esac - -VERSION="${VERSION_OVERRIDE:-0.0.0-local}" -DEB_CONTROL_VERSION="$(echo "${VERSION}" | sed -E 's/^[^0-9]*//')" -if [[ -z "${DEB_CONTROL_VERSION}" ]]; then - echo "ERROR: VERSION '${VERSION}' cannot be converted to a Debian control version" - exit 1 -fi - -PACKAGE_NAME="${PACKAGE_NAME:-dls2}" -MAINTAINER="${DEB_MAINTAINER:-Michele Pestarino }" -RUNTIME_PACKAGE_NAME="${PACKAGE_NAME}-runtime" -FRAMEWORK_PACKAGE_NAME="${PACKAGE_NAME}-framework" -RUNTIME_PACKAGE_DESCRIPTION="${DEB_RUNTIME_DESCRIPTION:-DLS2 runtime package}" -FRAMEWORK_PACKAGE_DESCRIPTION="${DEB_FRAMEWORK_DESCRIPTION:-DLS2 framework package}" -DEB_DEPENDS="${DEB_DEPENDS:-python3, python3-psutil, libyaml-cpp0.8, libtinyxml2-10, libgtk-3-0t64 | libgtk-3-0, libcairo2, libglib2.0-0t64 | libglib2.0-0, libboost-filesystem1.83.0, libconsole-bridge1.0, libcap2-bin}" - -RUNTIME_DEB_NAME="${RUNTIME_PACKAGE_NAME}_${VERSION}_amd64.deb" -FRAMEWORK_DEB_NAME="${FRAMEWORK_PACKAGE_NAME}_${VERSION}_amd64.deb" -RUNTIME_DEB_PATH="${ROOT_DIR}/${RUNTIME_DEB_NAME}" -FRAMEWORK_DEB_PATH="${ROOT_DIR}/${FRAMEWORK_DEB_NAME}" -JOBS="${JOBS:-4}" -LIVE_BUILD_OUTPUT="${LIVE_BUILD_OUTPUT:-0}" -BUILD_VERBOSE="${BUILD_VERBOSE:-0}" -CLEAN_BUILD="${CLEAN_BUILD:-0}" -CMAKE_ARGS="${CMAKE_ARGS:-}" -BUILD_ARGS="${BUILD_ARGS:--j${JOBS}}" - -mkdir -p "${ART_DIR}" -rm -f \ - "${RUNTIME_DEB_PATH}" \ - "${FRAMEWORK_DEB_PATH}" \ - "${ART_DIR}/pkg_files_runtime.txt" \ - "${ART_DIR}/pkg_files_framework.txt" \ - "${BUILD_LOG}" - -readarray -t required_dirs < <( - awk ' - match($0, /^[[:space:]]*add_subdirectory[[:space:]]*\(([[:space:]]*"[^"]+"|[[:space:]]*[^#)[:space:]]+)/) { - dir = substr($0, RSTART, RLENGTH) - sub(/^[[:space:]]*add_subdirectory[[:space:]]*\(/, "", dir) - sub(/^[[:space:]]+/, "", dir) - sub(/^"/, "", dir) - sub(/"$/, "", dir) - sub(/[[:space:]].*$/, "", dir) - if (dir !~ /^\$/ && dir !~ /^\// && dir !~ /\.\./) { - print dir - } - } - ' "${ROOT_DIR}/CMakeLists.txt" | sort -u -) - -if [[ ${#required_dirs[@]} -eq 0 ]]; then - echo "ERROR: could not infer required source directories from ${ROOT_DIR}/CMakeLists.txt." - exit 1 -fi - -for required_dir in "${required_dirs[@]}"; do - if [[ ! -f "${ROOT_DIR}/${required_dir}/CMakeLists.txt" ]]; then - echo "ERROR: missing ${required_dir}/CMakeLists.txt under ${ROOT_DIR}." - echo "Hint: submodules are not checked out on this runner." - exit 1 - fi -done - -run_pipeline() { - local build_dir="${ROOT_DIR}/build" - local base_stage_dir="${ROOT_DIR}/.deb_stage" - local reuse_existing_build="0" - - if [[ "${CLEAN_BUILD}" == "1" ]]; then - rm -rf "${build_dir}" - fi - rm -rf "${base_stage_dir}" "${ROOT_DIR}/.deb_stage_runtime" "${ROOT_DIR}/.deb_stage_framework" - - # shellcheck disable=SC2206 - local cmake_user_args=(${CMAKE_ARGS}) - # shellcheck disable=SC2206 - local build_user_args=(${BUILD_ARGS}) - - if [[ "${CLEAN_BUILD}" != "1" && -f "${build_dir}/CMakeCache.txt" ]]; then - case "${REUSE_BUILD}" in - auto|1) - reuse_existing_build="1" - ;; - 0) - ;; - esac - fi - - if [[ "${REUSE_BUILD}" == "1" && "${reuse_existing_build}" != "1" ]]; then - echo "ERROR: REUSE_BUILD=1 was requested, but no reusable build cache was found in ${build_dir}." - echo "Hint: provide a prebuilt build/ artifact or set REUSE_BUILD=auto or 0." - return 1 - fi - - if [[ "${reuse_existing_build}" == "1" ]]; then - echo "[build] reusing existing build directory: ${build_dir}" - echo "[build] refreshing generated install files and source-tree outputs for this workspace" - else - echo "[build] configuring and compiling in: ${build_dir}" - fi - - cmake -S "${ROOT_DIR}" -B "${build_dir}" -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/ \ - "${cmake_user_args[@]}" - - if [[ "${BUILD_VERBOSE}" == "1" ]]; then - cmake --build "${build_dir}" -- "${build_user_args[@]}" --verbose - else - cmake --build "${build_dir}" -- "${build_user_args[@]}" - fi - - DESTDIR="${base_stage_dir}" cmake --install "${build_dir}" - - strip "${base_stage_dir}/usr/bin/dls2/dynamic_legged_systems_framework" || true - strip "${base_stage_dir}/usr/bin/dls2/child_process_launcher" || true - strip "${base_stage_dir}/usr/lib/librobotlib.so" || true - - if [[ -f "${base_stage_dir}/usr/bin/dls" ]]; then - awk ' - NR == 1 { - print - print "export LD_LIBRARY_PATH=\"/opt/ros/jazzy/lib/x86_64-linux-gnu:/usr/local/lib:/usr/lib:/usr/lib/dls2:/usr/lib/dls2/motion_generators:/usr/lib/dls2/controllers:/usr/lib/dls2/estimators:/usr/lib/dls2/messages:${LD_LIBRARY_PATH:-}\"" - print "export DLS_SERVERS_PATH=\"${DLS_SERVERS_PATH:-/usr/include/dls2/util/messaging/servers.yaml}\"" - print "export DLS_SAFETY_LAYER_PATH=\"${DLS_SAFETY_LAYER_PATH:-/usr/include/dls2/supervisor/data/safety_layer.yaml}\"" - print "export DLS_SCHEDULER_PATH=\"${DLS_SCHEDULER_PATH:-/usr/include/dls2/schedulers}\"" - print "export GZ_SIM_RESOURCE_PATH=\"${GZ_SIM_RESOURCE_PATH:-/usr/local/share/dls-gazebo/worlds}\"" - next - } - /fastdds shm clean/ { - print "command -v fastdds >/dev/null 2>&1 && fastdds shm clean > /dev/null 2>/dev/null || true" - next - } - /dynamic_legged_systems_framework / { - sub(/^[[:space:]]*/, "") - print "exec " $0 - next - } - { print } - ' "${base_stage_dir}/usr/bin/dls" > "${base_stage_dir}/usr/bin/dls.tmp" - mv "${base_stage_dir}/usr/bin/dls.tmp" "${base_stage_dir}/usr/bin/dls" - chmod +x "${base_stage_dir}/usr/bin/dls" - fi - - mkdir -p "${base_stage_dir}/etc/profile.d" - cat > "${base_stage_dir}/etc/profile.d/dls2.sh" << "EOPROFILE" -#!/bin/sh -export GZ_SIM_RESOURCE_PATH="/usr/local/share/dls-gazebo/worlds" -export DLS_SERVERS_PATH="/usr/include/dls2/util/messaging/servers.yaml" -export DLS_SAFETY_LAYER_PATH="/usr/include/dls2/supervisor/data/safety_layer.yaml" -export DLS_SCHEDULER_PATH="/usr/include/dls2/schedulers" -EOPROFILE - chmod +x "${base_stage_dir}/etc/profile.d/dls2.sh" - - write_package_metadata() { - local stage_dir="$1" - local package_name="$2" - local package_description="$3" - mkdir -p "${stage_dir}/DEBIAN" - cat > "${stage_dir}/DEBIAN/control" << EOCONTROL -Package: ${package_name} -Version: ${DEB_CONTROL_VERSION} -Section: base -Priority: optional -Architecture: amd64 -Maintainer: ${MAINTAINER} -Depends: ${DEB_DEPENDS} -Description: ${package_description} -EOCONTROL - - cat > "${stage_dir}/DEBIAN/postinst" << 'EOPOSTINST' -#!/bin/sh -set -e - -if command -v setcap >/dev/null 2>&1; then - if [ -f /usr/bin/dls2/dynamic_legged_systems_framework ]; then - setcap cap_sys_nice=eip /usr/bin/dls2/dynamic_legged_systems_framework || true - fi - if [ -f /usr/bin/dls2/child_process_launcher ]; then - setcap cap_sys_nice=eip /usr/bin/dls2/child_process_launcher || true - fi -fi - -if command -v ldconfig >/dev/null 2>&1; then - ldconfig || true -fi - -exit 0 -EOPOSTINST - chmod 0755 "${stage_dir}/DEBIAN/postinst" - } - - package_variant() { - local variant="$1" - local include_headers="$2" - local package_name="$3" - local package_description="$4" - local deb_name="$5" - local pkg_list_path="$6" - local stage_dir="${ROOT_DIR}/.deb_stage_${variant}" - - cp -a "${base_stage_dir}" "${stage_dir}" - - if [[ "${include_headers}" == "0" && -d "${stage_dir}/usr/include" ]]; then - find "${stage_dir}/usr/include" -type f \ - \( -name '*.h' -o -name '*.hpp' -o -name '*.tpp' \) \ - -delete - find "${stage_dir}/usr/include" -depth -type d -empty -delete - fi - - write_package_metadata "${stage_dir}" "${package_name}" "${package_description}" - - if ! find "${stage_dir}" -mindepth 1 \ - ! -path "${stage_dir}/DEBIAN" \ - ! -path "${stage_dir}/DEBIAN/*" \ - ! -path "${stage_dir}/etc" \ - ! -path "${stage_dir}/etc/profile.d" \ - ! -path "${stage_dir}/etc/profile.d/dls2.sh" \ - -print -quit | grep -q .; then - echo "ERROR: staged package payload is empty for ${variant}." - echo "Hint: cmake configure/build/install likely failed earlier, or the build cache points to a different source tree." - return 1 - fi - - dpkg-deb --build "${stage_dir}" "${deb_name}" - - dpkg-deb -c "${deb_name}" \ - | awk ' - $1 !~ /^d/ { - for (i = 1; i <= NF; i++) { - if ($i ~ /^\.\//) { - print $i - break - } - } - } - ' \ - | sed -E 's#^\./#/#; s#/$##; s#//+#/#g' \ - | sort -u > "${pkg_list_path}" - } - - package_variant \ - "runtime" \ - "0" \ - "${RUNTIME_PACKAGE_NAME}" \ - "${RUNTIME_PACKAGE_DESCRIPTION}" \ - "${RUNTIME_DEB_NAME}" \ - "${ART_DIR}/pkg_files_runtime.txt" - - package_variant \ - "framework" \ - "1" \ - "${FRAMEWORK_PACKAGE_NAME}" \ - "${FRAMEWORK_PACKAGE_DESCRIPTION}" \ - "${FRAMEWORK_DEB_NAME}" \ - "${ART_DIR}/pkg_files_framework.txt" -} - -echo "[build] building and packaging on host in ${ROOT_DIR}" -echo "[build] reuse build: ${REUSE_BUILD}" -if [[ "${LIVE_BUILD_OUTPUT}" == "1" ]]; then - if run_pipeline > >(tee "${BUILD_LOG}") 2>&1; then - rc=0 - else - rc=$? - fi -else - if run_pipeline > "${BUILD_LOG}" 2>&1; then - rc=0 - else - rc=$? - fi -fi - -if [[ ${rc} -ne 0 ]]; then - echo "ERROR: build/package failed. See ${BUILD_LOG}" - tail -n 120 "${BUILD_LOG}" || true - exit ${rc} -fi - -if [[ ! -f "${RUNTIME_DEB_PATH}" || ! -f "${FRAMEWORK_DEB_PATH}" ]]; then - echo "ERROR: expected .deb files were not created:" - echo " - ${RUNTIME_DEB_PATH}" - echo " - ${FRAMEWORK_DEB_PATH}" - echo "See ${BUILD_LOG}" - tail -n 120 "${BUILD_LOG}" || true - exit 1 -fi - -echo "[build] OK: ${RUNTIME_DEB_PATH}" -echo "[build] OK: ${FRAMEWORK_DEB_PATH}" -echo "${RUNTIME_DEB_PATH}" -echo "${FRAMEWORK_DEB_PATH}"