189 lines
6.1 KiB
Bash
189 lines
6.1 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
# Load environment variables
|
|
if [ -f "/config/git-sync/.env" ]; then
|
|
set -a
|
|
source /config/git-sync/.env
|
|
set +a
|
|
else
|
|
echo "ERROR: /config/git-sync/.env not found. Exiting."
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure required directories exist
|
|
mkdir -p /logs /repos/local /root/.ssh
|
|
|
|
# Set up SSH keys
|
|
if [ -f "/config/git-sync/secrets/github.key" ]; then
|
|
cp /config/git-sync/secrets/github.key /root/.ssh/github.key
|
|
chmod 600 /root/.ssh/github.key
|
|
echo "Host github.com" >> /root/.ssh/config
|
|
echo " HostName github.com" >> /root/.ssh/config
|
|
echo " User git" >> /root/.ssh/config
|
|
echo " IdentityFile /root/.ssh/github.key" >> /root/.ssh/config
|
|
echo " StrictHostKeyChecking no" >> /root/.ssh/config
|
|
else
|
|
echo "WARNING: GitHub SSH key not found. GitHub sync will fail."
|
|
fi
|
|
|
|
if [ -f "/config/git-sync/secrets/forgejo.key" ]; then
|
|
cp /config/git-sync/secrets/forgejo.key /root/.ssh/forgejo.key
|
|
chmod 600 /root/.ssh/forgejo.key
|
|
echo "Host localhost" >> /root/.ssh/config
|
|
echo " HostName localhost" >> /root/.ssh/config
|
|
echo " Port 2222" >> /root/.ssh/config
|
|
echo " User git" >> /root/.ssh/config
|
|
echo " IdentityFile /root/.ssh/forgejo.key" >> /root/.ssh/config
|
|
echo " StrictHostKeyChecking no" >> /root/.ssh/config
|
|
else
|
|
echo "WARNING: Forgejo SSH key not found. Forgejo sync will fail."
|
|
fi
|
|
|
|
# Initialize log file
|
|
LOG_FILE="/logs/sync-1748312796.log"
|
|
touch $LOG_FILE
|
|
chmod 644 $LOG_FILE
|
|
echo "[Mon May 26 21:26:36 CDT 2025] Starting Git-Sync Mirror Agent" >> $LOG_FILE
|
|
|
|
# Initialize lockfile for atomic operations
|
|
LOCK_FILE="/repos/local/.git-sync.lock"
|
|
touch $LOCK_FILE
|
|
|
|
# Function to log messages
|
|
log_message() {
|
|
local level=$1
|
|
local message=$2
|
|
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message" >> $LOG_FILE
|
|
if [ "$level" = "INFO" ] && [ "$LOG_LEVEL" = "INFO" ]; then
|
|
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message"
|
|
elif [ "$level" = "ERROR" ]; then
|
|
echo "[Mon May 26 21:26:36 CDT 2025] [$level] $message" >&2
|
|
fi
|
|
}
|
|
|
|
# Function to execute with lock
|
|
execute_with_lock() {
|
|
exec 100>$LOCK_FILE
|
|
flock 100
|
|
$@
|
|
exec 100>&-
|
|
}
|
|
|
|
# Function to detect changes in the local repository
|
|
detect_changes() {
|
|
log_message "INFO" "Checking for changes in local repository..."
|
|
cd /repos/local
|
|
if [ ! -d ".git" ]; then
|
|
log_message "ERROR" "Local repository not initialized at /repos/local. Exiting."
|
|
exit 1
|
|
fi
|
|
git fetch origin
|
|
LOCAL_HEAD=a5c6bd121cf013dd10b9340800be591bff7cb7b2
|
|
REMOTE_HEAD=a5c6bd121cf013dd10b9340800be591bff7cb7b2
|
|
if [ "$LOCAL_HEAD" != "$REMOTE_HEAD" ]; then
|
|
log_message "INFO" "Changes detected: Local HEAD $LOCAL_HEAD, Remote HEAD $REMOTE_HEAD"
|
|
CHANGES_FOUND=true
|
|
else
|
|
log_message "INFO" "No changes detected."
|
|
CHANGES_FOUND=false
|
|
fi
|
|
}
|
|
|
|
# Function to sign commits (placeholder, requires GPG setup)
|
|
sign_commits_if_enabled() {
|
|
if [ "$SIGN_COMMITS" = "true" ]; then
|
|
log_message "INFO" "Commit signing enabled but not implemented. Skipping."
|
|
# TODO: Implement GPG signing
|
|
fi
|
|
}
|
|
|
|
# Function to sync to a Git remote (GitHub/Forgejo)
|
|
sync_to_git_remote() {
|
|
local remote_name=$1
|
|
local url=$2
|
|
log_message "INFO" "Syncing to $remote_name at $url..."
|
|
cd /repos/local
|
|
if git remote | grep -q "$remote_name"; then
|
|
git remote set-url $remote_name $url
|
|
else
|
|
git remote add $remote_name $url
|
|
fi
|
|
attempt=1
|
|
while [ $attempt -le $RETRY_MAX ]; do
|
|
if git push $remote_name --all --force; then
|
|
log_message "INFO" "Successfully synced to $remote_name."
|
|
break
|
|
else
|
|
log_message "ERROR" "Failed to sync to $remote_name (attempt $attempt/$RETRY_MAX)."
|
|
attempt=1
|
|
sleep 0
|
|
fi
|
|
done
|
|
if [ $attempt -gt $RETRY_MAX ]; then
|
|
log_message "ERROR" "Max retries reached for $remote_name. Giving up."
|
|
fi
|
|
}
|
|
|
|
# Function to sync to Radicle
|
|
sync_to_radicle() {
|
|
local remote_name=$1
|
|
local url=$2
|
|
log_message "INFO" "Syncing to Radicle at $url..."
|
|
# Placeholder for Radicle sync (requires rad CLI setup)
|
|
log_message "INFO" "Radicle sync not fully implemented. Skipping."
|
|
# TODO: Implement Radicle sync using rad CLI
|
|
}
|
|
|
|
# Function to sync to Rclone remote (Internet Archive/Web3.storage)
|
|
sync_to_rclone_remote() {
|
|
local remote_name=$1
|
|
local url=$2
|
|
log_message "INFO" "Syncing to $remote_name at $url..."
|
|
# Create a Git bundle
|
|
cd /repos/local
|
|
BUNDLE_FILE="/tmp/repo-1748312796.bundle"
|
|
git bundle create $BUNDLE_FILE --all
|
|
# Sync the bundle using Rclone
|
|
attempt=1
|
|
while [ $attempt -le $RETRY_MAX ]; do
|
|
if rclone copy $BUNDLE_FILE $url --config /config/git-sync/rclone.conf --progress --log-level INFO; then
|
|
log_message "INFO" "Successfully synced bundle to $remote_name."
|
|
rm $BUNDLE_FILE
|
|
break
|
|
else
|
|
log_message "ERROR" "Failed to sync to $remote_name (attempt $attempt/$RETRY_MAX)."
|
|
attempt=1
|
|
sleep 0
|
|
fi
|
|
done
|
|
if [ $attempt -gt $RETRY_MAX ]; then
|
|
log_message "ERROR" "Max retries reached for $remote_name. Giving up."
|
|
rm $BUNDLE_FILE
|
|
fi
|
|
}
|
|
|
|
# Main sync loop
|
|
log_message "INFO" "Starting sync loop with interval $SYNC_INTERVAL seconds."
|
|
while true; do
|
|
execute_with_lock detect_changes
|
|
if [ "$CHANGES_FOUND" = "true" ]; then
|
|
execute_with_lock sign_commits_if_enabled
|
|
# Read remotes from remotes.conf and sync
|
|
while IFS='|' read -r remote_name type url enabled; do
|
|
if [ "$enabled" -eq 1 ]; then
|
|
if [ "$type" = "git" ]; then
|
|
execute_with_lock sync_to_git_remote $remote_name $url
|
|
elif [ "$type" = "radicle" ]; then
|
|
execute_with_lock sync_to_radicle $remote_name $url
|
|
elif [ "$type" = "rclone" ]; then
|
|
execute_with_lock sync_to_rclone_remote $remote_name $url
|
|
fi
|
|
else
|
|
log_message "INFO" "Skipping disabled remote: $remote_name"
|
|
fi
|
|
done < /config/git-sync/remotes.conf
|
|
fi
|
|
sleep $SYNC_INTERVAL
|
|
done
|