#!/bin/bash # apt-ostree Debian Package Builder # Enhanced version for CI/CD environments with better error handling set -euo pipefail # Colors for output GREEN='\033[0;32m' BLUE='\033[0;34m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' print_status() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_header() { echo "" echo -e "${BLUE}================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}================================${NC}" } # Function to check if a command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Function to validate dependencies validate_dependencies() { local missing_deps=() for dep in "$@"; do if ! command_exists "$dep"; then missing_deps+=("$dep") fi done if [ ${#missing_deps[@]} -gt 0 ]; then print_error "Missing required dependencies: ${missing_deps[*]}" print_status "Please install the missing packages and try again." exit 1 fi } # Function to get version from Cargo.toml get_version_from_cargo() { if [ -f "Cargo.toml" ]; then grep '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/' | tr -d ' ' else echo "unknown" fi } # Function to get project name from Cargo.toml get_project_name_from_cargo() { if [ -f "Cargo.toml" ]; then grep '^name = ' Cargo.toml | sed 's/name = "\(.*\)"/\1/' | tr -d ' ' else echo "unknown" fi } # Function to check build environment check_build_environment() { print_status "Checking build environment..." # Check if we're in the right directory if [ ! -f "Cargo.toml" ]; then print_error "Cargo.toml not found. Please run this script from the project root." exit 1 fi # Check if debian directory exists if [ ! -d "debian" ]; then print_error "debian/ directory not found. Please ensure Debian packaging files are present." exit 1 fi # Validate required dependencies validate_dependencies dpkg-buildpackage dpkg-architecture # Check Rust environment if command_exists cargo; then print_status "Rust environment found:" cargo --version rustc --version else print_error "Cargo not found. Please ensure Rust is installed." print_status "You can install Rust using: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh" exit 1 fi # Check if we're on a Debian-based system if [ ! -f "/etc/debian_version" ]; then print_warning "This doesn't appear to be a Debian-based system." print_warning "Some features may not work correctly." fi } # Function to clean previous builds clean_previous_builds() { print_status "Cleaning previous build artifacts..." # Remove previous .deb files find . -maxdepth 1 -name "*.deb" -delete 2>/dev/null || true find . -maxdepth 1 -name "*.dsc" -delete 2>/dev/null || true find . -maxdepth 1 -name "*.tar.*" -delete 2>/dev/null || true find . -maxdepth 1 -name "*.buildinfo" -delete 2>/dev/null || true find . -maxdepth 1 -name "*.changes" -delete 2>/dev/null || true # Clean debian build directory if [ -d "debian/cargo" ]; then rm -rf debian/cargo fi } # Function to build the package build_package() { local build_opts=() print_status "Building apt-ostree package..." # Add build options build_opts+=(-us -uc -b) # No signing, no source package, binary only # Check if we want to build source package too if [ "${BUILD_SOURCE:-false}" = "true" ]; then build_opts=(-us -uc) # No signing, no source package fi # Check if we want to sign the package if [ "${SIGN_PACKAGE:-false}" = "true" ] && command_exists gpg; then build_opts=(-sa -k"${GPG_KEY:-}" -b) # Sign with specified key fi print_status "Running dpkg-buildpackage with options: ${build_opts[*]}" dpkg-buildpackage "${build_opts[@]}" } # Function to verify build results verify_build_results() { print_status "Verifying build results..." local deb_files=() local dsc_files=() local changes_files=() # Find built packages while IFS= read -r -d '' file; do deb_files+=("$file") done < <(find . -maxdepth 1 -name "*.deb" -print0 2>/dev/null) while IFS= read -r -d '' file; do dsc_files+=("$file") done < <(find . -maxdepth 1 -name "*.dsc" -print0 2>/dev/null) while IFS= read -r -d '' file; do changes_files+=("$file") done < <(find . -maxdepth 1 -name "*.changes" -print0 2>/dev/null) if [ ${#deb_files[@]} -gt 0 ]; then print_success "Built packages:" for file in "${deb_files[@]}"; do echo " - $(basename "$file")" done else print_error "No .deb files found!" exit 1 fi if [ ${#dsc_files[@]} -gt 0 ]; then print_status "Source package:" for file in "${dsc_files[@]}"; do echo " - $(basename "$file")" done fi if [ ${#changes_files[@]} -gt 0 ]; then print_status "Changes file:" for file in "${changes_files[@]}"; do echo " - $(basename "$file")" done fi } # Main execution main() { # Configuration PROJECT_NAME=$(get_project_name_from_cargo) VERSION=$(get_version_from_cargo) print_header "apt-ostree Debian Package Builder" print_status "Project: $PROJECT_NAME" print_status "Version: $VERSION" print_status "Build time: $(date)" # Check build environment check_build_environment # Clean previous builds clean_previous_builds # Build the package if build_package; then print_success "Package built successfully!" verify_build_results else print_error "Package build failed!" exit 1 fi print_success "Build completed successfully!" } # Handle command line arguments while [[ $# -gt 0 ]]; do case $1 in --build-source) BUILD_SOURCE=true shift ;; --sign-package) SIGN_PACKAGE=true shift ;; --gpg-key) GPG_KEY="$2" shift 2 ;; --help) echo "Usage: $0 [OPTIONS]" echo "Options:" echo " --build-source Build source package in addition to binary" echo " --sign-package Sign the package with GPG" echo " --gpg-key KEY GPG key to use for signing" echo " --help Show this help message" exit 0 ;; *) print_error "Unknown option: $1" print_status "Use --help for usage information" exit 1 ;; esac done # Run main function main "$@"