Remove old backups scriptΒΆ
This backup script removes old backups from a directory BACKUP_DIR. It keeps a total of MAX_BACKUPS backups that are distributed over an interval starting from a date saved in FIRST_BACKUP_FILE ending at the current time. More recent dates have a higher priority.
Currently increasing MAX_BACKUPS only has an effect of additionally keeping more recent backups and not older ones.
This script is used in in the Nextcloud configuration manual.
#!/usr/bin/env python3
from datetime import datetime
from pathlib import Path
# Configuration
BACKUP_DIR = Path("/var/backups")
FIRST_BACKUP_FILE = BACKUP_DIR / "first-backup-date.txt"
MAX_BACKUPS = 20
BACKUP_TIME_FORMAT = "%Y-%m-%d-%H-%M"
def load_first_backup_time():
with open(FIRST_BACKUP_FILE, "r") as f:
return datetime.strptime(
f.read().strip(),
BACKUP_TIME_FORMAT
)
def load_backups():
backups = []
for entry in BACKUP_DIR.glob("*.tar.gz"):
timestamp = entry.name.removesuffix(".tar.gz")
try:
backup_time = datetime.strptime(
timestamp,
BACKUP_TIME_FORMAT
)
backups.append((entry, backup_time))
except ValueError:
continue
backups.sort(key=lambda x: x[1])
return backups
def generate_target_points(first_backup_time, now, count):
if count <= 0:
return []
points = [now]
if count == 1:
return points
second = first_backup_time + (now - first_backup_time) / 2
points.append(second)
while len(points) < count:
previous = points[-1]
points.append(
previous + (now - previous) / 2
)
return points
def select_backups(backups, target_points):
available = list(backups)
selected = []
for point in target_points:
if not available:
break
nearest = min(
available,
key=lambda backup: abs(
(backup[1] - point).total_seconds()
)
)
selected.append(nearest)
available.remove(nearest)
return selected
def main():
first_backup_time = load_first_backup_time()
now = datetime.now()
backups = load_backups()
if len(backups) <= MAX_BACKUPS:
print(
f"{len(backups)} backups found, "
"nothing to delete."
)
return
target_points = generate_target_points(
first_backup_time,
now,
MAX_BACKUPS
)
selected = select_backups(
backups,
target_points
)
selected_files = {
backup[0]
for backup in selected
}
print("Keeping:")
for backup_file, backup_time in sorted(
selected,
key=lambda x: x[1]
):
print(f" {backup_file.name}")
print("\nDeleting:")
deleted_count = 0
for backup_file, backup_time in backups:
if backup_file in selected_files:
continue
print(f" {backup_file.name}")
backup_file.unlink()
deleted_count += 1
print(
f"\nFinished. "
f"Kept {len(selected_files)} backups, "
f"deleted {deleted_count}."
)
if __name__ == "__main__":
main()