cura-te-ipsum/spqr/curateipsum/backup.py

85 lines
2.4 KiB
Python

"""
Module with backup functions.
"""
import logging
import os
import pathlib
import shutil
from datetime import datetime
from typing import Optional
import spqr.curateipsum.fs as fs
BACKUP_ENT_FMT = "%y%m%d_%H%M"
_lg = logging.getLogger(__name__)
def _is_backup_entity(entity_path: pathlib.Path) -> bool:
""" Check if entity_path is a single backup dir. """
try:
datetime.strptime(entity_path.name, BACKUP_ENT_FMT)
return True
except ValueError:
return False
def _get_latest_backup(backup_dir: pathlib.Path) -> Optional[pathlib.Path]:
""" Returns path to latest backup created in backup_dir or None. """
backups = sorted(os.listdir(backup_dir), reverse=True)
for b_ent in backups:
b_ent_abs = pathlib.Path(os.path.join(backup_dir, b_ent))
if not _is_backup_entity(b_ent_abs):
continue
if not os.listdir(b_ent_abs):
_lg.info("Removing empty backup entity: %s", b_ent_abs.name)
_lg.debug("Removing directory %s", b_ent_abs)
os.rmdir(b_ent_abs)
continue
return b_ent_abs
return None
def initiate_backup(sources, backup_dir: pathlib.Path, dry_run=False):
""" Main backup function """
cur_backup = pathlib.Path(
os.path.join(backup_dir, datetime.now().strftime(BACKUP_ENT_FMT))
)
_lg.debug("Current backup dir: %s", cur_backup)
latest_backup = _get_latest_backup(backup_dir)
if cur_backup == latest_backup:
_lg.warning(
"Latest backup %s was created less than minute ago, exiting",
latest_backup.name,
)
return
if latest_backup is None:
_lg.info("Creating empty directory for current backup: %s", cur_backup.name)
os.mkdir(cur_backup)
else:
_lg.info(
"Copying data from latest backup %s to current backup %s",
latest_backup.name,
cur_backup.name,
)
hl_res = fs.hardlink_dir(latest_backup, cur_backup)
if not hl_res:
_lg.error("Something went wrong during copying data from latest backup,"
" removing created %s", cur_backup.name)
shutil.rmtree(cur_backup, ignore_errors=True)
return
if dry_run:
_lg.info("Dry-run, removing created backup: %s", cur_backup.name)
shutil.rmtree(cur_backup, ignore_errors=True)
else:
_lg.info("Backup created: %s", cur_backup.name)