dots/scripts/backup
2023-05-26 20:21:59 -04:00

150 lines
3.1 KiB
Bash
Executable file

#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s nullglob
source "$DOTS/config/zsh/config/colors.zsh" && define_colors
LOCAL_BACKUP_PATH="$HOME/Drives/Backups/auto-backups/"
REMOTE_BACKUP_PATH="auto-backups"
RCLONE_CLOUD_NAME="mega"
DATE_FORMAT="+%F"
# sources can be any rsync accepted path
SOURCES=(
"$HOME/Drives/Stuff/Pictures/"
"$HOME/Drives/Stuff/Music/"
"root@berry.net:/home/aleidk/services/"
)
MAX_BACKUPS=10
ensure_path_exist() {
path="$1"
shift
if [[ ! -d "$path" ]]; then
echo -e "Path ${RED}$path${RST} doesn't exist, ${GRN}creating...${RST}"
mkdir -p "$path"
fi
}
backup() {
src="$1"
shift
dst="$LOCAL_BACKUP_PATH"
name="$(basename "$src")"
dst="${dst}${name}"
date=$(date "$DATE_FORMAT")
# Config
SNAP="${dst}/${date}"
LAST="${dst}/last"
PARTIAL="${dst}/.partial_${date}"
# Check partial backups (failed)
if [[ -d "$SNAP" && ! -d "$PARTIAL" ]]; then
echo -e "${MGN}${DIM}Backup for $date already crated, skiping...${RST}"
return
else
echo -e "Backing up ${BLU}$dst${RST}"
fi
# shellcheck disable=2086
rsync \
--fake-super \
--compress \
--mkpath \
--archive \
--human-readable \
--delete \
--filter='dir-merge /.sync-exclude' \
--exclude="**/.sync-exclude" \
--partial \
--partial-dir="$PARTIAL" \
--info=none,progress2 \
--link-dest="$LAST" \
"$src" "$SNAP"
# Update symlink to last backup
rm -f "$LAST"
ln -s "$SNAP" "$LAST"
# clean failed backups
for dir in $dst/.partial_*; do
date="$(echo "$dir" | cut -d "_" -f 2)"
rm -r "$dir" "${dst:?}/${date}"
done
echo -e ""
}
delete_old() {
src="$1"
shift
dst="$LOCAL_BACKUP_PATH"
name="$(basename "$src")"
dst="${dst}${name}"
bkp_count="$(fd -t d --exact-depth 1 . "$dst" | wc -l)"
while [[ $bkp_count -gt $MAX_BACKUPS ]]; do
oldest_dir="$(fd -t d --exact-depth 1 . "$dst" | sort | head -n 1)"
echo -e "Max backups exceed for ${BLU}$name${RST}, deleting ${RED}$(basename "$oldest_dir")${RST}..."
rm -rf "$oldest_dir"
bkp_count="$(fd -t d --exact-depth 1 . "${dst}" | wc -l)"
done
echo ""
}
sync() {
config="$(rclone config dump 2>/dev/null | jq ".$RCLONE_CLOUD_NAME // empty")"
if [[ -z "$config" ]]; then
echo -e "${RED}${SHL}No Rclone configuration! skiping sync.${RST}${EHL}\n"
return
fi
for dir in $LOCAL_BACKUP_PATH/*; do
name="$(basename "$dir")"
remote_path="${RCLONE_CLOUD_NAME}:${REMOTE_BACKUP_PATH}/${name}"
newest="$(fd -t d --exact-depth 1 . "$dir" | sort -r | head -n 1)"
today=$(date "$DATE_FORMAT")
if [[ "$today" == "$(rclone cat "${remote_path}/.last-sync" 2>/dev/null)" ]]; then
echo -e "${MGN}${DIM}Last sync ${BLU}for${RST} $name was today, skiping...${RST}"
continue
else
echo -e "Syncthing latest backup for ${BLU}$name${RST} in ${RED}$remote_path${RST}"
fi
rclone sync \
--copy-links \
--progress \
--stats-one-line \
"$newest" "$remote_path"
echo "$today" | rclone rcat "${remote_path}/.last-sync"
done
echo ""
}
ensure_path_exist "$LOCAL_BACKUP_PATH"
for path in "${SOURCES[@]}"; do
backup "$path"
delete_old "$path"
done
# Sync to MEGA
# sync
echo -e "${GRN}Backups done!${RST}"