Files
zosbuilder/scripts/lib/common.sh
Jan De Landtsheer 860b9aa161 feat: Implement complete Zero OS Alpine Initramfs Builder
- Complete bash framework with strict error handling
- Modular library system (docker, alpine, components, initramfs, kernel, testing)
- Rust component integration (zinit, rfs, mycelium) with musl targeting
- Rootless Docker/Podman support for GitHub Actions
- Centralized configuration in config/build.conf
- 2-stage module loading system
- Strip + UPX optimization for minimal size
- Complete zinit integration replacing OpenRC
- GitHub Actions CI/CD pipeline
- Comprehensive documentation and usage guides

Components:
- Latest stable kernel 6.12.44
- Alpine Linux 3.22 base
- ThreeFold components: zinit, mycelium, rfs, corex
- Target: ~8-12MB final initramfs.cpio.xz
2025-08-31 12:31:49 +02:00

238 lines
5.6 KiB
Bash

#!/bin/bash
# Common functions and utilities for Zero OS Alpine Initramfs Builder
# Strict error handling
set -euo pipefail
# Script directory detection (only if not already set)
if [[ -z "${SCRIPT_DIR:-}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
fi
if [[ -z "${PROJECT_ROOT:-}" ]]; then
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
fi
# Colors for output (if terminal supports it)
if [[ -t 1 ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
else
RED=''
GREEN=''
YELLOW=''
BLUE=''
NC=''
fi
# Logging functions
function log_info() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${GREEN}[INFO]${NC} ${timestamp} - $*" >&2
}
function log_warn() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${YELLOW}[WARN]${NC} ${timestamp} - $*" >&2
}
function log_error() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${RED}[ERROR]${NC} ${timestamp} - $*" >&2
}
function log_debug() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [[ "${DEBUG:-0}" == "1" ]]; then
echo -e "${BLUE}[DEBUG]${NC} ${timestamp} - $*" >&2
fi
}
# Command execution with full transparency
function safe_execute() {
local cmd="$*"
log_info "Executing: ${cmd}"
if [[ "${DEBUG:-0}" == "1" ]]; then
# In debug mode, show all output
if ! ${cmd}; then
log_error "Command failed: ${cmd}"
exit 1
fi
else
# Normal mode, capture output and show only on error
local output
if ! output=$(${cmd} 2>&1); then
log_error "Command failed: ${cmd}"
log_error "Output: ${output}"
exit 1
fi
fi
}
# Section headers with clear text separators
function section_header() {
local title="$1"
echo ""
echo "=================================================="
echo "SECTION: ${title}"
echo "=================================================="
log_info "Starting section: ${title}"
}
# Check if command exists
function command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Check if we're running in a container
function in_container() {
[[ -f /.dockerenv ]] || [[ -f /run/.containerenv ]] || grep -q 'container' /proc/1/cgroup 2>/dev/null
}
# Verify required tools are available
function check_dependencies() {
local missing_deps=()
# Core build tools
local required_tools=(
"git"
"wget"
"tar"
"gzip"
"xz"
"cpio"
"strip"
"upx"
"rustc"
"cargo"
)
for tool in "${required_tools[@]}"; do
if ! command_exists "$tool"; then
missing_deps+=("$tool")
fi
done
# Check for container runtime (if not in container)
if ! in_container; then
if ! command_exists "podman" && ! command_exists "docker"; then
missing_deps+=("podman or docker")
fi
fi
if [[ ${#missing_deps[@]} -gt 0 ]]; then
log_error "Missing required dependencies:"
for dep in "${missing_deps[@]}"; do
log_error " - $dep"
done
return 1
fi
log_info "All dependencies satisfied"
return 0
}
# Create directory safely
function safe_mkdir() {
local dir="$1"
log_debug "Creating directory: ${dir}"
safe_execute mkdir -p "$dir"
}
# Remove directory safely
function safe_rmdir() {
local dir="$1"
if [[ -d "$dir" ]]; then
log_debug "Removing directory: ${dir}"
safe_execute rm -rf "$dir"
fi
}
# Copy file/directory safely
function safe_copy() {
local src="$1"
local dst="$2"
log_debug "Copying: ${src} -> ${dst}"
safe_execute cp -r "$src" "$dst"
}
# Check if path is absolute
function is_absolute_path() {
[[ "$1" = /* ]]
}
# Resolve relative path to absolute
function resolve_path() {
local path="$1"
if is_absolute_path "$path"; then
echo "$path"
else
echo "$(pwd)/$path"
fi
}
# Get file size in human readable format
function get_file_size() {
local file="$1"
if [[ -f "$file" ]]; then
du -h "$file" | cut -f1
else
echo "0B"
fi
}
# Wait for file to exist with timeout
function wait_for_file() {
local file="$1"
local timeout="${2:-30}"
local count=0
while [[ ! -f "$file" && $count -lt $timeout ]]; do
sleep 1
((count++))
done
[[ -f "$file" ]]
}
# Cleanup function for traps
function cleanup_on_exit() {
local exit_code=$?
log_info "Build process exiting with code: ${exit_code}"
# Unmount any mounted filesystems
if [[ -n "${CLEANUP_MOUNTS:-}" ]]; then
for mount in $CLEANUP_MOUNTS; do
if mountpoint -q "$mount" 2>/dev/null; then
log_info "Unmounting: $mount"
umount "$mount" 2>/dev/null || true
fi
done
fi
exit $exit_code
}
# Set up exit trap
trap cleanup_on_exit EXIT INT TERM
# Load build configuration after functions are defined
BUILD_CONF="${PROJECT_ROOT}/config/build.conf"
if [[ -f "$BUILD_CONF" ]]; then
log_debug "Loading build configuration from: ${BUILD_CONF}"
source "$BUILD_CONF"
else
log_warn "Build configuration not found: ${BUILD_CONF}"
log_warn "Using default values"
fi
# Export common variables
export SCRIPT_DIR PROJECT_ROOT
export -f log_info log_warn log_error log_debug
export -f safe_execute section_header
export -f command_exists in_container check_dependencies
export -f safe_mkdir safe_rmdir safe_copy
export -f is_absolute_path resolve_path get_file_size wait_for_file