forked from tfgrid/zosbuilder
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
This commit is contained in:
238
scripts/lib/common.sh
Normal file
238
scripts/lib/common.sh
Normal file
@@ -0,0 +1,238 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user