1import os
2import time
3from pathlib import Path
4
5import click
6
7from plain.cli import register_cli
8
9from .core import DatabaseBackups
10
11
12@register_cli("backups")
13@click.group("backups")
14def cli():
15 """Local database backups"""
16 pass
17
18
19@cli.command("list")
20def list_backups():
21 backups_handler = DatabaseBackups()
22 backups = backups_handler.find_backups()
23 if not backups:
24 click.secho("No backups found", fg="yellow")
25 return
26
27 for backup in backups:
28 click.secho(
29 f"{backup.name} ({backup.updated_at().strftime('%Y-%m-%d %H:%M:%S')})",
30 bold=True,
31 )
32
33 for backup_file in backup.iter_files():
34 size = os.path.getsize(backup_file)
35 click.echo(f"- {backup_file.name} ({size / 1024 / 1024:.2f} MB)")
36
37 click.echo()
38
39
40@cli.command("create")
41@click.option("--pg-dump", default="pg_dump", envvar="PG_DUMP")
42@click.argument("backup_name", default="")
43def create_backup(backup_name, pg_dump):
44 backups_handler = DatabaseBackups()
45
46 if not backup_name:
47 backup_name = f"backup_{time.strftime('%Y%m%d_%H%M%S')}"
48
49 try:
50 backup_dir = backups_handler.create(
51 backup_name,
52 pg_dump=pg_dump,
53 )
54 except Exception as e:
55 click.secho(str(e), fg="red")
56 exit(1)
57
58 click.secho(f"Backup created in {backup_dir.relative_to(Path.cwd())}", fg="green")
59
60
61@cli.command("restore")
62@click.option("--latest", is_flag=True)
63@click.option("--pg-restore", default="pg_restore", envvar="PG_RESTORE")
64@click.argument("backup_name", default="")
65def restore_backup(backup_name, latest, pg_restore):
66 backups_handler = DatabaseBackups()
67
68 if backup_name and latest:
69 raise click.UsageError("Only one of --latest or backup_name is allowed")
70
71 if not backup_name and not latest:
72 raise click.UsageError("Backup name or --latest is required")
73
74 if not backup_name and latest:
75 backup_name = backups_handler.find_backups()[0].name
76
77 click.secho(f"Restoring backup {backup_name}...", bold=True)
78
79 try:
80 backups_handler.restore(
81 backup_name,
82 pg_restore=pg_restore,
83 )
84 except Exception as e:
85 click.secho(str(e), fg="red")
86 exit(1)
87 click.echo(f"Backup {backup_name} restored successfully.")
88
89
90@cli.command("delete")
91@click.argument("backup_name")
92def delete_backup(backup_name):
93 backups_handler = DatabaseBackups()
94 try:
95 backups_handler.delete(backup_name)
96 except Exception as e:
97 click.secho(str(e), fg="red")
98 return
99 click.secho(f"Backup {backup_name} deleted", fg="green")
100
101
102@cli.command("clear")
103@click.confirmation_option(prompt="Are you sure you want to delete all backups?")
104def clear_backups():
105 backups_handler = DatabaseBackups()
106 backups = backups_handler.find_backups()
107 for backup in backups:
108 backup.delete()
109 click.secho("All backups deleted", fg="green")