particle-os-modules/modules/apt/apt-wrapper.sh
2025-08-27 19:42:18 -07:00

276 lines
9.5 KiB
Bash

#!/bin/bash
set -euo pipefail
# Log function
log() {
echo "[APT-WRAPPER] $1"
}
# Function to add repository files
add_repos() {
local repos_config="$1"
local cleanup=false
# Check if cleanup is enabled
if echo "$repos_config" | jq -e '.cleanup' >/dev/null 2>&1; then
cleanup=$(echo "$repos_config" | jq -r '.cleanup')
fi
# Add repository files
if echo "$repos_config" | jq -e '.files' >/dev/null 2>&1; then
local files=$(echo "$repos_config" | jq -r '.files[]? // empty')
for file in $files; do
if [[ $file == http* ]]; then
log "Downloading repository file: $file"
curl -fsSL "$file" -o "/etc/apt/sources.list.d/$(basename "$file")"
else
log "Copying repository file: $file"
cp "$file" "/etc/apt/sources.list.d/"
fi
done
fi
# Add PPA repositories
if echo "$repos_config" | jq -e '.ppa' >/dev/null 2>&1; then
local ppas=$(echo "$repos_config" | jq -r '.ppa[]? // empty')
for ppa in $ppas; do
log "Adding PPA: $ppa"
add-apt-repository -y "$ppa"
done
fi
# Add GPG keys
if echo "$repos_config" | jq -e '.keys' >/dev/null 2>&1; then
local keys=$(echo "$repos_config" | jq -r '.keys[]? // empty')
for key in $keys; do
if [[ $key == http* ]]; then
log "Downloading and adding GPG key: $key"
curl -fsSL "$key" | apt-key add -
else
log "Adding GPG key: $key"
apt-key add "$key"
fi
done
fi
# Enable backports if requested
if echo "$repos_config" | jq -e '.backports' >/dev/null 2>&1; then
local backports=$(echo "$repos_config" | jq -r '.backports')
if [ "$backports" = "true" ]; then
log "Enabling backports repository"
echo "deb http://deb.debian.org/debian $(lsb_release -cs)-backports main" > /etc/apt/sources.list.d/backports.list
fi
fi
# Update package lists
log "Updating package lists"
apt-get update
# Clean up repositories if requested
if [ "$cleanup" = "true" ]; then
log "Cleaning up added repositories"
rm -f /etc/apt/sources.list.d/*.list
apt-get update
fi
}
# Function to handle /opt/ symlinking
handle_optfix() {
local optfix_config="$1"
if [ -n "$optfix_config" ]; then
local optfixes=$(echo "$optfix_config" | jq -r '.[]? // empty')
for optfix in $optfixes; do
log "Setting up /opt/ symlink for: $optfix"
mkdir -p "/opt/$optfix"
ln -sf "/opt/$optfix" "/usr/local/$optfix"
done
fi
}
# Function to install packages
install_packages() {
local install_config="$1"
local skip_unavailable=false
# Check if skip-unavailable is enabled
if echo "$install_config" | jq -e '.skip-unavailable' >/dev/null 2>&1; then
skip_unavailable=$(echo "$install_config" | jq -r '.skip-unavailable')
fi
# Install packages
if echo "$install_config" | jq -e '.packages' >/dev/null 2>&1; then
local packages=$(echo "$install_config" | jq -r '.packages[]? // empty')
for package in $packages; do
if echo "$package" | jq -e '.repo' >/dev/null 2>&1; then
# Package from specific repository
local repo=$(echo "$package" | jq -r '.repo')
local repo_packages=$(echo "$package" | jq -r '.packages[]? // empty')
for repo_package in $repo_packages; do
log "Installing $repo_package from repository $repo"
apt-get install -y "$repo_package" || {
if [ "$skip_unavailable" = "true" ]; then
log "WARNING: Package $repo_package not available, skipping"
else
log "ERROR: Failed to install package $repo_package"
exit 1
fi
}
done
else
# Direct package specification
if [[ $package == http* && $package == *.deb ]]; then
log "Downloading and installing .deb package: $package"
curl -fsSL "$package" -o /tmp/package.deb
dpkg -i /tmp/package.deb || apt-get install -f -y
rm -f /tmp/package.deb
else
log "Installing package: $package"
apt-get install -y "$package" || {
if [ "$skip_unavailable" = "true" ]; then
log "WARNING: Package $package not available, skipping"
else
log "ERROR: Failed to install package $package"
exit 1
fi
}
fi
fi
done
fi
}
# Function to remove packages
remove_packages() {
local remove_config="$1"
if echo "$remove_config" | jq -e '.packages' >/dev/null 2>&1; then
local packages=$(echo "$remove_config" | jq -r '.packages[]? // empty')
for package in $packages; do
log "Removing package: $package"
apt-get remove -y "$package" || {
log "WARNING: Failed to remove package $package"
}
done
fi
}
# Function to replace packages
replace_packages() {
local replace_config="$1"
if echo "$replace_config" | jq -e '.[]' >/dev/null 2>&1; then
local replacements=$(echo "$replace_config" | jq -c '.[]')
echo "$replacements" | while read -r replacement; do
local from_repo=$(echo "$replacement" | jq -r '.from-repo // empty')
local packages=$(echo "$replacement" | jq -r '.packages[]? // empty')
local skip_unavailable=$(echo "$replacement" | jq -r '.skip-unavailable // false')
log "Replacing packages from repository: $from_repo"
for package in $packages; do
log "Replacing package: $package"
apt-get install -y "$package" || {
if [ "$skip_unavailable" = "true" ]; then
log "WARNING: Package $package not available, skipping"
else
log "ERROR: Failed to replace package $package"
exit 1
fi
}
done
done
fi
}
# Function to install task packages
install_tasks() {
local task_config="$1"
if echo "$task_config" | jq -e '.packages' >/dev/null 2>&1; then
local with_optional=$(echo "$task_config" | jq -r '.with-optional // false')
local packages=$(echo "$task_config" | jq -r '.packages[]? // empty')
for task in $packages; do
log "Installing task: $task"
if [ "$with_optional" = "true" ]; then
tasksel install "$task" || {
log "WARNING: Failed to install task $task"
}
else
tasksel install "$task" || {
log "WARNING: Failed to install task $task"
}
fi
done
fi
}
# Function to remove task packages
remove_tasks() {
local task_config="$1"
if echo "$task_config" | jq -e '.packages' >/dev/null 2>&1; then
local packages=$(echo "$task_config" | jq -r '.packages[]? // empty')
for task in $packages; do
log "Removing task: $task"
tasksel remove "$task" || {
log "WARNING: Failed to remove task $task"
}
done
fi
}
# Main execution
main() {
local module_config="$1"
log "Starting apt module execution"
# Handle repositories
if echo "$module_config" | jq -e '.repos' >/dev/null 2>&1; then
log "Processing repositories configuration"
add_repos "$(echo "$module_config" | jq -c '.repos')"
fi
# Handle /opt/ symlinking
if echo "$module_config" | jq -e '.optfix' >/dev/null 2>&1; then
log "Processing optfix configuration"
handle_optfix "$(echo "$module_config" | jq -c '.optfix')"
fi
# Handle package installation
if echo "$module_config" | jq -e '.install' >/dev/null 2>&1; then
log "Processing package installation"
install_packages "$(echo "$module_config" | jq -c '.install')"
fi
# Handle package removal
if echo "$module_config" | jq -e '.remove' >/dev/null 2>&1; then
log "Processing package removal"
remove_packages "$(echo "$module_config" | jq -c '.remove')"
fi
# Handle package replacement
if echo "$module_config" | jq -e '.replace' >/dev/null 2>&1; then
log "Processing package replacement"
replace_packages "$(echo "$module_config" | jq -c '.replace')"
fi
# Handle task installation
if echo "$module_config" | jq -e '.task-install' >/dev/null 2>&1; then
log "Processing task installation"
install_tasks "$(echo "$module_config" | jq -c '.task-install')"
fi
# Handle task removal
if echo "$module_config" | jq -e '.task-remove' >/dev/null 2>&1; then
log "Processing task removal"
remove_tasks "$(echo "$module_config" | jq -c '.task-remove')"
fi
# Clean up
log "Cleaning up package cache"
apt-get clean
apt-get autoremove -y
log "apt module execution completed successfully"
}
# Execute main function with the module configuration
main "$1"