#=============================================================================== # Script Name: svn_backup_full.sh # Description: svn repos full backup # keep recent 3 backups # # # Author: Wang Huaizhuang # Email: [email protected] # Created Date: 2024-12-12 # Last Modified: 2024-12-17 # Version: 1.0 # # Usage: ./svn_backup_full.sh # # # Requirements: - pigz # - gzip # # Notes: Special considerations or limitations of the script # - Make sure there is enough space on your servers # - A temp dir will be created during the backup process # # # License: GPL #===============================================================================
# Logging function with timestamp log() { echo"[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOGFILE" }
# Make sure backup is required should_backup() { local repo="$1" local curr_version curr_version=$(svnlook youngest "$SVN_REPOS_PATH/$repo") local recent_backups recent_backups=$(find "$BACKUP_BASE_DIR/$repo" -name "${repo}-*-full-*.tar.gz" | sort -r) # Check if any of these backups contain the current revision for backup_file in$recent_backups; do if [[ "$backup_file" == *"full-${curr_version}"* ]]; then ((NOT_UPDATE++)) return 1 # No backup needed fi done return 0 # Backup needed }
# SVN full backup function full_backup() { # Get list of SVN repos mapfile -t REPOS < <(ls"$SVN_REPOS_PATH") TOTAL_REPOS=${#REPOS[@]} log"============ STARTING BACKUP ===============" log"Total number of SVN repositories: $TOTAL_REPOS" # For each SVN repos for repo in"${REPOS[@]}"; do if ! should_backup "$repo"; then log"Repository: $repo - No updates, skipping backup" continue fi mkdir -p "$BACKUP_TMP_DIR/$repo" mkdir -p "$BACKUP_BASE_DIR/$repo" latest_revision=$(svnlook youngest "$SVN_REPOS_PATH/$repo") backup_filename="${repo}-${DATE}-full-${latest_revision}.tar.gz" log"Starting backup for repository: $repo" if ( svnadmin hotcopy "$SVN_REPOS_PATH/$repo""$BACKUP_TMP_DIR/$repo" && tar -c "$BACKUP_TMP_DIR/$repo" | pigz -9 -p 8 > "$BACKUP_BASE_DIR/$repo/$backup_filename" && # Delete temp file rm -rf "$BACKUP_TMP_DIR/$repo" ); then ((SUCCESSFUL_BACKUPS++)) log"Repository: $repo - Backup Succeeded: $backup_filename (Revision: $latest_revision)" else ((FAILED_BACKUPS++)) log"ERROR: Repository: $repo - Backup Failed!" svnlook youngest "$SVN_REPOS_PATH/$repo" || log"Cannot retrieve revision" fi done }
# Cleanup old backups cleanup_old_backups() { log"============ STARTING CLEATUP ==============" # Check backup dir [[ -d "$BACKUP_BASE_DIR" ]] || { log"Backup directory $BACKUP_BASE_DIR does not exist" return 1 } # For each SVN repos for repo_dir in"$BACKUP_BASE_DIR"/*; do # make sure dir exsit and not empty [[ -d "$repo_dir" && -n "$(ls -A "$repo_dir")" ]] || continue # get all backups, sort by time local repo_name=$(basename"$repo_dir") local -a full_backups=() while IFS= read -r -d '' backup; do full_backups+=("$backup") done < <(find "$repo_dir" -maxdepth 1 -type f -name "*-full-*.tar.gz" -print0 | sort -zr) # keep 3 backups local backup_count=${#full_backups[@]} if [[ $backup_count -gt 3 ]]; then for ((i=3; i<backup_count; i++)); do log"Removing old backup for $repo_name: ${full_backups[i]}" rm -f "${full_backups[i]}" done log"Removed $((backup_count - 3)) old backups for $repo_name" else log"Keeping all $backup_count backups for $repo_name" fi done log"Old backups cleanup completed" }