import aiofile import asyncio import configparser import io import os import time from .backups import Backup from .remotes import Remote # Config HOME_DIR = os.path.abspath(os.environ.get("HOME")) if os.environ.get("XDG_CONFIG_HOME", None) is not None: CONFIG_FILE = os.environ.get("XDG_CONFIG_HOME") else: CONFIG_FILE = os.path.join(HOME_DIR, ".config") CONFIG_FILE = os.path.join(CONFIG_FILE, "home-backup.conf") # TODO: Set own config dir backups = [] remotes = {} config_lock = asyncio.Lock() if os.path.exists(CONFIG_FILE): def _parse_config(): # Load config config = configparser.ConfigParser() config.read(CONFIG_FILE) remotes = {} for iID, i in filter(lambda x: x[0] != "DEFAULT", config.items()): if iID.startswith("REMOTE|"): # Parse remote config iID = iID[len("REMOTE|"):] tmp = Remote.load_remote(iID, i) remotes[tmp.name] = tmp backups = [] for iID, i in filter(lambda x: x[0] != "DEFAULT", config.items()): if iID.startswith("BACKUP|"): # Parse backup config iID = iID[len("BACKUP|"):] backups.append(Backup.load_backup(iID, i, remotes)) return backups, remotes backups, remotes = _parse_config() async def save_config(): # Create config config = configparser.ConfigParser() # Add backups for i in backups: if not isinstance(i, Backup): raise ValueError("backups contains a non backup config entry.") config["BACKUP|%s" % i.name] = i.dump_config() # Add remotes for i in remotes.values(): if not isinstance(i, Remote): raise ValueError("remotes contains a non remote config entry.") config["REMOTE|%s" % i.name] = i.dump_config() # Write data tmp = io.StringIO() config.write(tmp) to_write = tmp.getvalue() async with aiofile.AIOFile(CONFIG_FILE, "w") as f: await f.write(to_write) await f.fsync() # Timer support class Timer(): __zero:int __latest:int def __init__(self): self.__zero = self.__latest = int(time.time()) async def run(self, async_callback): tasks = [] try: while True: # Delete finished futures to_delete = [] for i in tasks: if i.done() or i.cancelled(): to_delete.append(i) for i in to_delete: await i tasks.remove(i) # Check for new backup next_time = int(time.time()) candiates = {} candidate_name = set() async with config_lock: for i in backups: if self.__latest < i.get_next_scedule(self.__latest, self.__zero) <= next_time: candiates[i.name] = i candidate_name.add(i.name) self.__latest = next_time # Filter backups to_ignore = set() for iID, i in candiates.items(): if candidate_name.intersection(i.blocks): to_ignore.add(iID) # Generate backup task backups_to_run = [] for iID, i in filter(lambda x: x[0] not in to_ignore, candiates.items()): backups_to_run.append(i) tasks.append(asyncio.create_task(async_callback(backups_to_run))) # Wait for 1 min await asyncio.sleep(60) # Stop backup processes finally: for i in tasks: i.cancel()