diff --git a/app/__main__.py b/app/__main__.py index b4cd3a0..fec66e1 100644 --- a/app/__main__.py +++ b/app/__main__.py @@ -1,3 +1,4 @@ +"""The main entrypoint of the program.""" import argparse import sys from parser import read_specs_file @@ -5,55 +6,62 @@ from parser import read_specs_file # This just displays the error type and message, not the stack trace def except_hook(ext_type, value, traceback): + """ + Make errors not show the stracktrace to stdout. + + Todo: + * Replace this with proper error handling + """ sys.stderr.write("{}: {}\n".format(ext_type.__name__, value)) # sys.excepthook = except_hook -# Define parser -parser = argparse.ArgumentParser( - description="Backup directories and Docker volumes." -) -parser.add_argument( - "-f", - "--file", - action="append", - dest="file", - required=True, - help="File containing spec definitions.", -) -parser.add_argument( - "-j", - "--json", - action="store_const", - const=True, - default=False, - help="Print out the parsed specs as JSON and exit", -) -parser.add_argument( - "spec", nargs="*", help="The specs to process. Defaults to all." -) +if __name__ == "__main__": + # Define parser + parser = argparse.ArgumentParser( + description="Backup directories and Docker volumes." + ) + parser.add_argument( + "-f", + "--file", + action="append", + dest="file", + required=True, + help="File containing spec definitions.", + ) + parser.add_argument( + "-j", + "--json", + action="store_const", + const=True, + default=False, + help="Print out the parsed specs as JSON and exit", + ) + parser.add_argument( + "spec", nargs="*", help="The specs to process. Defaults to all." + ) -# Parse arguments -args = parser.parse_args() -specs = sum([read_specs_file(path) for path in args.file], []) + # Parse arguments + args = parser.parse_args() + specs = sum((read_specs_file(path) for path in args.file), []) -# Filter specs if needed -if args.spec: - specs = list(filter(lambda s: s.name in args.spec, specs)) + # Filter specs if needed + if args.spec: + specs = list(filter(lambda s: s.name in args.spec, specs)) -# Dump parsed data as json -if args.json: - import json + # Dump parsed data as json + if args.json: + import json - print(json.dumps([spec.to_dict() for spec in specs], indent=4)) + # TODO replace this with error handling system + print(json.dumps([spec.to_dict() for spec in specs], indent=4)) -else: - # Run the backups - if not specs: - print("No specs, exiting.") - sys.exit(0) + elif not specs: + # TODO replace this with error handling system + print("No specs, exiting.") + sys.exit(0) - for spec in specs: - spec.backup() + for spec in specs: + spec.backup() diff --git a/app/specs/__init__.py b/app/specs/__init__.py index 0192b9e..dd08c1c 100644 --- a/app/specs/__init__.py +++ b/app/specs/__init__.py @@ -1,4 +1,7 @@ +"""Parent module for the various spec types.""" from .spec import Spec from .directory import DirectorySpec from .volume import VolumeSpec from .container import ContainerSpec + +__all__ = ["Spec", "DirectorySpec", "VolumeSpec", "ContainerSpec"] diff --git a/app/specs/container.py b/app/specs/container.py index bef6f8c..76579f0 100644 --- a/app/specs/container.py +++ b/app/specs/container.py @@ -1,3 +1,4 @@ +"""Module defining a Container-based spec.""" from .spec import Spec from typing import Union from pathlib import Path @@ -6,11 +7,10 @@ import subprocess class ContainerSpec(Spec): - """ - A spec for backing up via a container. - """ + """Spec for backing up via a container.""" _SKEL = {"container": None, "command": None, "mountpoint": "/from"} + """The skeleton for the ContainerSpec config.""" def __init__( self, @@ -23,6 +23,22 @@ class ContainerSpec(Spec): mountpoint: str, notify=None, ): + """ + Create a new ContainerSpec object. + + Args: + name: name of the spec (used as an identifier) + container: the Docker container to back up + destination: where to store the backups (gets created if + non-existent) + limit: max amount of backups to keep + command: command to run inside the container. This command should + perform a specified backup and output this data to stdout. This + output then gets piped to a backup file. + extension: the extension of the backup files. + mountpoint: + notify: notifier object (may be None) + """ super().__init__(name, destination, limit, extension, notify) self.container = container diff --git a/app/specs/spec.py b/app/specs/spec.py index 9b372ef..2669ccb 100644 --- a/app/specs/spec.py +++ b/app/specs/spec.py @@ -60,7 +60,19 @@ class Spec: self.extension = extension @classmethod - def skeleton(cls): + def skeleton(cls: "Spec") -> Dict: + """ + Return the skeleton for the given class. + + It works by inspecting the inheritance tree and merging the skeleton + for each of the parents. + + Args: + cls: the class to get the skeleton for + + Returns: + a dictionary containing the skeleton + """ return skeleton.merge( *[val._SKEL for val in reversed(inspect.getmro(cls)[:-1])] )