From 83faa356a1645229daaca3fe999b3e5e8f00a214 Mon Sep 17 00:00:00 2001 From: Joe Particle Date: Wed, 16 Jul 2025 16:49:15 +0000 Subject: [PATCH] fix: Resolve unbound variable issue in apt-layer.sh status command - Add default variable initialization to prevent unbound variable errors - Make path configuration loading optional with fallback values - Fix associative array syntax and enhance error handling - Status command now works correctly showing system directories and files - Update TODO and changelog with completion status - Ready for full integration testing with daemon --- .gitignore | 3 + TODO.md | 5 ++ apt-layer.sh | 46 ++++++++++----- src/apt-layer/CHANGELOG.md | 31 ++++++++++ src/apt-layer/compile-installer.sh | 0 src/apt-layer/compile.sh | 66 ++++++++++++++++++++++ src/apt-layer/scriptlets/08-system-init.sh | 42 ++++++++++---- src/apt-ostree.py/docs/CHANGELOG.md | 7 +++ 8 files changed, 174 insertions(+), 26 deletions(-) mode change 100644 => 100755 src/apt-layer/compile-installer.sh mode change 100644 => 100755 src/apt-layer/compile.sh diff --git a/.gitignore b/.gitignore index 4fffc3f..bb46a4a 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ __pycache__/ *.pyd .Python *.so + +# Test files +test*.py \ No newline at end of file diff --git a/TODO.md b/TODO.md index 7fbed02..c1949d8 100644 --- a/TODO.md +++ b/TODO.md @@ -73,6 +73,11 @@ - ✅ **Idle Management**: Proper idle timeout and shutdown handling - ✅ **Error Handling**: Proper shutdown and cleanup procedures - ✅ **Logging**: Comprehensive structured logging working correctly +- ✅ **apt-layer.sh Status Command**: Fixed unbound variable issue in status command + - Added default variable initialization to prevent unbound variable errors + - Made path configuration loading optional with fallback values + - Fixed associative array syntax and error handling + - Status command now works correctly showing system directories and files - 🎯 **D-Bus Method Testing**: Ready to test package management operations - 🎯 **apt-layer.sh Integration**: Ready to test shell script integration diff --git a/apt-layer.sh b/apt-layer.sh index f5bb62a..4a6980c 100755 --- a/apt-layer.sh +++ b/apt-layer.sh @@ -6,7 +6,7 @@ # DO NOT modify this file directly as it will be overwritten # # # # apt-layer Tool # -# Generated on: 2025-07-15 18:39:00 # +# Generated on: 2025-07-16 16:45:40 # # # ################################################################################################################ @@ -18,7 +18,7 @@ set -euo pipefail # Inspired by Vanilla OS Apx approach, ParticleOS apt-layer, and rpm-ostree live layering -# Version: 25.07.15 +# Version: 25.07.16 # apt-layer Tool # Enhanced with Container Support and LIVE SYSTEM LAYERING @@ -4815,14 +4815,32 @@ remove_apt_layer_system() { show_apt_layer_system_status() { log_info "apt-layer System Status:" "apt-layer" - # Load path configuration - if ! load_path_config; then - log_error "Failed to load path configuration" "apt-layer" - return 1 + # Initialize default values to prevent unbound variable errors + local APT_LAYER_WORKSPACE="${APT_LAYER_WORKSPACE:-/var/lib/apt-layer}" + local APT_LAYER_LOG_DIR="${APT_LAYER_LOG_DIR:-/var/log/apt-layer}" + local APT_LAYER_CACHE_DIR="${APT_LAYER_CACHE_DIR:-/var/cache/apt-layer}" + local BUILD_DIR="${BUILD_DIR:-$APT_LAYER_WORKSPACE/build}" + local LIVE_OVERLAY_DIR="${LIVE_OVERLAY_DIR:-$APT_LAYER_WORKSPACE/live-overlay}" + local COMPOSEFS_DIR="${COMPOSEFS_DIR:-$APT_LAYER_WORKSPACE/composefs}" + local OSTREE_COMMITS_DIR="${OSTREE_COMMITS_DIR:-$APT_LAYER_WORKSPACE/ostree-commits}" + local DEPLOYMENTS_DIR="${DEPLOYMENTS_DIR:-$APT_LAYER_WORKSPACE/deployments}" + local HISTORY_DIR="${HISTORY_DIR:-$APT_LAYER_WORKSPACE/history}" + local BOOTLOADER_STATE_DIR="${BOOTLOADER_STATE_DIR:-$APT_LAYER_WORKSPACE/bootloader}" + local TRANSACTION_STATE="${TRANSACTION_STATE:-$APT_LAYER_WORKSPACE/transaction-state}" + local DEPLOYMENT_DB="${DEPLOYMENT_DB:-$APT_LAYER_WORKSPACE/deployments.json}" + local CURRENT_DEPLOYMENT_FILE="${CURRENT_DEPLOYMENT_FILE:-$APT_LAYER_WORKSPACE/current-deployment}" + local PENDING_DEPLOYMENT_FILE="${PENDING_DEPLOYMENT_FILE:-$APT_LAYER_WORKSPACE/pending-deployment}" + local TRANSACTION_LOG="${TRANSACTION_LOG:-$APT_LAYER_WORKSPACE/transaction.log}" + + # Try to load path configuration (optional, will use defaults if it fails) + if load_path_config 2>/dev/null; then + log_debug "Path configuration loaded successfully" "apt-layer" + else + log_debug "Using default path configuration" "apt-layer" fi echo "=== Main Directories ===" - local main_dirs=( + declare -A main_dirs=( ["Workspace"]="$APT_LAYER_WORKSPACE" ["Logs"]="$APT_LAYER_LOG_DIR" ["Cache"]="$APT_LAYER_CACHE_DIR" @@ -4831,8 +4849,8 @@ show_apt_layer_system_status() { for name in "${!main_dirs[@]}"; do local dir="${main_dirs[$name]}" if [[ -d "$dir" ]]; then - local size=$(du -sh "$dir" 2>/dev/null | cut -f1) - local perms=$(stat -c "%a" "$dir" 2>/dev/null) + local size=$(du -sh "$dir" 2>/dev/null | cut -f1 || echo "unknown") + local perms=$(stat -c "%a" "$dir" 2>/dev/null || echo "unknown") echo "✅ $name: $dir ($size, perms: $perms)" else echo "❌ $name: $dir (not found)" @@ -4841,7 +4859,7 @@ show_apt_layer_system_status() { echo "" echo "=== Workspace Subdirectories ===" - local subdirs=( + declare -A subdirs=( ["Build"]="$BUILD_DIR" ["Live Overlay"]="$LIVE_OVERLAY_DIR" ["ComposeFS"]="$COMPOSEFS_DIR" @@ -4855,7 +4873,7 @@ show_apt_layer_system_status() { for name in "${!subdirs[@]}"; do local dir="${subdirs[$name]}" if [[ -d "$dir" ]]; then - local count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l) + local count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l || echo "0") echo "✅ $name: $dir ($count files)" else echo "❌ $name: $dir (not found)" @@ -4864,7 +4882,7 @@ show_apt_layer_system_status() { echo "" echo "=== System Files ===" - local files=( + declare -A files=( ["Deployment DB"]="$DEPLOYMENT_DB" ["Current Deployment"]="$CURRENT_DEPLOYMENT_FILE" ["Pending Deployment"]="$PENDING_DEPLOYMENT_FILE" @@ -4874,7 +4892,7 @@ show_apt_layer_system_status() { for name in "${!files[@]}"; do local file="${files[$name]}" if [[ -f "$file" ]]; then - local size=$(stat -c "%s" "$file" 2>/dev/null) + local size=$(stat -c "%s" "$file" 2>/dev/null || echo "unknown") echo "✅ $name: $file ($size bytes)" else echo "❌ $name: $file (not found)" @@ -4883,7 +4901,7 @@ show_apt_layer_system_status() { echo "" echo "=== Live Overlay Status ===" - if is_live_overlay_active; then + if is_live_overlay_active 2>/dev/null; then echo "🟡 Live overlay is ACTIVE" echo " Mount point: $LIVE_OVERLAY_DIR/mount" echo " Upper dir: $LIVE_OVERLAY_DIR/upper" diff --git a/src/apt-layer/CHANGELOG.md b/src/apt-layer/CHANGELOG.md index 2f572ee..e774a82 100644 --- a/src/apt-layer/CHANGELOG.md +++ b/src/apt-layer/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### [2025-07-16 UTC] - APT-LAYER.SH STATUS COMMAND: UNBOUND VARIABLE ISSUE RESOLVED +- **Major Fix**: Successfully resolved unbound variable issue in apt-layer.sh status command. +- **Status Command Enhancement**: Fixed `show_apt_layer_system_status()` function in system initialization scriptlet: + - **Default Variable Initialization**: Added fallback values for all variables using `${VAR:-default}` syntax + - **Optional Path Configuration**: Made JSON config loading optional - function continues with defaults if config can't be loaded + - **Associative Array Syntax**: Fixed from `local array=()` to `declare -A array=()` for proper associative array handling + - **Enhanced Error Handling**: Added fallback values for all commands with `|| echo "default"` syntax + - **Error Output Suppression**: Added `2>/dev/null` to prevent error messages from cluttering output +- **Variable Safety**: Prevented unbound variable errors for all path variables: + - `APT_LAYER_WORKSPACE`: Defaults to `/var/lib/apt-layer` + - `APT_LAYER_LOG_DIR`: Defaults to `/var/log/apt-layer` + - `APT_LAYER_CACHE_DIR`: Defaults to `/var/cache/apt-layer` + - All subdirectory and file paths: Proper fallback values based on workspace +- **Status Command Functionality**: Command now provides reliable system information: + - ✅ Main directories: Shows workspace, logs, and cache directories with size and permissions + - ✅ Workspace subdirectories: Shows build, live overlay, composefs, deployments, etc. + - ✅ System files: Shows deployment DB, transaction log, current/pending deployment files + - ✅ Live overlay status: Shows active/inactive state with mount information +- **Robust Error Handling**: Enhanced resilience against configuration issues: + - Graceful fallback when JSON configuration is unavailable + - Safe handling of missing directories and files + - Proper error suppression for clean output + - Default values ensure command always works +- **Integration Readiness**: apt-layer.sh status command now fully functional: + - ✅ No more unbound variable errors + - ✅ Reliable system status reporting + - ✅ Clean, informative output + - ✅ Robust error handling + - 🔄 Ready for full integration testing with daemon +- **Next Steps**: Proceed with D-Bus method testing and complete apt-layer.sh integration testing. + ### [2025-07-16 UTC] - DAEMON STARTUP SUCCESS: D-BUS INTERFACE PUBLISHING ACHIEVED - **Major Milestone**: Successfully achieved daemon startup and D-Bus interface publishing. - **Daemon Startup Success**: apt-ostree daemon now successfully starts and operates: diff --git a/src/apt-layer/compile-installer.sh b/src/apt-layer/compile-installer.sh old mode 100644 new mode 100755 diff --git a/src/apt-layer/compile.sh b/src/apt-layer/compile.sh old mode 100644 new mode 100755 index a3916b9..e199eef --- a/src/apt-layer/compile.sh +++ b/src/apt-layer/compile.sh @@ -121,6 +121,69 @@ convert_line_endings() { fi } +# --- Scriptlet/Function Dependency Validation --- +validate_scriptlet_dependencies() { + print_header "Validating Scriptlet and Function Dependencies" + local missing_scriptlets=() + local all_scriptlets=( + "00-header.sh" "01-dependencies.sh" "02-transactions.sh" "03-traditional.sh" "04-container.sh" \ + "05-live-overlay.sh" "06-oci-integration.sh" "07-bootloader.sh" "08-system-init.sh" \ + "09-atomic-deployment.sh" "10-rpm-ostree-compat.sh" "15-ostree-atomic.sh" \ + "20-daemon-integration.sh" "24-dpkg-direct-install.sh" "99-main.sh" + ) + # 1. Check all scriptlets exist + for s in "${all_scriptlets[@]}"; do + if [[ ! -f "$SCRIPTLETS_DIR/$s" ]]; then + print_error "Missing scriptlet: $s" + missing_scriptlets+=("$s") + fi + done + if [[ ${#missing_scriptlets[@]} -gt 0 ]]; then + print_error "Compilation aborted due to missing scriptlets." + exit 1 + fi + # 2. Parse for function definitions and calls + local defined_funcs=() + local called_funcs=() + for s in "${all_scriptlets[@]}"; do + local file="$SCRIPTLETS_DIR/$s" + # Find function definitions + while read -r line; do + if [[ "$line" =~ ^[[:space:]]*([a-zA-Z0-9_]+)[[:space:]]*\(\)[[:space:]]*\{ ]]; then + defined_funcs+=("${BASH_REMATCH[1]}") + fi + done < "$file" + # Find function calls (simple heuristic: foo ... or foo() ...) + while read -r line; do + if [[ "$line" =~ ^[[:space:]]*([a-zA-Z0-9_]+)[[:space:]]*\(\)?[[:space:]] ]]; then + called_funcs+=("${BASH_REMATCH[1]}") + fi + done < "$file" + done + # Remove duplicates + defined_funcs=( $(printf "%s\n" "${defined_funcs[@]}" | sort -u) ) + called_funcs=( $(printf "%s\n" "${called_funcs[@]}" | sort -u) ) + # 3. Warn if a function is called but not defined + local missing_funcs=() + for f in "${called_funcs[@]}"; do + if ! [[ " ${defined_funcs[*]} " =~ " $f " ]]; then + # Ignore bash builtins and common commands + if ! command -v "$f" &>/dev/null; then + print_warning "Function called but not defined: $f" + missing_funcs+=("$f") + fi + fi + done + # 4. Print summary + print_status "Function definitions found: ${#defined_funcs[@]}" + print_status "Function calls found: ${#called_funcs[@]}" + if [[ ${#missing_funcs[@]} -gt 0 ]]; then + print_warning "Missing function definitions: ${missing_funcs[*]}" + else + print_status "All called functions are defined or available as commands." + fi +} + # Get script directory and project root SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPTLETS_DIR="$SCRIPT_DIR/scriptlets" @@ -172,6 +235,9 @@ if [[ -d "$SCRIPT_DIR/config" ]]; then validate_json_files "$SCRIPT_DIR/config" fi +# Call validation before merging scriptlets +validate_scriptlet_dependencies + # Create temporary directory rm -rf "$TEMP_DIR" mkdir -p "$TEMP_DIR" diff --git a/src/apt-layer/scriptlets/08-system-init.sh b/src/apt-layer/scriptlets/08-system-init.sh index c4dd8ff..89de163 100644 --- a/src/apt-layer/scriptlets/08-system-init.sh +++ b/src/apt-layer/scriptlets/08-system-init.sh @@ -185,14 +185,32 @@ remove_apt_layer_system() { show_apt_layer_system_status() { log_info "apt-layer System Status:" "apt-layer" - # Load path configuration - if ! load_path_config; then - log_error "Failed to load path configuration" "apt-layer" - return 1 + # Initialize default values to prevent unbound variable errors + local APT_LAYER_WORKSPACE="${APT_LAYER_WORKSPACE:-/var/lib/apt-layer}" + local APT_LAYER_LOG_DIR="${APT_LAYER_LOG_DIR:-/var/log/apt-layer}" + local APT_LAYER_CACHE_DIR="${APT_LAYER_CACHE_DIR:-/var/cache/apt-layer}" + local BUILD_DIR="${BUILD_DIR:-$APT_LAYER_WORKSPACE/build}" + local LIVE_OVERLAY_DIR="${LIVE_OVERLAY_DIR:-$APT_LAYER_WORKSPACE/live-overlay}" + local COMPOSEFS_DIR="${COMPOSEFS_DIR:-$APT_LAYER_WORKSPACE/composefs}" + local OSTREE_COMMITS_DIR="${OSTREE_COMMITS_DIR:-$APT_LAYER_WORKSPACE/ostree-commits}" + local DEPLOYMENTS_DIR="${DEPLOYMENTS_DIR:-$APT_LAYER_WORKSPACE/deployments}" + local HISTORY_DIR="${HISTORY_DIR:-$APT_LAYER_WORKSPACE/history}" + local BOOTLOADER_STATE_DIR="${BOOTLOADER_STATE_DIR:-$APT_LAYER_WORKSPACE/bootloader}" + local TRANSACTION_STATE="${TRANSACTION_STATE:-$APT_LAYER_WORKSPACE/transaction-state}" + local DEPLOYMENT_DB="${DEPLOYMENT_DB:-$APT_LAYER_WORKSPACE/deployments.json}" + local CURRENT_DEPLOYMENT_FILE="${CURRENT_DEPLOYMENT_FILE:-$APT_LAYER_WORKSPACE/current-deployment}" + local PENDING_DEPLOYMENT_FILE="${PENDING_DEPLOYMENT_FILE:-$APT_LAYER_WORKSPACE/pending-deployment}" + local TRANSACTION_LOG="${TRANSACTION_LOG:-$APT_LAYER_WORKSPACE/transaction.log}" + + # Try to load path configuration (optional, will use defaults if it fails) + if load_path_config 2>/dev/null; then + log_debug "Path configuration loaded successfully" "apt-layer" + else + log_debug "Using default path configuration" "apt-layer" fi echo "=== Main Directories ===" - local main_dirs=( + declare -A main_dirs=( ["Workspace"]="$APT_LAYER_WORKSPACE" ["Logs"]="$APT_LAYER_LOG_DIR" ["Cache"]="$APT_LAYER_CACHE_DIR" @@ -201,8 +219,8 @@ show_apt_layer_system_status() { for name in "${!main_dirs[@]}"; do local dir="${main_dirs[$name]}" if [[ -d "$dir" ]]; then - local size=$(du -sh "$dir" 2>/dev/null | cut -f1) - local perms=$(stat -c "%a" "$dir" 2>/dev/null) + local size=$(du -sh "$dir" 2>/dev/null | cut -f1 || echo "unknown") + local perms=$(stat -c "%a" "$dir" 2>/dev/null || echo "unknown") echo "✅ $name: $dir ($size, perms: $perms)" else echo "❌ $name: $dir (not found)" @@ -211,7 +229,7 @@ show_apt_layer_system_status() { echo "" echo "=== Workspace Subdirectories ===" - local subdirs=( + declare -A subdirs=( ["Build"]="$BUILD_DIR" ["Live Overlay"]="$LIVE_OVERLAY_DIR" ["ComposeFS"]="$COMPOSEFS_DIR" @@ -225,7 +243,7 @@ show_apt_layer_system_status() { for name in "${!subdirs[@]}"; do local dir="${subdirs[$name]}" if [[ -d "$dir" ]]; then - local count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l) + local count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l || echo "0") echo "✅ $name: $dir ($count files)" else echo "❌ $name: $dir (not found)" @@ -234,7 +252,7 @@ show_apt_layer_system_status() { echo "" echo "=== System Files ===" - local files=( + declare -A files=( ["Deployment DB"]="$DEPLOYMENT_DB" ["Current Deployment"]="$CURRENT_DEPLOYMENT_FILE" ["Pending Deployment"]="$PENDING_DEPLOYMENT_FILE" @@ -244,7 +262,7 @@ show_apt_layer_system_status() { for name in "${!files[@]}"; do local file="${files[$name]}" if [[ -f "$file" ]]; then - local size=$(stat -c "%s" "$file" 2>/dev/null) + local size=$(stat -c "%s" "$file" 2>/dev/null || echo "unknown") echo "✅ $name: $file ($size bytes)" else echo "❌ $name: $file (not found)" @@ -253,7 +271,7 @@ show_apt_layer_system_status() { echo "" echo "=== Live Overlay Status ===" - if is_live_overlay_active; then + if is_live_overlay_active 2>/dev/null; then echo "🟡 Live overlay is ACTIVE" echo " Mount point: $LIVE_OVERLAY_DIR/mount" echo " Upper dir: $LIVE_OVERLAY_DIR/upper" diff --git a/src/apt-ostree.py/docs/CHANGELOG.md b/src/apt-ostree.py/docs/CHANGELOG.md index da66d7b..442db1d 100644 --- a/src/apt-ostree.py/docs/CHANGELOG.md +++ b/src/apt-ostree.py/docs/CHANGELOG.md @@ -228,6 +228,13 @@ - Clear explanation of root-only access requirements - Troubleshooting information for production deployment +- **Centralized all apt-ostree.py documentation in `src/apt-ostree.py/docs/` with a unified index in `readme.md`.** +- **Adopted double-underscore (`__`) convention for environment variable mapping to nested configuration keys.** +- **Enhanced configuration management: YAML schema validation, robust env var overrides, and comprehensive test coverage.** + +### Changed +- **Rationalized and clarified documentation files; each file now has a clear, single purpose and is linked from the main index.** + ## [0.1.0] - 2024-01-15 ### Added