self-host-playbook/update.sh
2025-04-11 09:36:53 +02:00

298 lines
8.9 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# Ensure we're in a flakes-enabled environment with required tools
if ! command -v nix &> /dev/null; then
echo "❌ Nix is not installed. Please install Nix first:"
echo "curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install"
exit 1
fi
# Check if we need to enter a new shell
if [ -z "${INSIDE_NIX_SHELL+x}" ]; then
export NIX_CONFIG="experimental-features = nix-command flakes"
export INSIDE_NIX_SHELL=1
exec nix shell nixpkgs#git nixpkgs#jq --command bash "$0"
fi
get_current_version() {
local version_file=$1
if [ -f "$version_file" ]; then
jq -r '.version' "$version_file"
else
echo "0.0.0"
fi
}
get_latest_version() {
local LATEST_VERSION
latest_version=$(curl -s "https://code.m3tam3re.com/api/v1/repos/m3tam3re/self-host-playbook/tags" | jq -r '.[] | select(.name | startswith("v")) | .name' | sort -V | tail -n1)
if [ -z "$latest_version" ]; then
echo "❌ Error: Could not fetch latest version from repository"
exit 1
fi
# Remove 'v' prefix if present and return
echo "${latest_version#v}"
}
check_compatibility() {
local current_version=$1
local target_version=$2
local version_file=$3
# Special case for initial install
if [ "$current_version" = "0.0.0" ]; then
echo " First time upgrade detected - proceeding with upgrade"
return 0
fi
local min_compatible_version
min_compatible_version=$(curl -s "https://code.m3tam3re.com/m3tam3re/self-host-playbook/raw/branch/develop/v${target_version}/$version_file" | jq -r '.minCompatibleVersion')
if version_lt "$current_version" "$min_compatible_version"; then
echo "❌ Your current version ($current_version) is too old for direct upgrade."
echo "Please upgrade to version $min_compatible_version first."
return 1
fi
return 0
}
# Show changelog - modified to use version file parameter
show_changelog() {
local current_version=$1
local target_version=$2
local version_file=$3
echo "📋 Changelog from $current_version to $target_version:"
echo "------------------------------------------------"
local changelog
changelog=$(curl -s "https://code.m3tam3re.com/m3tam3re/self-host-playbook/raw/branch/develop/v${target_version}/$version_file" | jq -r '.changelog')
# Process each version once, then all its changes
echo "$changelog" | jq -r --arg cv "$current_version" --arg tv "$target_version" '
to_entries[]
| select(.key > $cv and .key <= $tv)
| "\(.key):\n" + (.value | map(" - " + .) | join("\n"))
' 2>/dev/null
echo "------------------------------------------------"
}
perform_update() {
local target_version=$1
local backup_dir=$2
echo "⬇️ Downloading version $target_version..."
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT
# Create a subdirectory for the clone
CLONE_DIR="${TEMP_DIR}/clone"
mkdir -p "$CLONE_DIR"
# Clone to temporary directory with --quiet flag
if ! nix flake clone --quiet "git+https://code.m3tam3re.com/m3tam3re/self-host-playbook?ref=v${target_version}" --dest "$CLONE_DIR" 2>/dev/null; then
echo "❌ Failed to clone repository"
return 1
fi
# Remove current directory contents except backup
echo "🗑️ Cleaning current directory..."
find . -maxdepth 1 ! -name "." ! -name ".." ! -name "$backup_dir" -exec rm -rf {} +
# Copy new version from clone
echo "📋 Installing new version..."
cp -r "$CLONE_DIR"/* .
# Restore configuration files from backup
echo "🔄 Restoring configuration files..."
cp -r "${backup_dir}/config.json" \
"${backup_dir}/env" . 2>/dev/null || true
return 0
}
setup_ssh_config() {
local username=$1
local ip_address=$2
local ssh_config_dir="$HOME/.ssh"
local ssh_config_file="$ssh_config_dir/config"
local ssh_key_file="$ssh_config_dir/self-host-playbook"
# Create .ssh directory if it doesn't exist
mkdir -p "$ssh_config_dir"
chmod 700 "$ssh_config_dir"
# Create or append to SSH config
local config_entry="Host self-host-playbook
HostName $ip_address
User $username
Port 2222
IdentityFile $ssh_key_file"
# Check if entry already exists
if ! grep -q "Host self-host-playbook" "$ssh_config_file" 2>/dev/null; then
echo -e "\n$config_entry" >> "$ssh_config_file"
echo "✅ Added SSH config entry"
else
# Update existing entry
sed -i.bak "/Host self-host-playbook/,/IdentityFile.*/{
s/HostName.*/HostName $ip_address/
s/User.*/User $username/
}" "$ssh_config_file"
echo "✅ Updated existing SSH config entry"
fi
# Set appropriate permissions
chmod 600 "$ssh_config_file"
}
update_config_value() {
local key=$1
local value=$2
local config_file="config.json"
# Read existing config
local config
config=$(cat "$config_file")
# Update or add the field
if jq -e ".$key" "$config_file" >/dev/null 2>&1; then
config=$(echo "$config" | jq --arg key "$key" --arg value "$value" '.[$key] = $value')
else
config=$(echo "$config" | jq --arg key "$key" --arg value "$value" '. + {($key): $value}')
fi
# Write back to file
echo "$config" | jq '.' > "$config_file"
echo "✅ Updated $key in config.json"
}
install_deploy_rs() {
echo "🔧 Installing deploy-rs to user environment..."
# Check if deploy is already installed
if command -v deploy >/dev/null 2>&1; then
echo " deploy-rs is already installed"
return 0
fi
# Install deploy-rs using nix profile
if nix profile install 'github:serokell/deploy-rs'; then
echo "✅ deploy-rs installed successfully"
else
echo "❌ Failed to install deploy-rs"
return 1
fi
}
# Main script
echo "🔄 Self-Host Playbook Update Assistant"
echo "======================================"
# Check if we're in the right directory
if [ ! -f "config.json" ]; then
echo "❌ Error: config.json not found. Please run this script in your self-host-playbook directory."
exit 1
fi
USERNAME=$(jq -r '.username' config.json)
IP_ADDRESS=$(jq -r '.ipAddress // empty' config.json)
HOSTNAME=$(jq -r '.hostname // empty' config.json)
if [ -z "$USERNAME" ]; then
echo "❌ Error: Could not read username from config.json"
exit 1
fi
# If IP address is not in config.json, prompt for it
if [ -z "$IP_ADDRESS" ]; then
echo " No IP address found in config.json"
read -p "Enter the IP address of your server: " IP_ADDRESS
# Validate IP address format
if ! [[ $IP_ADDRESS =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Error: Invalid IP address format"
exit 1
fi
# Update config.json with the new IP address
update_config_value "ipAddress" "$IP_ADDRESS"
fi
# If hostname is not in config.json, prompt for it
if [ -z "$HOSTNAME" ]; then
echo " No hostname found in config.json"
read -p "Enter the hostname for your server: " HOSTNAME
# Validate hostname format (basic validation)
if ! [[ $HOSTNAME =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$ ]]; then
echo "❌ Error: Invalid hostname format"
exit 1
fi
# Update config.json with the new hostname
update_config_value "hostname" "$HOSTNAME"
fi
VERSION_FILE="version.json"
CURRENT_VERSION=$(get_current_version "$VERSION_FILE")
LATEST_VERSION=$(get_latest_version)
echo "Current version: $CURRENT_VERSION"
echo "Latest version: $LATEST_VERSION"
echo
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo "✅ You are already on the latest version!"
exit 0
fi
if ! check_compatibility "$CURRENT_VERSION" "$LATEST_VERSION" "$VERSION_FILE"; then
exit 1
fi
show_changelog "$CURRENT_VERSION" "$LATEST_VERSION" "$VERSION_FILE"
echo
read -p "Do you want to update to version $LATEST_VERSION? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Create backup
backup_dir="backup_${CURRENT_VERSION}_$(date +%Y%m%d_%H%M%S)"
echo "📑 Creating backup in $backup_dir..."
mkdir -p "$backup_dir"
find . -maxdepth 1 ! -name "." ! -name ".." ! -name "$backup_dir" -exec cp -r {} "$backup_dir/" \;
# Perform update
if perform_update "$LATEST_VERSION" "$backup_dir"; then
echo
echo "✅ Update completed successfully!"
# Setup SSH configuration
echo
echo "🔧 Setting up SSH configuration..."
setup_ssh_config "$USERNAME" "$IP_ADDRESS"
echo
install_deploy_rs
echo "🚀 Applying the update to your system..."
deploy .#$HOSTNAME
echo
echo "If you encounter any issues, your backup is available in $backup_dir"
else
echo "❌ Update failed. Your backup is available in $backup_dir"
exit 1
fi
else
echo "Update cancelled."
exit 1
fi