fix: Resolve unbound variable issue in apt-layer.sh status command
Some checks failed
Compile apt-layer (v2) / compile (push) Failing after 3h12m36s

- 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
This commit is contained in:
Joe Particle 2025-07-16 16:49:15 +00:00
parent 6883cadf4d
commit 83faa356a1
8 changed files with 174 additions and 26 deletions

3
.gitignore vendored
View file

@ -88,3 +88,6 @@ __pycache__/
*.pyd
.Python
*.so
# Test files
test*.py

View file

@ -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

View file

@ -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"

View file

@ -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:

0
src/apt-layer/compile-installer.sh Normal file → Executable file
View file

66
src/apt-layer/compile.sh Normal file → Executable file
View file

@ -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"

View file

@ -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"

View file

@ -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