From 15d6833134405e7f4b6838b2c5a647228754879a Mon Sep 17 00:00:00 2001 From: Jerome Justin Date: Tue, 9 Sep 2025 09:44:54 +1000 Subject: [PATCH 1/4] adding the tf rotation and offset feature --- .../include/adnav_driver/adnav_driver.h | 6 + adnav_driver/src/adnav_driver.cpp | 119 +++++++++++------- adnav_launch/config/adnav_serial.yaml | 14 ++- 3 files changed, 94 insertions(+), 45 deletions(-) diff --git a/adnav_driver/include/adnav_driver/adnav_driver.h b/adnav_driver/include/adnav_driver/adnav_driver.h index 9855254..3c985a9 100644 --- a/adnav_driver/include/adnav_driver/adnav_driver.h +++ b/adnav_driver/include/adnav_driver/adnav_driver.h @@ -61,6 +61,7 @@ // ROS2 Packages, Services, Messages #include #include +#include #include #include #include @@ -132,6 +133,11 @@ class Driver : public rclcpp::Node // Inheriting gives every "this->" as a poin ~Driver(); private: + double roll_, pitch_, yaw_; + double yaw_offset_, roll_offset_; + tf2::Quaternion rotation_q_; + tf2::Matrix3x3 rotation_matrix_; + // Debug variables int pub_num_ = 0, P28_num_ = 0, P20_num_ = 0, P27_num_ = 0, P33_num_ = 0, P0_num_ = 0; diff --git a/adnav_driver/src/adnav_driver.cpp b/adnav_driver/src/adnav_driver.cpp index 7833959..8b73b5f 100644 --- a/adnav_driver/src/adnav_driver.cpp +++ b/adnav_driver/src/adnav_driver.cpp @@ -497,6 +497,23 @@ void Driver::setupParams() { comms_select_description.integer_range.push_back(commRange); this->declare_parameter("comm_select", adnav::CONNECTION_SERIAL, comms_select_description); comms_data_.method = (int) this->get_parameter("comm_select").as_int(); + + // Add parameters for static rotation + this->declare_parameter("rotation_x_angle", 0.0); + this->declare_parameter("rotation_y_angle", 0.0); + this->declare_parameter("rotation_z_angle", 0.0); + this->declare_parameter("roll_offset", 0.0); + this->declare_parameter("pitch_offset", 0.0); + this->declare_parameter("yaw_offset", 0.0); + + this->get_parameter("rotation_x_angle", roll_); + this->get_parameter("rotation_y_angle", pitch_); + this->get_parameter("rotation_z_angle", yaw_); + this->get_parameter("pitch_offset", pitch_offset_); + this->get_parameter("yaw_offset", yaw_offset_); + + rotation_q_.setRPY(roll_, pitch_, yaw_); + rotation_matrix_.setRotation(rotation_q_); } //~~~~~~ Control Functions @@ -1602,43 +1619,50 @@ void Driver::systemStateRosDecoder(an_packet_t* an_packet) { ntrip_client_->set_location(llh_.latitude, llh_.longitude, llh_.height); } // TWIST - twist_msg_.linear.x = system_state_packet.velocity[0]; - twist_msg_.linear.y = system_state_packet.velocity[1]; - twist_msg_.linear.z = system_state_packet.velocity[2]; - twist_msg_.angular.x = system_state_packet.angular_velocity[0]; - twist_msg_.angular.y = system_state_packet.angular_velocity[1]; - twist_msg_.angular.z = system_state_packet.angular_velocity[2]; - + tf2::Vector3 original_vel(system_state_packet.velocity[0], system_state_packet.velocity[1], system_state_packet.velocity[2]); + tf2::Vector3 rotated_vel = rotation_matrix_ * original_vel; + twist_msg_.linear.x = rotated_vel.x(); + twist_msg_.linear.y = rotated_vel.y(); + twist_msg_.linear.z = rotated_vel.z(); + + tf2::Vector3 original_ang_vel(system_state_packet.angular_velocity[0], system_state_packet.angular_velocity[1], system_state_packet.angular_velocity[2]); + tf2::Vector3 rotated_ang_vel = rotation_matrix_ * original_ang_vel; + twist_msg_.angular.x = rotated_ang_vel.x(); + twist_msg_.angular.y = rotated_ang_vel.y(); + twist_msg_.angular.z = rotated_ang_vel.z(); // IMU imu_msg_.header.stamp.sec = system_state_packet.unix_time_seconds; imu_msg_.header.stamp.nanosec = system_state_packet.microseconds*1000; imu_msg_.header.frame_id = frame_id_; // Using the RPY orientation as done by cosama - orientation_.setRPY( - system_state_packet.orientation[0], - system_state_packet.orientation[1], - M_PI/2.0f - system_state_packet.orientation[2] // REP 103 - ); - imu_msg_.orientation.x = orientation_[0]; - imu_msg_.orientation.y = orientation_[1]; - imu_msg_.orientation.z = orientation_[2]; - imu_msg_.orientation.w = orientation_[3]; - - // POSE Orientation - pose_msg_.orientation.x = orientation_[0]; - pose_msg_.orientation.y = orientation_[1]; - pose_msg_.orientation.z = orientation_[2]; - pose_msg_.orientation.w = orientation_[3]; - - imu_msg_.angular_velocity.x = system_state_packet.angular_velocity[0]; // These the same as the TWIST msg values - imu_msg_.angular_velocity.y = system_state_packet.angular_velocity[1]; - imu_msg_.angular_velocity.z = system_state_packet.angular_velocity[2]; - - // The IMU linear acceleration is now coming from the RAW Sensors Accelerometer - imu_msg_.linear_acceleration.x = system_state_packet.body_acceleration[0]; - imu_msg_.linear_acceleration.y = system_state_packet.body_acceleration[1]; - imu_msg_.linear_acceleration.z = system_state_packet.body_acceleration[2]; + tf2::Quaternion sensor_orientation; + sensor_orientation.setRPY( + system_state_packet.orientation[0] + (roll_offset_ * M_PI / 180.0), + system_state_packet.orientation[1] + (pitch_offset_ * M_PI / 180.0), + M_PI/2.0f - system_state_packet.orientation[2] + (yaw_offset_ * M_PI / 180.0)// REP 103 + ); + + // Apply the static rotation by multiplying the quaternions + tf2::Quaternion final_orientation = rotation_q_ * sensor_orientation; + final_orientation.normalize(); // It's good practice to normalize after multiplication + + // Assign the final, rotated orientation to the IMU and Pose messages + imu_msg_.orientation.x = final_orientation.x(); + imu_msg_.orientation.y = final_orientation.y(); + imu_msg_.orientation.z = final_orientation.z(); + imu_msg_.orientation.w = final_orientation.w(); + + // POSE Orientation + pose_msg_.orientation.x = final_orientation.x(); + pose_msg_.orientation.y = final_orientation.y(); + pose_msg_.orientation.z = final_orientation.z(); + pose_msg_.orientation.w = final_orientation.w(); + + // The angular velocity is already rotated, so this is correct + imu_msg_.angular_velocity.x = rotated_ang_vel.x(); + imu_msg_.angular_velocity.y = rotated_ang_vel.y(); + imu_msg_.angular_velocity.z = rotated_ang_vel.z(); // SYSTEM STATUS system_status_msg_.message = ""; @@ -1883,19 +1907,26 @@ void Driver::rawSensorsRosDecoder(an_packet_t* an_packet) { if(decode_raw_sensors_packet(&raw_sensors_packet, an_packet) == 0) { // RAW MAGNETICFIELD VALUE FROM IMU - mag_field_msg_.header.frame_id = frame_id_; - mag_field_msg_.magnetic_field.x = raw_sensors_packet.magnetometers[0]; - mag_field_msg_.magnetic_field.y = raw_sensors_packet.magnetometers[1]; - mag_field_msg_.magnetic_field.z = raw_sensors_packet.magnetometers[2]; - - imu_raw_msg_.header.frame_id = frame_id_; - imu_raw_msg_.orientation_covariance[0] = -1; // Tell recievers that no orientation is sent. - imu_raw_msg_.linear_acceleration.x = raw_sensors_packet.accelerometers[0]; - imu_raw_msg_.linear_acceleration.y = raw_sensors_packet.accelerometers[1]; - imu_raw_msg_.linear_acceleration.z = raw_sensors_packet.accelerometers[2]; - imu_raw_msg_.angular_velocity.x = raw_sensors_packet.gyroscopes[0]; - imu_raw_msg_.angular_velocity.y = raw_sensors_packet.gyroscopes[1]; - imu_raw_msg_.angular_velocity.z = raw_sensors_packet.gyroscopes[2]; + mag_field_msg_.header.frame_id = frame_id_; + tf2::Vector3 original_mag(raw_sensors_packet.magnetometers[0], raw_sensors_packet.magnetometers[1], raw_sensors_packet.magnetometers[2]); + tf2::Vector3 rotated_mag = rotation_matrix_ * original_mag; + mag_field_msg_.magnetic_field.x = rotated_mag.x(); + mag_field_msg_.magnetic_field.y = rotated_mag.y(); + mag_field_msg_.magnetic_field.z = rotated_mag.z(); + + imu_raw_msg_.header.frame_id = frame_id_; + imu_raw_msg_.orientation_covariance[0] = -1; // Tell recievers that no orientation is sent. + tf2::Vector3 original_raw_accel(raw_sensors_packet.accelerometers[0], raw_sensors_packet.accelerometers[1], raw_sensors_packet.accelerometers[2]); + tf2::Vector3 rotated_raw_accel = rotation_matrix_ * original_raw_accel; + imu_raw_msg_.linear_acceleration.x = rotated_raw_accel.x(); + imu_raw_msg_.linear_acceleration.y = rotated_raw_accel.y(); + imu_raw_msg_.linear_acceleration.z = rotated_raw_accel.z(); + + tf2::Vector3 original_raw_gyro(raw_sensors_packet.gyroscopes[0], raw_sensors_packet.gyroscopes[1], raw_sensors_packet.gyroscopes[2]); + tf2::Vector3 rotated_raw_gyro = rotation_matrix_ * original_raw_gyro; + imu_raw_msg_.angular_velocity.x = rotated_raw_gyro.x(); + imu_raw_msg_.angular_velocity.y = rotated_raw_gyro.y(); + imu_raw_msg_.angular_velocity.z = rotated_raw_gyro.z(); // BAROMETRIC PRESSURE baro_msg_.header.frame_id = frame_id_; diff --git a/adnav_launch/config/adnav_serial.yaml b/adnav_launch/config/adnav_serial.yaml index 1198a30..76f2339 100644 --- a/adnav_launch/config/adnav_serial.yaml +++ b/adnav_launch/config/adnav_serial.yaml @@ -45,4 +45,16 @@ adnav_node: # The size of the packet period in Microseconds. # Bounded to [1000-65535] [1000Hz-15.29Hz] - packet_timer_period: 1000 \ No newline at end of file + packet_timer_period: 1000 + + # Optional + # Only do this if you have not already set the orientation and offset in the JAVA App + # Add TF rotation to the raw RPY values of the IMU based on your robot's body coordinate system + rotation_x_angle: 0.0 + rotation_y_angle: 0.0 + rotation_z_angle: 0.0 + + # Add an offset to the raw RPY values of the IMU based on your robot's body coordinate system + yaw_offset: 0.0 + roll_offset: 0.0 + pitch_offset: 0.0 From abb0a6b208b7bb56f0caf86cb6ba295a0491ae42 Mon Sep 17 00:00:00 2001 From: Jerome Justin Date: Mon, 22 Sep 2025 11:30:14 +1000 Subject: [PATCH 2/4] adding newly fork of ad nav driver --- adnav_driver/include/adnav_driver/adnav_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adnav_driver/include/adnav_driver/adnav_driver.h b/adnav_driver/include/adnav_driver/adnav_driver.h index 3c985a9..ab29d2b 100644 --- a/adnav_driver/include/adnav_driver/adnav_driver.h +++ b/adnav_driver/include/adnav_driver/adnav_driver.h @@ -134,7 +134,7 @@ class Driver : public rclcpp::Node // Inheriting gives every "this->" as a poin private: double roll_, pitch_, yaw_; - double yaw_offset_, roll_offset_; + double yaw_offset_, roll_offset_, pitch_offset_; tf2::Quaternion rotation_q_; tf2::Matrix3x3 rotation_matrix_; From b30ce04cc0f2f25b7661f9b9100fbb1bbf6816a8 Mon Sep 17 00:00:00 2001 From: Jerome Justin Date: Sun, 16 Nov 2025 11:56:16 +1100 Subject: [PATCH 3/4] adding binary generation and deployment scripts --- .gitignore | 10 +- adnav/CMakeLists.txt | 5 + adnav/package.xml | 20 +++ scripts/DEPLOYMENT_SUMMARY.md | 148 +++++++++++++++++ scripts/README.md | 171 ++++++++++++++++++++ scripts/create_deb_packages.sh | 157 ++++++++++++++++++ scripts/deploy_to_apt_repo.sh | 237 ++++++++++++++++++++++++++++ scripts/regenerate_repo_metadata.sh | 150 ++++++++++++++++++ 8 files changed, 897 insertions(+), 1 deletion(-) create mode 100644 adnav/CMakeLists.txt create mode 100644 adnav/package.xml create mode 100644 scripts/DEPLOYMENT_SUMMARY.md create mode 100644 scripts/README.md create mode 100755 scripts/create_deb_packages.sh create mode 100755 scripts/deploy_to_apt_repo.sh create mode 100755 scripts/regenerate_repo_metadata.sh diff --git a/.gitignore b/.gitignore index d189c23..64e7728 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,12 @@ rqt.repos __pycache__/ .vs/ Log_* -cpplint_* \ No newline at end of file +cpplint_* + +**/.obj* + +adnav/debian/ +adnav_driver/debian/ +adnav_launch/debian/ +adnav_interfaces/debian/ + diff --git a/adnav/CMakeLists.txt b/adnav/CMakeLists.txt new file mode 100644 index 0000000..7405833 --- /dev/null +++ b/adnav/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.16) +project(adnav LANGUAGES NONE) + +find_package(ament_cmake REQUIRED) +ament_package() diff --git a/adnav/package.xml b/adnav/package.xml new file mode 100644 index 0000000..3a48c92 --- /dev/null +++ b/adnav/package.xml @@ -0,0 +1,20 @@ + + + adnav + 1.0.0 + Metapackage for adnav packages + + Jerome Justin + + Apache License 2.0 + + ament_cmake + + adnav_driver + adnav_interfaces + adnav_launch + + + ament_cmake + + diff --git a/scripts/DEPLOYMENT_SUMMARY.md b/scripts/DEPLOYMENT_SUMMARY.md new file mode 100644 index 0000000..a8589e5 --- /dev/null +++ b/scripts/DEPLOYMENT_SUMMARY.md @@ -0,0 +1,148 @@ +# Advanced Navigation Package Deployment - Summary + +## Overview +Successfully created and deployed Debian packages for the Advanced Navigation ROS 2 metapackage. + +## Packages Built +All packages were built for **ROS 2 Jazzy** on **Ubuntu 24.04 (Noble)**: + +1. **ros-jazzy-adnav-interfaces** (265 KB) + - Version: 2.1.1-0noble + - Contains: Message and service definitions + - Dependencies: std_msgs, geometry_msgs + +2. **ros-jazzy-adnav-driver** (263 KB) + - Version: 2.1.1-0noble + - Contains: Main driver implementation + - Dependencies: rclcpp, sensor_msgs, adnav_interfaces + +3. **ros-jazzy-adnav-launch** (6.7 KB) + - Version: 2.1.1-0noble + - Contains: Launch files and configurations + - Dependencies: adnav_driver + - Note: Has some flake8 test failures (formatting issues in launch files) but builds successfully + +4. **ros-jazzy-adnav** (4.8 KB) + - Version: 1.0.0-0noble + - Metapackage that installs all components + - Dependencies: adnav_driver, adnav_interfaces, adnav_launch + +## Deployment Status +✅ **All packages successfully deployed** to avocado.acfr.usyd.edu.au + +Repository URL: https://data.acfr.usyd.edu.au/ubuntu-repo/ + +## Custom Rosdep Rules +Added to `/tmp/rosdep/custom.yaml`: +```yaml +adnav_interfaces: + ubuntu: [ros-jazzy-adnav-interfaces] +adnav_driver: + ubuntu: [ros-jazzy-adnav-driver] +adnav_launch: + ubuntu: [ros-jazzy-adnav-launch] +``` + +## Installation Instructions + +### On Client Machines + +1. **Add ACFR Repository** (if not already added): +```bash +echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ + sudo tee /etc/apt/sources.list.d/acfr.list +``` + +2. **Update and Install**: +```bash +sudo apt update +sudo apt install ros-jazzy-adnav +``` + +This single command will install all Advanced Navigation packages (interfaces, driver, and launch files). + +### In Docker + +Add to Dockerfile: +```dockerfile +# Add ACFR repository +RUN echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ + sudo tee /etc/apt/sources.list.d/acfr.list && sudo apt update + +# Install Advanced Navigation packages +RUN sudo apt install -y ros-jazzy-adnav +``` + +## Build Scripts Location +All automation scripts are in `/home/jjustin/gh_ws/src/groundhog/advanced_navigation/scripts/`: + +- **create_deb_packages.sh** (executable) - Builds all .deb files +- **deploy_to_apt_repo.sh** (executable) - Uploads and regenerates metadata +- **regenerate_repo_metadata.sh** (executable) - Metadata regeneration only +- **README.md** - Complete documentation + +## Repository Status +The ACFR APT repository now contains **8 packages**: +- ros-jazzy-adnav +- ros-jazzy-adnav-driver +- ros-jazzy-adnav-interfaces +- ros-jazzy-adnav-launch +- ros-jazzy-roboteq-driver (previously deployed) +- ros-jazzy-ros2-hetronic (previously deployed) +- ros-jazzy-ros2-hetronic-driver (previously deployed) +- ros-jazzy-ros2-hetronic-interfaces (previously deployed) + +## Notes + +### Test Failures +The adnav_launch package has flake8 and uncrustify test failures due to Python code style issues in the launch files. These are non-blocking and don't affect functionality: +- E225: missing whitespace around operator +- E251: unexpected spaces around keyword/parameter equals +- E302: expected 2 blank lines +- I201: missing newline between import groups +- W291: trailing whitespace +- W292: no newline at end of file +- W293: blank line contains whitespace + +These can be fixed later if needed, but the packages are fully functional. + +### Build Dependencies +Build order is enforced by the script: +1. adnav_interfaces (no dependencies) +2. adnav_driver (depends on adnav_interfaces) +3. adnav_launch (depends on adnav_driver) +4. adnav (metapackage, depends on all) + +Each package is installed locally after building to satisfy dependencies for subsequent packages. + +## Maintenance + +### Rebuilding Packages +To rebuild after code changes: +```bash +cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation +./scripts/create_deb_packages.sh +``` + +### Redeploying to Server +```bash +./scripts/deploy_to_apt_repo.sh +``` + +Or if files are already on server: +```bash +./scripts/regenerate_repo_metadata.sh +``` + +## Verification +Deployment verified on: 2025-11-16 11:40 UTC + +All packages are accessible via: +```bash +apt search ros-jazzy-adnav +``` + +Installation test successful: +```bash +sudo apt install ros-jazzy-adnav +``` diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..ca93107 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,171 @@ +# Advanced Navigation Debian Package Build and Deployment + +This directory contains scripts for building and deploying the Advanced Navigation ROS 2 packages as Debian packages to the ACFR APT repository. + +## Overview + +The `adnav` metapackage contains three ROS 2 packages: +- **adnav_interfaces**: Message and service definitions +- **adnav_driver**: Main driver node +- **adnav_launch**: Launch files and configurations +- **adnav**: Metapackage that installs all components + +## Prerequisites + +### Local System +```bash +sudo apt install python3-bloom fakeroot dpkg-dev +``` + +### SSH Access +- SSH key authentication set up for `avocado.acfr.usyd.edu.au` +- Access to `/data/www/EHM/datasets/ubuntu-repo/` + +## Scripts + +### 1. `create_deb_packages.sh` +Builds Debian packages for all Advanced Navigation packages in dependency order. + +**Usage:** +```bash +cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation +./scripts/create_deb_packages.sh +``` + +**What it does:** +1. Generates debian build files using bloom +2. Builds packages in correct dependency order: + - adnav_interfaces (no dependencies) + - adnav_driver (depends on adnav_interfaces) + - adnav_launch (depends on adnav_driver) + - adnav (metapackage, depends on all) +3. Installs each package locally to satisfy dependencies for next package +4. Outputs .deb files to `/home/jjustin/gh_ws/` + +**Output files:** +- `ros-jazzy-adnav-interfaces_*.deb` +- `ros-jazzy-adnav-driver_*.deb` +- `ros-jazzy-adnav-launch_*.deb` +- `ros-jazzy-adnav_*.deb` + +### 2. `deploy_to_apt_repo.sh` +Uploads packages to the ACFR APT repository and regenerates metadata. + +**Usage:** +```bash +./scripts/deploy_to_apt_repo.sh +``` + +**What it does:** +1. Finds all adnav-related .deb files +2. Uploads them to `avocado.acfr.usyd.edu.au` +3. Regenerates repository metadata (Packages, Release files) +4. Verifies packages are in repository index + +### 3. `regenerate_repo_metadata.sh` +Regenerates repository metadata without uploading files (useful after manual upload). + +**Usage:** +```bash +./scripts/regenerate_repo_metadata.sh +``` + +## Complete Workflow + +### Build and Deploy +```bash +# 1. Build all packages +cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation +./scripts/create_deb_packages.sh + +# 2. Deploy to repository +./scripts/deploy_to_apt_repo.sh +``` + +### Manual Upload (Alternative) +If you prefer to upload files manually: +```bash +# 1. Build packages +./scripts/create_deb_packages.sh + +# 2. Manually upload +scp /home/jjustin/gh_ws/ros-jazzy-adnav*.deb \ + jjustin@avocado.acfr.usyd.edu.au:/data/www/EHM/datasets/ubuntu-repo/ + +# 3. Regenerate metadata +./scripts/regenerate_repo_metadata.sh +``` + +## Installation on Client Machines + +### Add ACFR Repository +```bash +echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ + sudo tee /etc/apt/sources.list.d/acfr.list +``` + +### Install Package +```bash +sudo apt update +sudo apt install ros-jazzy-adnav +``` + +This will install all Advanced Navigation packages (interfaces, driver, and launch files). + +## Docker Integration + +To use these packages in Docker: + +```dockerfile +# Add ACFR repository +RUN echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ + sudo tee /etc/apt/sources.list.d/acfr.list && sudo apt update + +# Install Advanced Navigation packages +RUN sudo apt install -y ros-jazzy-adnav +``` + +## Troubleshooting + +### Bloom fails with "Multiple packages found" +- The script runs bloom from the metapackage directory with explicit package names +- This should be handled automatically + +### Dependencies not found during build +- Packages are built in dependency order +- Each package is installed locally before building the next +- If issues persist, check package.xml dependencies + +### SSH connection fails +- Ensure SSH keys are set up: `ssh-copy-id jjustin@avocado.acfr.usyd.edu.au` +- Test connection: `ssh jjustin@avocado.acfr.usyd.edu.au` + +### Packages not showing up after deployment +- Run `./scripts/regenerate_repo_metadata.sh` +- Check server logs for upload issues +- Verify files exist: `ssh jjustin@avocado.acfr.usyd.edu.au "ls -l /data/www/EHM/datasets/ubuntu-repo/ros-jazzy-adnav*.deb"` + +## Package Versions + +Current versions (as of package.xml): +- adnav_interfaces: 2.1.1 +- adnav_driver: 2.1.1 +- adnav_launch: 2.1.1 +- adnav (metapackage): 1.0.0 + +## Repository Structure + +``` +/data/www/EHM/datasets/ubuntu-repo/ +├── Packages # Package index +├── Packages.gz # Compressed package index +├── Release # Repository metadata with checksums +├── ros-jazzy-*.deb # All ROS 2 Jazzy packages +``` + +## Notes + +- Packages use Ubuntu 24.04 (Noble) as target distribution +- ROS 2 distribution: Jazzy +- Build output includes debug symbol packages (*.dbgsym.deb) which are not uploaded +- The metapackage has no build dependencies but depends on all sub-packages at runtime diff --git a/scripts/create_deb_packages.sh b/scripts/create_deb_packages.sh new file mode 100755 index 0000000..5de9779 --- /dev/null +++ b/scripts/create_deb_packages.sh @@ -0,0 +1,157 @@ +#!/bin/bash +set -e + +# Configuration +METAPACKAGE_NAME="adnav" +METAPACKAGE_DIR="/home/jjustin/gh_ws/src/groundhog/advanced_navigation" +OUTPUT_DIR="/home/jjustin/gh_ws" +ROS_DISTRO="jazzy" + +# Define packages in build order (dependencies first) +PACKAGES=( + "adnav_interfaces" + "adnav_driver" + "adnav_launch" + "adnav" +) + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${GREEN}=== Advanced Navigation Debian Package Builder ===${NC}" +echo "Metapackage: $METAPACKAGE_NAME" +echo "Directory: $METAPACKAGE_DIR" +echo "Output: $OUTPUT_DIR" +echo "ROS Distro: $ROS_DISTRO" +echo "" + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check dependencies +echo -e "${YELLOW}Checking dependencies...${NC}" +for cmd in bloom-generate fakeroot dpkg-deb; do + if ! command_exists "$cmd"; then + echo -e "${RED}Error: $cmd is not installed${NC}" + echo "Install with: sudo apt install python3-bloom fakeroot dpkg-dev" + exit 1 + fi +done +echo -e "${GREEN}All dependencies found${NC}" +echo "" + +# Function to build a single package +build_package() { + local package_name=$1 + local package_dir=$2 + + echo -e "${YELLOW}=== Building $package_name ===${NC}" + + # Check if package directory exists + if [ ! -d "$package_dir" ]; then + echo -e "${RED}Error: Package directory $package_dir does not exist${NC}" + return 1 + fi + + # Clean up previous build artifacts + echo "Cleaning previous build artifacts..." + rm -rf "$package_dir/debian" + rm -rf "$METAPACKAGE_DIR/debian" + + # Generate debian files using bloom (run from METAPACKAGE_DIR with explicit package name) + echo "Generating debian files for $package_name..." + cd "$METAPACKAGE_DIR" + + # Run bloom-generate from the metapackage directory with explicit package name + if ! bloom-generate rosdebian "$package_name" --os-name ubuntu --os-version noble --ros-distro "$ROS_DISTRO"; then + # Move debian directory to package directory if it was created in METAPACKAGE_DIR + if [ -d "$METAPACKAGE_DIR/debian" ]; then + mv "$METAPACKAGE_DIR/debian" "$package_dir/" + fi + echo -e "${RED}Error: bloom-generate failed for $package_name${NC}" + return 1 + fi + + # Move debian directory to package directory if it was created in METAPACKAGE_DIR + if [ -d "$METAPACKAGE_DIR/debian" ]; then + mv "$METAPACKAGE_DIR/debian" "$package_dir/" + fi + + # Build the package + echo "Building debian package for $package_name..." + cd "$package_dir" + fakeroot debian/rules binary + + # Find the generated .deb file (in parent directory with hyphenated name) + search_pattern=$(echo "$package_name" | tr '_' '-') + deb_file=$(ls ../*${search_pattern}*.deb 2>/dev/null | grep -v dbgsym | head -n 1) + + if [ -z "$deb_file" ]; then + echo -e "${RED}Error: Could not find generated .deb file for $package_name${NC}" + echo "Looking for pattern: ../*${search_pattern}*.deb" + ls -la ../*.deb 2>/dev/null || echo "No .deb files found" + return 1 + fi + + # Move to output directory + echo "Moving $deb_file to $OUTPUT_DIR/" + mv "$deb_file" "$OUTPUT_DIR/" + + # Get just the filename + deb_filename=$(basename "$deb_file") + + echo -e "${GREEN}Successfully built: $deb_filename${NC}" + echo "" + + return 0 +} + +# Main build process +echo -e "${YELLOW}Starting build process...${NC}" +echo "" + +cd "$METAPACKAGE_DIR" + +# Build each package in order +for package_name in "${PACKAGES[@]}"; do + # Determine package directory + if [ "$package_name" = "$METAPACKAGE_NAME" ]; then + package_dir="$METAPACKAGE_DIR/$package_name" + else + package_dir="$METAPACKAGE_DIR/$package_name" + fi + + if build_package "$package_name" "$package_dir"; then + echo -e "${GREEN}✓ $package_name built successfully${NC}" + else + echo -e "${RED}✗ Failed to build $package_name${NC}" + echo "Build process stopped." + exit 1 + fi + + # For non-metapackage builds, install the package locally to satisfy dependencies + if [ "$package_name" != "$METAPACKAGE_NAME" ]; then + search_pattern=$(echo "$package_name" | tr '_' '-') + deb_file=$(ls "$OUTPUT_DIR"/*${search_pattern}*.deb 2>/dev/null | grep -v dbgsym | head -n 1) + + if [ -n "$deb_file" ]; then + echo -e "${YELLOW}Installing $package_name locally for dependency resolution...${NC}" + sudo dpkg -i "$deb_file" || sudo apt-get install -f -y + echo "" + fi + fi +done + +echo -e "${GREEN}=== Build Complete ===${NC}" +echo "" +echo "Generated packages in $OUTPUT_DIR:" +ls -lh "$OUTPUT_DIR"/ros-${ROS_DISTRO}-*${METAPACKAGE_NAME}*.deb 2>/dev/null | grep -v dbgsym || echo "No packages found" +echo "" +echo -e "${GREEN}To install the metapackage:${NC}" +echo " sudo dpkg -i $OUTPUT_DIR/ros-${ROS_DISTRO}-${METAPACKAGE_NAME}_*.deb" +echo " sudo apt-get install -f -y" diff --git a/scripts/deploy_to_apt_repo.sh b/scripts/deploy_to_apt_repo.sh new file mode 100755 index 0000000..268404c --- /dev/null +++ b/scripts/deploy_to_apt_repo.sh @@ -0,0 +1,237 @@ +#!/bin/bash +set -e + +# Configuration +PACKAGE_PREFIX="adnav" +LOCAL_DEB_DIR="/home/jjustin/gh_ws" +REMOTE_SERVER="avocado.acfr.usyd.edu.au" +REMOTE_USER="jjustin" +REMOTE_REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" +ROS_DISTRO="jazzy" + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${GREEN}=== Advanced Navigation Package Deployment Script ===${NC}" +echo "Package Prefix: $PACKAGE_PREFIX" +echo "Local Directory: $LOCAL_DEB_DIR" +echo "Remote Server: $REMOTE_SERVER" +echo "Remote Repository: $REMOTE_REPO_DIR" +echo "ROS Distribution: $ROS_DISTRO" +echo "" + +# Function to check if SSH connection works +check_ssh() { + echo -e "${YELLOW}Checking SSH connection to $REMOTE_SERVER...${NC}" + if ssh -o ConnectTimeout=5 "$REMOTE_USER@$REMOTE_SERVER" "echo 'SSH connection successful'" >/dev/null 2>&1; then + echo -e "${GREEN}✓ SSH connection successful${NC}" + return 0 + else + echo -e "${RED}✗ SSH connection failed${NC}" + echo "Please ensure:" + echo " 1. SSH key is set up for $REMOTE_USER@$REMOTE_SERVER" + echo " 2. You have access to the server" + echo " 3. Server is reachable from your network" + return 1 + fi +} + +# Function to find .deb files +find_deb_files() { + echo -e "${YELLOW}Finding .deb files...${NC}" + + # Find all adnav-related .deb files (excluding debug symbols) + DEB_FILES=($(ls "$LOCAL_DEB_DIR"/ros-${ROS_DISTRO}-*${PACKAGE_PREFIX}*.deb 2>/dev/null | grep -v dbgsym)) + + if [ ${#DEB_FILES[@]} -eq 0 ]; then + echo -e "${RED}Error: No .deb files found in $LOCAL_DEB_DIR${NC}" + echo "Expected pattern: ros-${ROS_DISTRO}-*${PACKAGE_PREFIX}*.deb" + echo "" + echo "Please run the build script first:" + echo " ./scripts/create_deb_packages.sh" + return 1 + fi + + echo -e "${GREEN}Found ${#DEB_FILES[@]} package(s):${NC}" + for deb in "${DEB_FILES[@]}"; do + local size=$(ls -lh "$deb" | awk '{print $5}') + echo " - $(basename "$deb") ($size)" + done + echo "" + + return 0 +} + +# Function to upload files +upload_files() { + echo -e "${YELLOW}Uploading .deb files to $REMOTE_SERVER...${NC}" + + for deb_file in "${DEB_FILES[@]}"; do + local filename=$(basename "$deb_file") + echo "Uploading $filename..." + + if scp "$deb_file" "$REMOTE_USER@$REMOTE_SERVER:$REMOTE_REPO_DIR/pool/main/"; then + echo -e "${GREEN}✓ Uploaded $filename${NC}" + else + echo -e "${RED}✗ Failed to upload $filename${NC}" + return 1 + fi + done + + echo "" + return 0 +} + +# Function to regenerate repository metadata +regenerate_metadata() { + echo -e "${YELLOW}Regenerating repository metadata...${NC}" + + # Create a script to run on the remote server (RHEL compatible) + local remote_script=$(cat << 'EOF' +#!/bin/bash +set -e + +REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" +cd "$REPO_DIR" + +echo "Current directory: $(pwd)" +echo "" + +echo "Generating Packages file..." +dpkg-scanpackages -m pool/main /dev/null > dists/noble/main/binary-amd64/Packages + +echo "Compressing Packages file..." +gzip -9c dists/noble/main/binary-amd64/Packages > dists/noble/main/binary-amd64/Packages.gz + +echo "Generating Release file..." +cd dists/noble +cat > Release << EOL +Origin: ACFR +Label: ACFR Ubuntu Repository +Suite: noble +Codename: noble +Architectures: amd64 +Components: main +Description: ACFR Ubuntu Repository for ROS 2 Jazzy +Date: $(LANG=C date -u '+%a, %d %b %Y %H:%M:%S +0000') +EOL + +# Add file hashes to Release (RHEL uses --format instead of -c) +echo "MD5Sum:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(md5sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "SHA1:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(sha1sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "SHA256:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(sha256sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "" +echo "Repository metadata regenerated successfully!" +echo "" +echo "Package count:" +grep -c "^Package:" main/binary-amd64/Packages || echo "0" +EOF +) + + # Execute the script on the remote server + if ssh "$REMOTE_USER@$REMOTE_SERVER" "bash -s" <<< "$remote_script"; then + echo -e "${GREEN}✓ Repository metadata regenerated${NC}" + return 0 + else + echo -e "${RED}✗ Failed to regenerate repository metadata${NC}" + return 1 + fi +} + +# Function to verify installation +verify_installation() { + echo "" + echo -e "${YELLOW}Verifying repository access...${NC}" + + echo "Checking if packages are in repository index..." + if ssh "$REMOTE_USER@$REMOTE_SERVER" "grep -q 'Package: ros-${ROS_DISTRO}-${PACKAGE_PREFIX}' $REMOTE_REPO_DIR/dists/noble/main/binary-amd64/Packages"; then + echo -e "${GREEN}✓ Packages found in repository index${NC}" + else + echo -e "${RED}✗ Packages not found in repository index${NC}" + return 1 + fi + + echo "" + return 0 +} + +# Main deployment process +main() { + # Check SSH connection + if ! check_ssh; then + exit 1 + fi + echo "" + + # Find .deb files + if ! find_deb_files; then + exit 1 + fi + + # Confirm before proceeding + echo -e "${BLUE}Ready to deploy ${#DEB_FILES[@]} package(s) to $REMOTE_SERVER${NC}" + read -p "Continue? (y/N) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Deployment cancelled." + exit 0 + fi + echo "" + + # Upload files + if ! upload_files; then + echo -e "${RED}Deployment failed during upload${NC}" + exit 1 + fi + + # Regenerate metadata + if ! regenerate_metadata; then + echo -e "${RED}Deployment failed during metadata generation${NC}" + exit 1 + fi + + # Verify installation + if ! verify_installation; then + echo -e "${YELLOW}Warning: Verification failed, but files may have been uploaded${NC}" + fi + + echo "" + echo -e "${GREEN}=== Deployment Complete ===${NC}" + echo "" + echo "The packages are now available in the ACFR repository." + echo "" + echo -e "${GREEN}To install on a client machine:${NC}" + echo " 1. Add the repository (if not already added):" + echo " echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \\" + echo " sudo tee /etc/apt/sources.list.d/acfr.list" + echo "" + echo " 2. Update and install:" + echo " sudo apt update" + echo " sudo apt install ros-${ROS_DISTRO}-${PACKAGE_PREFIX}" + echo "" +} + +# Run main function +main diff --git a/scripts/regenerate_repo_metadata.sh b/scripts/regenerate_repo_metadata.sh new file mode 100755 index 0000000..f0f6a90 --- /dev/null +++ b/scripts/regenerate_repo_metadata.sh @@ -0,0 +1,150 @@ +#!/bin/bash +set -e + +# Configuration +REMOTE_SERVER="avocado.acfr.usyd.edu.au" +REMOTE_USER="jjustin" +REMOTE_REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${GREEN}=== Repository Metadata Regeneration Script ===${NC}" +echo "Remote Server: $REMOTE_SERVER" +echo "Remote Repository: $REMOTE_REPO_DIR" +echo "" + +# Function to check if SSH connection works +check_ssh() { + echo -e "${YELLOW}Checking SSH connection to $REMOTE_SERVER...${NC}" + if ssh -o ConnectTimeout=5 "$REMOTE_USER@$REMOTE_SERVER" "echo 'SSH connection successful'" >/dev/null 2>&1; then + echo -e "${GREEN}✓ SSH connection successful${NC}" + return 0 + else + echo -e "${RED}✗ SSH connection failed${NC}" + echo "Please ensure:" + echo " 1. SSH key is set up for $REMOTE_USER@$REMOTE_SERVER" + echo " 2. You have access to the server" + echo " 3. Server is reachable from your network" + return 1 + fi +} + +# Function to regenerate repository metadata +regenerate_metadata() { + echo -e "${YELLOW}Regenerating repository metadata on $REMOTE_SERVER...${NC}" + echo "" + + # Create a script to run on the remote server (RHEL compatible) + local remote_script=$(cat << 'EOF' +#!/bin/bash +set -e + +REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" +cd "$REPO_DIR" + +echo "Current directory: $(pwd)" +echo "Listing .deb files in pool/main:" +ls -lh pool/main/*.deb 2>/dev/null | tail -n 10 || echo "No .deb files found" +echo "" + +echo "Generating Packages file..." +dpkg-scanpackages -m pool/main /dev/null > dists/noble/main/binary-amd64/Packages + +echo "Compressing Packages file..." +gzip -9c dists/noble/main/binary-amd64/Packages > dists/noble/main/binary-amd64/Packages.gz + +echo "Generating Release file..." +cd dists/noble +cat > Release << EOL +Origin: ACFR +Label: ACFR Ubuntu Repository +Suite: noble +Codename: noble +Architectures: amd64 +Components: main +Description: ACFR Ubuntu Repository for ROS 2 Jazzy +Date: $(LANG=C date -u '+%a, %d %b %Y %H:%M:%S +0000') +EOL + +# Add file hashes to Release (RHEL uses --format instead of -c) +echo "MD5Sum:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(md5sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "SHA1:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(sha1sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "SHA256:" >> Release +for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do + if [ -f "$file" ]; then + echo " $(sha256sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release + fi +done + +echo "" +echo "Generated files:" +ls -lh main/binary-amd64/Packages* Release 2>/dev/null +echo "" + +echo "Package count in repository:" +PACKAGE_COUNT=$(grep -c "^Package:" main/binary-amd64/Packages || echo "0") +echo "$PACKAGE_COUNT packages" +echo "" + +echo "Sample packages (first 20):" +grep "^Package:" main/binary-amd64/Packages | head -n 20 +echo "" + +if [ $PACKAGE_COUNT -gt 20 ]; then + echo "... and $((PACKAGE_COUNT - 20)) more packages" + echo "" +fi + +echo "Repository metadata regenerated successfully!" +EOF +) + + # Execute the script on the remote server + if ssh "$REMOTE_USER@$REMOTE_SERVER" "bash -s" <<< "$remote_script"; then + echo -e "${GREEN}✓ Repository metadata regenerated successfully${NC}" + return 0 + else + echo -e "${RED}✗ Failed to regenerate repository metadata${NC}" + return 1 + fi +} + +# Main process +main() { + # Check SSH connection + if ! check_ssh; then + exit 1 + fi + echo "" + + # Regenerate metadata + if ! regenerate_metadata; then + exit 1 + fi + + echo "" + echo -e "${GREEN}=== Metadata Regeneration Complete ===${NC}" + echo "" + echo "The repository metadata has been updated." + echo "Clients can now run 'apt update' to see the latest packages." + echo "" +} + +# Run main function +main From 1c504023a727049ed94c5e09113ad83f503fd6ce Mon Sep 17 00:00:00 2001 From: jclinton830 Date: Mon, 12 Jan 2026 13:49:02 +1100 Subject: [PATCH 4/4] removing the build and deploy scripts --- scripts/DEPLOYMENT_SUMMARY.md | 148 ----------------- scripts/README.md | 171 -------------------- scripts/create_deb_packages.sh | 157 ------------------ scripts/deploy_to_apt_repo.sh | 237 ---------------------------- scripts/regenerate_repo_metadata.sh | 150 ------------------ 5 files changed, 863 deletions(-) delete mode 100644 scripts/DEPLOYMENT_SUMMARY.md delete mode 100644 scripts/README.md delete mode 100755 scripts/create_deb_packages.sh delete mode 100755 scripts/deploy_to_apt_repo.sh delete mode 100755 scripts/regenerate_repo_metadata.sh diff --git a/scripts/DEPLOYMENT_SUMMARY.md b/scripts/DEPLOYMENT_SUMMARY.md deleted file mode 100644 index a8589e5..0000000 --- a/scripts/DEPLOYMENT_SUMMARY.md +++ /dev/null @@ -1,148 +0,0 @@ -# Advanced Navigation Package Deployment - Summary - -## Overview -Successfully created and deployed Debian packages for the Advanced Navigation ROS 2 metapackage. - -## Packages Built -All packages were built for **ROS 2 Jazzy** on **Ubuntu 24.04 (Noble)**: - -1. **ros-jazzy-adnav-interfaces** (265 KB) - - Version: 2.1.1-0noble - - Contains: Message and service definitions - - Dependencies: std_msgs, geometry_msgs - -2. **ros-jazzy-adnav-driver** (263 KB) - - Version: 2.1.1-0noble - - Contains: Main driver implementation - - Dependencies: rclcpp, sensor_msgs, adnav_interfaces - -3. **ros-jazzy-adnav-launch** (6.7 KB) - - Version: 2.1.1-0noble - - Contains: Launch files and configurations - - Dependencies: adnav_driver - - Note: Has some flake8 test failures (formatting issues in launch files) but builds successfully - -4. **ros-jazzy-adnav** (4.8 KB) - - Version: 1.0.0-0noble - - Metapackage that installs all components - - Dependencies: adnav_driver, adnav_interfaces, adnav_launch - -## Deployment Status -✅ **All packages successfully deployed** to avocado.acfr.usyd.edu.au - -Repository URL: https://data.acfr.usyd.edu.au/ubuntu-repo/ - -## Custom Rosdep Rules -Added to `/tmp/rosdep/custom.yaml`: -```yaml -adnav_interfaces: - ubuntu: [ros-jazzy-adnav-interfaces] -adnav_driver: - ubuntu: [ros-jazzy-adnav-driver] -adnav_launch: - ubuntu: [ros-jazzy-adnav-launch] -``` - -## Installation Instructions - -### On Client Machines - -1. **Add ACFR Repository** (if not already added): -```bash -echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ - sudo tee /etc/apt/sources.list.d/acfr.list -``` - -2. **Update and Install**: -```bash -sudo apt update -sudo apt install ros-jazzy-adnav -``` - -This single command will install all Advanced Navigation packages (interfaces, driver, and launch files). - -### In Docker - -Add to Dockerfile: -```dockerfile -# Add ACFR repository -RUN echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ - sudo tee /etc/apt/sources.list.d/acfr.list && sudo apt update - -# Install Advanced Navigation packages -RUN sudo apt install -y ros-jazzy-adnav -``` - -## Build Scripts Location -All automation scripts are in `/home/jjustin/gh_ws/src/groundhog/advanced_navigation/scripts/`: - -- **create_deb_packages.sh** (executable) - Builds all .deb files -- **deploy_to_apt_repo.sh** (executable) - Uploads and regenerates metadata -- **regenerate_repo_metadata.sh** (executable) - Metadata regeneration only -- **README.md** - Complete documentation - -## Repository Status -The ACFR APT repository now contains **8 packages**: -- ros-jazzy-adnav -- ros-jazzy-adnav-driver -- ros-jazzy-adnav-interfaces -- ros-jazzy-adnav-launch -- ros-jazzy-roboteq-driver (previously deployed) -- ros-jazzy-ros2-hetronic (previously deployed) -- ros-jazzy-ros2-hetronic-driver (previously deployed) -- ros-jazzy-ros2-hetronic-interfaces (previously deployed) - -## Notes - -### Test Failures -The adnav_launch package has flake8 and uncrustify test failures due to Python code style issues in the launch files. These are non-blocking and don't affect functionality: -- E225: missing whitespace around operator -- E251: unexpected spaces around keyword/parameter equals -- E302: expected 2 blank lines -- I201: missing newline between import groups -- W291: trailing whitespace -- W292: no newline at end of file -- W293: blank line contains whitespace - -These can be fixed later if needed, but the packages are fully functional. - -### Build Dependencies -Build order is enforced by the script: -1. adnav_interfaces (no dependencies) -2. adnav_driver (depends on adnav_interfaces) -3. adnav_launch (depends on adnav_driver) -4. adnav (metapackage, depends on all) - -Each package is installed locally after building to satisfy dependencies for subsequent packages. - -## Maintenance - -### Rebuilding Packages -To rebuild after code changes: -```bash -cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation -./scripts/create_deb_packages.sh -``` - -### Redeploying to Server -```bash -./scripts/deploy_to_apt_repo.sh -``` - -Or if files are already on server: -```bash -./scripts/regenerate_repo_metadata.sh -``` - -## Verification -Deployment verified on: 2025-11-16 11:40 UTC - -All packages are accessible via: -```bash -apt search ros-jazzy-adnav -``` - -Installation test successful: -```bash -sudo apt install ros-jazzy-adnav -``` diff --git a/scripts/README.md b/scripts/README.md deleted file mode 100644 index ca93107..0000000 --- a/scripts/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# Advanced Navigation Debian Package Build and Deployment - -This directory contains scripts for building and deploying the Advanced Navigation ROS 2 packages as Debian packages to the ACFR APT repository. - -## Overview - -The `adnav` metapackage contains three ROS 2 packages: -- **adnav_interfaces**: Message and service definitions -- **adnav_driver**: Main driver node -- **adnav_launch**: Launch files and configurations -- **adnav**: Metapackage that installs all components - -## Prerequisites - -### Local System -```bash -sudo apt install python3-bloom fakeroot dpkg-dev -``` - -### SSH Access -- SSH key authentication set up for `avocado.acfr.usyd.edu.au` -- Access to `/data/www/EHM/datasets/ubuntu-repo/` - -## Scripts - -### 1. `create_deb_packages.sh` -Builds Debian packages for all Advanced Navigation packages in dependency order. - -**Usage:** -```bash -cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation -./scripts/create_deb_packages.sh -``` - -**What it does:** -1. Generates debian build files using bloom -2. Builds packages in correct dependency order: - - adnav_interfaces (no dependencies) - - adnav_driver (depends on adnav_interfaces) - - adnav_launch (depends on adnav_driver) - - adnav (metapackage, depends on all) -3. Installs each package locally to satisfy dependencies for next package -4. Outputs .deb files to `/home/jjustin/gh_ws/` - -**Output files:** -- `ros-jazzy-adnav-interfaces_*.deb` -- `ros-jazzy-adnav-driver_*.deb` -- `ros-jazzy-adnav-launch_*.deb` -- `ros-jazzy-adnav_*.deb` - -### 2. `deploy_to_apt_repo.sh` -Uploads packages to the ACFR APT repository and regenerates metadata. - -**Usage:** -```bash -./scripts/deploy_to_apt_repo.sh -``` - -**What it does:** -1. Finds all adnav-related .deb files -2. Uploads them to `avocado.acfr.usyd.edu.au` -3. Regenerates repository metadata (Packages, Release files) -4. Verifies packages are in repository index - -### 3. `regenerate_repo_metadata.sh` -Regenerates repository metadata without uploading files (useful after manual upload). - -**Usage:** -```bash -./scripts/regenerate_repo_metadata.sh -``` - -## Complete Workflow - -### Build and Deploy -```bash -# 1. Build all packages -cd /home/jjustin/gh_ws/src/groundhog/advanced_navigation -./scripts/create_deb_packages.sh - -# 2. Deploy to repository -./scripts/deploy_to_apt_repo.sh -``` - -### Manual Upload (Alternative) -If you prefer to upload files manually: -```bash -# 1. Build packages -./scripts/create_deb_packages.sh - -# 2. Manually upload -scp /home/jjustin/gh_ws/ros-jazzy-adnav*.deb \ - jjustin@avocado.acfr.usyd.edu.au:/data/www/EHM/datasets/ubuntu-repo/ - -# 3. Regenerate metadata -./scripts/regenerate_repo_metadata.sh -``` - -## Installation on Client Machines - -### Add ACFR Repository -```bash -echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ - sudo tee /etc/apt/sources.list.d/acfr.list -``` - -### Install Package -```bash -sudo apt update -sudo apt install ros-jazzy-adnav -``` - -This will install all Advanced Navigation packages (interfaces, driver, and launch files). - -## Docker Integration - -To use these packages in Docker: - -```dockerfile -# Add ACFR repository -RUN echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \ - sudo tee /etc/apt/sources.list.d/acfr.list && sudo apt update - -# Install Advanced Navigation packages -RUN sudo apt install -y ros-jazzy-adnav -``` - -## Troubleshooting - -### Bloom fails with "Multiple packages found" -- The script runs bloom from the metapackage directory with explicit package names -- This should be handled automatically - -### Dependencies not found during build -- Packages are built in dependency order -- Each package is installed locally before building the next -- If issues persist, check package.xml dependencies - -### SSH connection fails -- Ensure SSH keys are set up: `ssh-copy-id jjustin@avocado.acfr.usyd.edu.au` -- Test connection: `ssh jjustin@avocado.acfr.usyd.edu.au` - -### Packages not showing up after deployment -- Run `./scripts/regenerate_repo_metadata.sh` -- Check server logs for upload issues -- Verify files exist: `ssh jjustin@avocado.acfr.usyd.edu.au "ls -l /data/www/EHM/datasets/ubuntu-repo/ros-jazzy-adnav*.deb"` - -## Package Versions - -Current versions (as of package.xml): -- adnav_interfaces: 2.1.1 -- adnav_driver: 2.1.1 -- adnav_launch: 2.1.1 -- adnav (metapackage): 1.0.0 - -## Repository Structure - -``` -/data/www/EHM/datasets/ubuntu-repo/ -├── Packages # Package index -├── Packages.gz # Compressed package index -├── Release # Repository metadata with checksums -├── ros-jazzy-*.deb # All ROS 2 Jazzy packages -``` - -## Notes - -- Packages use Ubuntu 24.04 (Noble) as target distribution -- ROS 2 distribution: Jazzy -- Build output includes debug symbol packages (*.dbgsym.deb) which are not uploaded -- The metapackage has no build dependencies but depends on all sub-packages at runtime diff --git a/scripts/create_deb_packages.sh b/scripts/create_deb_packages.sh deleted file mode 100755 index 5de9779..0000000 --- a/scripts/create_deb_packages.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/bash -set -e - -# Configuration -METAPACKAGE_NAME="adnav" -METAPACKAGE_DIR="/home/jjustin/gh_ws/src/groundhog/advanced_navigation" -OUTPUT_DIR="/home/jjustin/gh_ws" -ROS_DISTRO="jazzy" - -# Define packages in build order (dependencies first) -PACKAGES=( - "adnav_interfaces" - "adnav_driver" - "adnav_launch" - "adnav" -) - -# Color output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}=== Advanced Navigation Debian Package Builder ===${NC}" -echo "Metapackage: $METAPACKAGE_NAME" -echo "Directory: $METAPACKAGE_DIR" -echo "Output: $OUTPUT_DIR" -echo "ROS Distro: $ROS_DISTRO" -echo "" - -# Function to check if a command exists -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -# Check dependencies -echo -e "${YELLOW}Checking dependencies...${NC}" -for cmd in bloom-generate fakeroot dpkg-deb; do - if ! command_exists "$cmd"; then - echo -e "${RED}Error: $cmd is not installed${NC}" - echo "Install with: sudo apt install python3-bloom fakeroot dpkg-dev" - exit 1 - fi -done -echo -e "${GREEN}All dependencies found${NC}" -echo "" - -# Function to build a single package -build_package() { - local package_name=$1 - local package_dir=$2 - - echo -e "${YELLOW}=== Building $package_name ===${NC}" - - # Check if package directory exists - if [ ! -d "$package_dir" ]; then - echo -e "${RED}Error: Package directory $package_dir does not exist${NC}" - return 1 - fi - - # Clean up previous build artifacts - echo "Cleaning previous build artifacts..." - rm -rf "$package_dir/debian" - rm -rf "$METAPACKAGE_DIR/debian" - - # Generate debian files using bloom (run from METAPACKAGE_DIR with explicit package name) - echo "Generating debian files for $package_name..." - cd "$METAPACKAGE_DIR" - - # Run bloom-generate from the metapackage directory with explicit package name - if ! bloom-generate rosdebian "$package_name" --os-name ubuntu --os-version noble --ros-distro "$ROS_DISTRO"; then - # Move debian directory to package directory if it was created in METAPACKAGE_DIR - if [ -d "$METAPACKAGE_DIR/debian" ]; then - mv "$METAPACKAGE_DIR/debian" "$package_dir/" - fi - echo -e "${RED}Error: bloom-generate failed for $package_name${NC}" - return 1 - fi - - # Move debian directory to package directory if it was created in METAPACKAGE_DIR - if [ -d "$METAPACKAGE_DIR/debian" ]; then - mv "$METAPACKAGE_DIR/debian" "$package_dir/" - fi - - # Build the package - echo "Building debian package for $package_name..." - cd "$package_dir" - fakeroot debian/rules binary - - # Find the generated .deb file (in parent directory with hyphenated name) - search_pattern=$(echo "$package_name" | tr '_' '-') - deb_file=$(ls ../*${search_pattern}*.deb 2>/dev/null | grep -v dbgsym | head -n 1) - - if [ -z "$deb_file" ]; then - echo -e "${RED}Error: Could not find generated .deb file for $package_name${NC}" - echo "Looking for pattern: ../*${search_pattern}*.deb" - ls -la ../*.deb 2>/dev/null || echo "No .deb files found" - return 1 - fi - - # Move to output directory - echo "Moving $deb_file to $OUTPUT_DIR/" - mv "$deb_file" "$OUTPUT_DIR/" - - # Get just the filename - deb_filename=$(basename "$deb_file") - - echo -e "${GREEN}Successfully built: $deb_filename${NC}" - echo "" - - return 0 -} - -# Main build process -echo -e "${YELLOW}Starting build process...${NC}" -echo "" - -cd "$METAPACKAGE_DIR" - -# Build each package in order -for package_name in "${PACKAGES[@]}"; do - # Determine package directory - if [ "$package_name" = "$METAPACKAGE_NAME" ]; then - package_dir="$METAPACKAGE_DIR/$package_name" - else - package_dir="$METAPACKAGE_DIR/$package_name" - fi - - if build_package "$package_name" "$package_dir"; then - echo -e "${GREEN}✓ $package_name built successfully${NC}" - else - echo -e "${RED}✗ Failed to build $package_name${NC}" - echo "Build process stopped." - exit 1 - fi - - # For non-metapackage builds, install the package locally to satisfy dependencies - if [ "$package_name" != "$METAPACKAGE_NAME" ]; then - search_pattern=$(echo "$package_name" | tr '_' '-') - deb_file=$(ls "$OUTPUT_DIR"/*${search_pattern}*.deb 2>/dev/null | grep -v dbgsym | head -n 1) - - if [ -n "$deb_file" ]; then - echo -e "${YELLOW}Installing $package_name locally for dependency resolution...${NC}" - sudo dpkg -i "$deb_file" || sudo apt-get install -f -y - echo "" - fi - fi -done - -echo -e "${GREEN}=== Build Complete ===${NC}" -echo "" -echo "Generated packages in $OUTPUT_DIR:" -ls -lh "$OUTPUT_DIR"/ros-${ROS_DISTRO}-*${METAPACKAGE_NAME}*.deb 2>/dev/null | grep -v dbgsym || echo "No packages found" -echo "" -echo -e "${GREEN}To install the metapackage:${NC}" -echo " sudo dpkg -i $OUTPUT_DIR/ros-${ROS_DISTRO}-${METAPACKAGE_NAME}_*.deb" -echo " sudo apt-get install -f -y" diff --git a/scripts/deploy_to_apt_repo.sh b/scripts/deploy_to_apt_repo.sh deleted file mode 100755 index 268404c..0000000 --- a/scripts/deploy_to_apt_repo.sh +++ /dev/null @@ -1,237 +0,0 @@ -#!/bin/bash -set -e - -# Configuration -PACKAGE_PREFIX="adnav" -LOCAL_DEB_DIR="/home/jjustin/gh_ws" -REMOTE_SERVER="avocado.acfr.usyd.edu.au" -REMOTE_USER="jjustin" -REMOTE_REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" -ROS_DISTRO="jazzy" - -# Color output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -echo -e "${GREEN}=== Advanced Navigation Package Deployment Script ===${NC}" -echo "Package Prefix: $PACKAGE_PREFIX" -echo "Local Directory: $LOCAL_DEB_DIR" -echo "Remote Server: $REMOTE_SERVER" -echo "Remote Repository: $REMOTE_REPO_DIR" -echo "ROS Distribution: $ROS_DISTRO" -echo "" - -# Function to check if SSH connection works -check_ssh() { - echo -e "${YELLOW}Checking SSH connection to $REMOTE_SERVER...${NC}" - if ssh -o ConnectTimeout=5 "$REMOTE_USER@$REMOTE_SERVER" "echo 'SSH connection successful'" >/dev/null 2>&1; then - echo -e "${GREEN}✓ SSH connection successful${NC}" - return 0 - else - echo -e "${RED}✗ SSH connection failed${NC}" - echo "Please ensure:" - echo " 1. SSH key is set up for $REMOTE_USER@$REMOTE_SERVER" - echo " 2. You have access to the server" - echo " 3. Server is reachable from your network" - return 1 - fi -} - -# Function to find .deb files -find_deb_files() { - echo -e "${YELLOW}Finding .deb files...${NC}" - - # Find all adnav-related .deb files (excluding debug symbols) - DEB_FILES=($(ls "$LOCAL_DEB_DIR"/ros-${ROS_DISTRO}-*${PACKAGE_PREFIX}*.deb 2>/dev/null | grep -v dbgsym)) - - if [ ${#DEB_FILES[@]} -eq 0 ]; then - echo -e "${RED}Error: No .deb files found in $LOCAL_DEB_DIR${NC}" - echo "Expected pattern: ros-${ROS_DISTRO}-*${PACKAGE_PREFIX}*.deb" - echo "" - echo "Please run the build script first:" - echo " ./scripts/create_deb_packages.sh" - return 1 - fi - - echo -e "${GREEN}Found ${#DEB_FILES[@]} package(s):${NC}" - for deb in "${DEB_FILES[@]}"; do - local size=$(ls -lh "$deb" | awk '{print $5}') - echo " - $(basename "$deb") ($size)" - done - echo "" - - return 0 -} - -# Function to upload files -upload_files() { - echo -e "${YELLOW}Uploading .deb files to $REMOTE_SERVER...${NC}" - - for deb_file in "${DEB_FILES[@]}"; do - local filename=$(basename "$deb_file") - echo "Uploading $filename..." - - if scp "$deb_file" "$REMOTE_USER@$REMOTE_SERVER:$REMOTE_REPO_DIR/pool/main/"; then - echo -e "${GREEN}✓ Uploaded $filename${NC}" - else - echo -e "${RED}✗ Failed to upload $filename${NC}" - return 1 - fi - done - - echo "" - return 0 -} - -# Function to regenerate repository metadata -regenerate_metadata() { - echo -e "${YELLOW}Regenerating repository metadata...${NC}" - - # Create a script to run on the remote server (RHEL compatible) - local remote_script=$(cat << 'EOF' -#!/bin/bash -set -e - -REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" -cd "$REPO_DIR" - -echo "Current directory: $(pwd)" -echo "" - -echo "Generating Packages file..." -dpkg-scanpackages -m pool/main /dev/null > dists/noble/main/binary-amd64/Packages - -echo "Compressing Packages file..." -gzip -9c dists/noble/main/binary-amd64/Packages > dists/noble/main/binary-amd64/Packages.gz - -echo "Generating Release file..." -cd dists/noble -cat > Release << EOL -Origin: ACFR -Label: ACFR Ubuntu Repository -Suite: noble -Codename: noble -Architectures: amd64 -Components: main -Description: ACFR Ubuntu Repository for ROS 2 Jazzy -Date: $(LANG=C date -u '+%a, %d %b %Y %H:%M:%S +0000') -EOL - -# Add file hashes to Release (RHEL uses --format instead of -c) -echo "MD5Sum:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(md5sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "SHA1:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(sha1sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "SHA256:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(sha256sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "" -echo "Repository metadata regenerated successfully!" -echo "" -echo "Package count:" -grep -c "^Package:" main/binary-amd64/Packages || echo "0" -EOF -) - - # Execute the script on the remote server - if ssh "$REMOTE_USER@$REMOTE_SERVER" "bash -s" <<< "$remote_script"; then - echo -e "${GREEN}✓ Repository metadata regenerated${NC}" - return 0 - else - echo -e "${RED}✗ Failed to regenerate repository metadata${NC}" - return 1 - fi -} - -# Function to verify installation -verify_installation() { - echo "" - echo -e "${YELLOW}Verifying repository access...${NC}" - - echo "Checking if packages are in repository index..." - if ssh "$REMOTE_USER@$REMOTE_SERVER" "grep -q 'Package: ros-${ROS_DISTRO}-${PACKAGE_PREFIX}' $REMOTE_REPO_DIR/dists/noble/main/binary-amd64/Packages"; then - echo -e "${GREEN}✓ Packages found in repository index${NC}" - else - echo -e "${RED}✗ Packages not found in repository index${NC}" - return 1 - fi - - echo "" - return 0 -} - -# Main deployment process -main() { - # Check SSH connection - if ! check_ssh; then - exit 1 - fi - echo "" - - # Find .deb files - if ! find_deb_files; then - exit 1 - fi - - # Confirm before proceeding - echo -e "${BLUE}Ready to deploy ${#DEB_FILES[@]} package(s) to $REMOTE_SERVER${NC}" - read -p "Continue? (y/N) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Deployment cancelled." - exit 0 - fi - echo "" - - # Upload files - if ! upload_files; then - echo -e "${RED}Deployment failed during upload${NC}" - exit 1 - fi - - # Regenerate metadata - if ! regenerate_metadata; then - echo -e "${RED}Deployment failed during metadata generation${NC}" - exit 1 - fi - - # Verify installation - if ! verify_installation; then - echo -e "${YELLOW}Warning: Verification failed, but files may have been uploaded${NC}" - fi - - echo "" - echo -e "${GREEN}=== Deployment Complete ===${NC}" - echo "" - echo "The packages are now available in the ACFR repository." - echo "" - echo -e "${GREEN}To install on a client machine:${NC}" - echo " 1. Add the repository (if not already added):" - echo " echo 'deb [arch=amd64 trusted=yes] https://data.acfr.usyd.edu.au/ubuntu-repo/ noble main' | \\" - echo " sudo tee /etc/apt/sources.list.d/acfr.list" - echo "" - echo " 2. Update and install:" - echo " sudo apt update" - echo " sudo apt install ros-${ROS_DISTRO}-${PACKAGE_PREFIX}" - echo "" -} - -# Run main function -main diff --git a/scripts/regenerate_repo_metadata.sh b/scripts/regenerate_repo_metadata.sh deleted file mode 100755 index f0f6a90..0000000 --- a/scripts/regenerate_repo_metadata.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash -set -e - -# Configuration -REMOTE_SERVER="avocado.acfr.usyd.edu.au" -REMOTE_USER="jjustin" -REMOTE_REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" - -# Color output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}=== Repository Metadata Regeneration Script ===${NC}" -echo "Remote Server: $REMOTE_SERVER" -echo "Remote Repository: $REMOTE_REPO_DIR" -echo "" - -# Function to check if SSH connection works -check_ssh() { - echo -e "${YELLOW}Checking SSH connection to $REMOTE_SERVER...${NC}" - if ssh -o ConnectTimeout=5 "$REMOTE_USER@$REMOTE_SERVER" "echo 'SSH connection successful'" >/dev/null 2>&1; then - echo -e "${GREEN}✓ SSH connection successful${NC}" - return 0 - else - echo -e "${RED}✗ SSH connection failed${NC}" - echo "Please ensure:" - echo " 1. SSH key is set up for $REMOTE_USER@$REMOTE_SERVER" - echo " 2. You have access to the server" - echo " 3. Server is reachable from your network" - return 1 - fi -} - -# Function to regenerate repository metadata -regenerate_metadata() { - echo -e "${YELLOW}Regenerating repository metadata on $REMOTE_SERVER...${NC}" - echo "" - - # Create a script to run on the remote server (RHEL compatible) - local remote_script=$(cat << 'EOF' -#!/bin/bash -set -e - -REPO_DIR="/data/www/EHM/datasets/ubuntu-repo" -cd "$REPO_DIR" - -echo "Current directory: $(pwd)" -echo "Listing .deb files in pool/main:" -ls -lh pool/main/*.deb 2>/dev/null | tail -n 10 || echo "No .deb files found" -echo "" - -echo "Generating Packages file..." -dpkg-scanpackages -m pool/main /dev/null > dists/noble/main/binary-amd64/Packages - -echo "Compressing Packages file..." -gzip -9c dists/noble/main/binary-amd64/Packages > dists/noble/main/binary-amd64/Packages.gz - -echo "Generating Release file..." -cd dists/noble -cat > Release << EOL -Origin: ACFR -Label: ACFR Ubuntu Repository -Suite: noble -Codename: noble -Architectures: amd64 -Components: main -Description: ACFR Ubuntu Repository for ROS 2 Jazzy -Date: $(LANG=C date -u '+%a, %d %b %Y %H:%M:%S +0000') -EOL - -# Add file hashes to Release (RHEL uses --format instead of -c) -echo "MD5Sum:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(md5sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "SHA1:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(sha1sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "SHA256:" >> Release -for file in main/binary-amd64/Packages main/binary-amd64/Packages.gz; do - if [ -f "$file" ]; then - echo " $(sha256sum $file | cut -d' ' -f1) $(stat --format=%s $file) $file" >> Release - fi -done - -echo "" -echo "Generated files:" -ls -lh main/binary-amd64/Packages* Release 2>/dev/null -echo "" - -echo "Package count in repository:" -PACKAGE_COUNT=$(grep -c "^Package:" main/binary-amd64/Packages || echo "0") -echo "$PACKAGE_COUNT packages" -echo "" - -echo "Sample packages (first 20):" -grep "^Package:" main/binary-amd64/Packages | head -n 20 -echo "" - -if [ $PACKAGE_COUNT -gt 20 ]; then - echo "... and $((PACKAGE_COUNT - 20)) more packages" - echo "" -fi - -echo "Repository metadata regenerated successfully!" -EOF -) - - # Execute the script on the remote server - if ssh "$REMOTE_USER@$REMOTE_SERVER" "bash -s" <<< "$remote_script"; then - echo -e "${GREEN}✓ Repository metadata regenerated successfully${NC}" - return 0 - else - echo -e "${RED}✗ Failed to regenerate repository metadata${NC}" - return 1 - fi -} - -# Main process -main() { - # Check SSH connection - if ! check_ssh; then - exit 1 - fi - echo "" - - # Regenerate metadata - if ! regenerate_metadata; then - exit 1 - fi - - echo "" - echo -e "${GREEN}=== Metadata Regeneration Complete ===${NC}" - echo "" - echo "The repository metadata has been updated." - echo "Clients can now run 'apt update' to see the latest packages." - echo "" -} - -# Run main function -main