2025-04-22 08:44:10 +02:00

306 lines
9.0 KiB
Bash
Raw Permalink 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.m3ta.dev/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.m3ta.dev/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.m3ta.dev/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
# Verify essential files exist before proceeding
if [ ! -f "config.json" ] || [ ! -d "env" ]; then
echo "❌ Error: Essential files missing. Are you in the correct directory?"
return 1
fi
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.m3ta.dev/m3tam3re/self-host-playbook?ref=v${target_version}" --dest "$CLONE_DIR" 2>/dev/null; then
echo "❌ Failed to clone repository"
return 1
fi
# Verify downloaded content
if [ ! -f "$CLONE_DIR/flake.nix" ]; then
echo "❌ Error: Downloaded content appears invalid"
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"/* .
# Verify essential files were copied
if [ ! -f "flake.nix" ]; then
echo "❌ Error: Failed to copy new version files"
return 1
fi
# Restore configuration files from backup with validation
echo "🔄 Restoring configuration files..."
if [ -f "${backup_dir}/config.json" ]; then
cp -r "${backup_dir}/config.json" . || {
echo "❌ Error: Failed to restore config.json"
return 1
}
fi
if [ -d "${backup_dir}/env" ]; then
cp -r "${backup_dir}/env" . || {
echo "❌ Error: Failed to restore env directory"
return 1
}
fi
return 0
}
setup_ssh_config() {
local username=$1
local ip_address=$2
local hostname=$3
local ssh_config_dir="$HOME/.ssh"
local ssh_config_file="$ssh_config_dir/config"
local ssh_key_file="$ssh_config_dir/self-host-playbook"
mkdir -p "$ssh_config_dir"
chmod 700 "$ssh_config_dir"
local config_entry="Host $hostname
HostName $ip_address
User $username
Port 2222
IdentityFile $ssh_key_file"
if ! grep -q "Host $hostname" "$ssh_config_file" 2>/dev/null; then
echo -e "\n$config_entry" >> "$ssh_config_file"
echo "✅ Added SSH config entry"
else
sed -i.bak "/Host $hostname/,/IdentityFile.*/{
s/HostName.*/HostName $ip_address/
s/User.*/User $username/
}" "$ssh_config_file"
echo "✅ Updated existing SSH config entry"
fi
chmod 600 "$ssh_config_file"
}
update_config_value() {
local key=$1
local value=$2
local config_file="config.json"
local config
config=$(cat "$config_file")
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
echo "$config" | jq '.' > "$config_file"
echo "✅ Updated $key in config.json"
}
install_deploy_rs() {
echo "🔧 Installing deploy-rs to user environment..."
if command -v deploy >/dev/null 2>&1; then
echo " deploy-rs is already installed"
return 0
fi
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 "======================================"
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 [ -z "$IP_ADDRESS" ]; then
echo " No IP address found in config.json"
read -p "Enter the IP address of your server: " IP_ADDRESS
if ! [[ $IP_ADDRESS =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Error: Invalid IP address format"
exit 1
fi
update_config_value "ipAddress" "$IP_ADDRESS"
fi
if [ -z "$HOSTNAME" ]; then
echo " No hostname found in config.json"
read -p "Enter the hostname for your server: " HOSTNAME
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_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
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/" \;
if perform_update "$LATEST_VERSION" "$backup_dir"; then
echo
echo "✅ Update completed successfully!"
echo
echo "🔧 Setting up SSH configuration..."
setup_ssh_config "$USERNAME" "$IP_ADDRESS" "$HOSTNAME"
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