summaryrefslogblamecommitdiffstatshomepage
path: root/src/hircine/cli.py
blob: 6941e2c54195a35dc06d718ca093960b0a4e41a0 (plain) (tree)































































































































                                                                                        
import argparse
import asyncio
import configparser
import importlib.metadata
import os
import sys
from datetime import datetime, timezone

import alembic.config

import hircine.db as db
from hircine import codename
from hircine.config import init_dir_structure
from hircine.scanner import Scanner


class SubcommandHelpFormatter(argparse.RawDescriptionHelpFormatter):
    def _format_action(self, action):
        parts = super(argparse.RawDescriptionHelpFormatter, self)._format_action(action)
        if action.nargs == argparse.PARSER:
            parts = "\n".join(parts.split("\n")[1:])
        return parts


def init(config, dirs, engine, args):
    if os.path.exists(dirs.database):
        sys.exit("Database already initialized.")

    dirs.mkdirs()

    print("Initializing database...")
    asyncio.run(db.initialize(engine))
    print("Done.")


def scan(config, dirs, engine, args):
    db.ensuredb(dirs)

    asyncio.run(db.ensure_current_revision(engine))

    scanner = Scanner(config, dirs, reprocess=args.reprocess)
    asyncio.run(scanner.scan())
    scanner.report()


def backup(config, dirs, engine, args, tag="manual"):
    db.ensuredb(dirs)

    os.makedirs(dirs.backups, exist_ok=True)

    date = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d_%H%M%S")
    filename = f"{os.path.basename(dirs.database)}.{tag}.{date}"
    path = os.path.join(dirs.backups, filename)

    asyncio.run(db.backup(engine, path))


def migrate(config, dirs, engine, args):
    db.ensuredb(dirs)

    backup(config, dirs, engine, args, tag="pre-migrate")
    alembic.config.main(argv=["--config", db.alembic_ini, "upgrade", "head"])


def vacuum(config, dirs, engine, args):
    db.ensuredb(dirs)

    asyncio.run(db.vacuum(engine))


def version(config, dirs, engine, args):
    version = importlib.metadata.metadata("hircine")["Version"]
    print(f'hircine {version} "{codename}"')


def main():
    parser = argparse.ArgumentParser(
        prog="hircine", formatter_class=SubcommandHelpFormatter
    )
    parser.add_argument("-C", dest="dir", help="run as if launched in DIR")

    subparsers = parser.add_subparsers(title="commands", required=True)

    parser_init = subparsers.add_parser("init", help="initialize a database")
    parser_init.set_defaults(func=init)

    parser_import = subparsers.add_parser("import", help="import archives")
    parser_import.set_defaults(func=scan)
    parser_import.add_argument(
        "-r", "--reprocess", action="store_true", help="reprocess all image files"
    )

    parser_migrate = subparsers.add_parser("migrate", help="run database migrations")
    parser_migrate.set_defaults(func=migrate)

    parser_backup = subparsers.add_parser(
        "backup", help="create a backup of the database"
    )
    parser_backup.set_defaults(func=backup)

    parser_vacuum = subparsers.add_parser(
        "vacuum", help="repack and optimize the database"
    )
    parser_vacuum.set_defaults(func=vacuum)

    parser_version = subparsers.add_parser("version", help="show version and exit")
    parser_version.set_defaults(func=version)

    args = parser.parse_args()

    if args.dir:
        try:
            os.chdir(args.dir)
        except OSError as e:
            sys.exit(e)

    dirs = init_dir_structure()

    config = configparser.ConfigParser()
    config.read(dirs.config)

    engine = db.configure(dirs)

    args.func(config, dirs, engine, args)


if __name__ == "__main__":
    main()