#!/bin/bash

# /etc/ports/drivers/rsync: rsync(1) driver script for ports(8)

set -euo pipefail

host=""
collection=""
destination=""
declare -A old_checkouts
declare -A new_checkouts

error() {
    echo "Error: $1 ($!)"
    echo "Updating failed"
    exit 1
}

warning() {
    echo "Warning: $1 ($!)"
}

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <file>"
    exit 1
fi

config_file="$1"

if [[ ! -f "$config_file" ]]; then
    error "Couldn't open $config_file"
fi

# Read config values
while IFS= read -r line; do
    if [[ "$line" =~ ^host=(.*) ]]; then
        host="${BASH_REMATCH[1]}"
    elif [[ "$line" =~ ^collection=(.*) ]]; then
        collection="${BASH_REMATCH[1]}"
    elif [[ "$line" =~ ^destination=(.*) ]]; then
        destination="${BASH_REMATCH[1]}"
    fi
done < "$config_file"

[[ -z "$host" ]] && error "Host field not set in $config_file"
[[ -z "$collection" ]] && error "Collection field not set in $config_file"
[[ -z "$destination" ]] && error "Destination field not set in $config_file"

# Read old .checkouts
if [[ -e "$destination/.checkouts" ]]; then
    while IFS= read -r line; do
        old_checkouts["$line"]=1
    done < "$destination/.checkouts"
fi

echo "Updating file list from $host::$collection"

# Get new checkouts
while IFS= read -r line; do
    [[ "$line" =~ ^MOTD: ]] && continue
    line="${line:43}"  # Skip first 43 chars
    [[ "$line" == "." ]] && continue
    new_checkouts["$line"]=1
done < <(rsync -crz --no-human-readable "$host::$collection") || error "Running rsync failed"

echo "Updating collection $(basename "$destination")"

# Run actual rsync
while IFS= read -r line; do
    if [[ "$line" =~ ^recv[[:space:]]+(.*) ]]; then
        file="${BASH_REMATCH[1]}"
        if [[ -n "${old_checkouts[$file]:-}" ]]; then
            echo " Edit $file"
        else
            echo " Checkout $file"
        fi
    else
        echo "$line"
    fi
done < <(rsync -crz --no-human-readable --log-format="%o %n" "$host::$collection" "$destination") || error "Running rsync failed"

# Save new checkouts
{
    for file in "${!new_checkouts[@]}"; do
        echo "$file"
    done | sort
} > "$destination/.checkouts" || error "Couldn't save checkouts to $destination/.checkouts"

# Simulate chroot by changing to destination
cd "$destination" || error "Couldn't chroot into $destination"

# Delete obsolete files
for file in "${!old_checkouts[@]}"; do
    if [[ -z "${new_checkouts[$file]:-}" ]]; then
        if [[ -f "$file" ]]; then
            echo " Delete $file"
            rm -f "$file" || warning "Couldn't delete $file"
        fi
    fi
done

# Delete obsolete directories
for file in "${!old_checkouts[@]}"; do
    if [[ -z "${new_checkouts[$file]:-}" ]]; then
        if [[ -d "$file" ]]; then
            echo " Delete $file"
            rmdir "$file" 2>/dev/null || warning "Couldn't delete $file"
        fi
    fi
done

echo "Finished successfully"

exit 0
