#!/bin/bash # rpm-ostree compatibility layer for Ubuntu uBlue apt-layer Tool # Provides 1:1 command compatibility with rpm-ostree # rpm-ostree install compatibility rpm_ostree_install() { local packages=("$@") log_info "rpm-ostree install compatibility: ${packages[*]}" "apt-layer" # Use live overlay for package installation if ! live_install "${packages[@]}"; then log_error "rpm-ostree install failed" "apt-layer" return 1 fi log_success "rpm-ostree install completed successfully" "apt-layer" return 0 } # rpm-ostree upgrade compatibility rpm_ostree_upgrade() { log_info "rpm-ostree upgrade compatibility" "apt-layer" # Use true system upgrade (not package upgrade) if ! system_upgrade; then log_error "rpm-ostree upgrade failed" "apt-layer" return 1 fi log_success "rpm-ostree upgrade completed successfully" "apt-layer" return 0 } # rpm-ostree rebase compatibility rpm_ostree_rebase() { local new_base="$1" log_info "rpm-ostree rebase compatibility: $new_base" "apt-layer" # Use intelligent rebase with conflict resolution if ! intelligent_rebase "$new_base"; then log_error "rpm-ostree rebase failed" "apt-layer" return 1 fi log_success "rpm-ostree rebase completed successfully" "apt-layer" return 0 } # rpm-ostree rollback compatibility rpm_ostree_rollback() { local target_commit="${1:-}" log_info "rpm-ostree rollback compatibility: ${target_commit:-latest}" "apt-layer" if [[ -z "$target_commit" ]]; then # Rollback to previous deployment target_commit=$(get_previous_deployment) if [[ -z "$target_commit" ]]; then log_error "No previous deployment found for rollback" "apt-layer" return 1 fi fi # Use commit-based rollback if ! commit_rollback "$target_commit"; then log_error "rpm-ostree rollback failed" "apt-layer" return 1 fi log_success "rpm-ostree rollback completed successfully" "apt-layer" return 0 } # rpm-ostree status compatibility rpm_ostree_status() { log_info "rpm-ostree status compatibility" "apt-layer" # Show atomic deployment status atomic_status # Show live overlay status echo "" echo "=== Live Overlay Status ===" get_live_overlay_status # Show package diff if pending deployment local pending_deployment pending_deployment=$(get_pending_deployment) if [[ -n "$pending_deployment" ]]; then echo "" echo "=== Pending Changes ===" show_package_diff "$(get_current_deployment)" "$pending_deployment" fi } # rpm-ostree diff compatibility rpm_ostree_diff() { local from_commit="${1:-}" local to_commit="${2:-}" log_info "rpm-ostree diff compatibility: $from_commit -> $to_commit" "apt-layer" # If no commits specified, compare current to pending if [[ -z "$from_commit" ]]; then from_commit=$(get_current_deployment) fi if [[ -z "$to_commit" ]]; then to_commit=$(get_pending_deployment) if [[ -z "$to_commit" ]]; then log_error "No target commit specified and no pending deployment" "apt-layer" return 1 fi fi # Show package-level diff show_package_diff "$from_commit" "$to_commit" } # rpm-ostree db list compatibility rpm_ostree_db_list() { log_info "rpm-ostree db list compatibility" "apt-layer" # List all deployments list_deployments } # rpm-ostree db diff compatibility rpm_ostree_db_diff() { local from_commit="${1:-}" local to_commit="${2:-}" log_info "rpm-ostree db diff compatibility: $from_commit -> $to_commit" "apt-layer" # If no commits specified, compare current to pending if [[ -z "$from_commit" ]]; then from_commit=$(get_current_deployment) fi if [[ -z "$to_commit" ]]; then to_commit=$(get_pending_deployment) if [[ -z "$to_commit" ]]; then log_error "No target commit specified and no pending deployment" "apt-layer" return 1 fi fi # Show detailed package diff show_detailed_package_diff "$from_commit" "$to_commit" } # rpm-ostree cleanup compatibility rpm_ostree_cleanup() { local purge="${1:-}" log_info "rpm-ostree cleanup compatibility: purge=$purge" "apt-layer" # Clean up old deployments cleanup_old_deployments # Clean up old ComposeFS images cleanup_old_composefs_images if [[ "$purge" == "--purge" ]]; then # Also clean up old bootloader entries cleanup_old_bootloader_entries fi log_success "rpm-ostree cleanup completed successfully" "apt-layer" } # rpm-ostree cancel compatibility rpm_ostree_cancel() { log_info "rpm-ostree cancel compatibility" "apt-layer" # Clear pending deployment clear_pending_deployment # Clean up live overlay stop_live_overlay log_success "rpm-ostree cancel completed successfully" "apt-layer" } # rpm-ostree initramfs compatibility rpm_ostree_initramfs() { local action="${1:-}" log_info "rpm-ostree initramfs compatibility: $action" "apt-layer" case "$action" in --enable) enable_initramfs_rebuild ;; --disable) disable_initramfs_rebuild ;; --rebuild) rebuild_initramfs ;; *) log_error "Invalid initramfs action: $action" "apt-layer" return 1 ;; esac } # rpm-ostree kargs compatibility rpm_ostree_kargs() { local action="${1:-}" shift log_info "rpm-ostree kargs compatibility: $action" "apt-layer" case "$action" in --get) get_kernel_args ;; --set) set_kernel_args "$@" ;; --append) append_kernel_args "$@" ;; --delete) delete_kernel_args "$@" ;; --reset) reset_kernel_args ;; *) log_error "Invalid kargs action: $action" "apt-layer" return 1 ;; esac } # rpm-ostree usroverlay compatibility rpm_ostree_usroverlay() { local action="${1:-}" log_info "rpm-ostree usroverlay compatibility: $action" "apt-layer" case "$action" in --mount) mount_usr_overlay ;; --unmount) unmount_usr_overlay ;; --status) usr_overlay_status ;; *) log_error "Invalid usroverlay action: $action" "apt-layer" return 1 ;; esac } # rpm-ostree composefs compatibility rpm_ostree_composefs() { local action="${1:-}" shift log_info "rpm-ostree composefs compatibility: $action" "apt-layer" case "$action" in --mount) composefs_mount "$@" ;; --unmount) composefs_unmount "$@" ;; --list) composefs_list_images ;; --info) composefs_image_info "$@" ;; *) log_error "Invalid composefs action: $action" "apt-layer" return 1 ;; esac } # Helper functions for rpm-ostree compatibility # Get previous deployment get_previous_deployment() { local current_deployment current_deployment=$(get_current_deployment) if [[ -n "$current_deployment" ]]; then local parent_commit parent_commit=$(jq -r ".deployments[\"$current_deployment\"].parent_commit" "$DEPLOYMENT_DB" 2>/dev/null || echo "") echo "$parent_commit" fi } # Show package diff between commits show_package_diff() { local from_commit="$1" local to_commit="$2" log_info "Showing package diff: $from_commit -> $to_commit" "apt-layer" # Get package lists from both commits local from_packages=() local to_packages=() if [[ -n "$from_commit" ]]; then from_packages=($(get_packages_from_commit "$from_commit")) fi if [[ -n "$to_commit" ]]; then to_packages=($(get_packages_from_commit "$to_commit")) fi # Calculate differences local added_packages=() local removed_packages=() local updated_packages=() # Find added packages for pkg in "${to_packages[@]}"; do if [[ ! " ${from_packages[*]} " =~ " ${pkg} " ]]; then added_packages+=("$pkg") fi done # Find removed packages for pkg in "${from_packages[@]}"; do if [[ ! " ${to_packages[*]} " =~ " ${pkg} " ]]; then removed_packages+=("$pkg") fi done # Show results if [[ ${#added_packages[@]} -gt 0 ]]; then echo "Added packages:" printf " %s\n" "${added_packages[@]}" fi if [[ ${#removed_packages[@]} -gt 0 ]]; then echo "Removed packages:" printf " %s\n" "${removed_packages[@]}" fi if [[ ${#added_packages[@]} -eq 0 ]] && [[ ${#removed_packages[@]} -eq 0 ]]; then echo "No package changes detected" fi } # Get packages from commit get_packages_from_commit() { local commit_id="$1" local composefs_image # Get ComposeFS image name composefs_image=$(jq -r ".deployments[\"$commit_id\"].composefs_image" "$DEPLOYMENT_DB" 2>/dev/null || echo "") if [[ -z "$composefs_image" ]]; then return 1 fi # Mount and extract package list local temp_mount="/tmp/apt-layer-commit-$$" mkdir -p "$temp_mount" if composefs_mount "$composefs_image" "$temp_mount"; then # Extract package list chroot "$temp_mount" dpkg -l | grep '^ii' | awk '{print $2}' 2>/dev/null || true # Cleanup composefs_unmount "$temp_mount" rmdir "$temp_mount" fi } # Cleanup functions cleanup_old_deployments() { log_info "Cleaning up old deployments..." "apt-layer" # Keep last 5 deployments local deployments deployments=($(jq -r '.deployments | keys[]' "$DEPLOYMENT_DB" 2>/dev/null | sort -r | tail -n +6)) for commit_id in "${deployments[@]}"; do log_info "Removing old deployment: $commit_id" "apt-layer" # Remove from database jq --arg commit_id "$commit_id" 'del(.deployments[$commit_id])' \ "$DEPLOYMENT_DB" > "${DEPLOYMENT_DB}.tmp" && mv "${DEPLOYMENT_DB}.tmp" "$DEPLOYMENT_DB" # Remove history file rm -f "$DEPLOYMENT_HISTORY_DIR/$commit_id.json" # Remove deployment directory rm -rf "/var/lib/particle-os/deployments/$commit_id" done } cleanup_old_composefs_images() { log_info "Cleaning up old ComposeFS images..." "apt-layer" # Get list of images still referenced by deployments local referenced_images referenced_images=($(jq -r '.deployments[].composefs_image' "$DEPLOYMENT_DB" 2>/dev/null || true)) # Get all ComposeFS images local all_images all_images=($(composefs_list_images)) # Remove unreferenced images for image in "${all_images[@]}"; do if [[ ! " ${referenced_images[*]} " =~ " ${image} " ]]; then log_info "Removing unreferenced image: $image" "apt-layer" composefs_remove_image "$image" fi done } cleanup_old_bootloader_entries() { log_info "Cleaning up old bootloader entries..." "apt-layer" # Get current and pending deployments local current_deployment current_deployment=$(get_current_deployment) local pending_deployment pending_deployment=$(get_pending_deployment) # Remove old bootloader entries local boot_dir="/boot/loader/entries" for entry in "$boot_dir"/apt-layer-*.conf; do if [[ -f "$entry" ]]; then local commit_id commit_id=$(basename "$entry" .conf | sed 's/apt-layer-//') # Keep current and pending deployments if [[ "$commit_id" != "$current_deployment" ]] && [[ "$commit_id" != "$pending_deployment" ]]; then log_info "Removing old bootloader entry: $entry" "apt-layer" rm -f "$entry" fi fi done }