Skip to content

Commit 5dd7350

Browse files
committed
feat: add xpostgres script
1 parent 9ce3b43 commit 5dd7350

4 files changed

Lines changed: 68 additions & 1 deletion

File tree

clit/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
# ___ Error on setup of test_name ___
1313
# ___ test_name[Parameter] ___
1414
TEST_NAMES_REGEX = re.compile(r"___ .*(test[^\[\] ]+)[\[\]A-Za-z]* ___")
15+
POSTGRES_DOCKER_CONTAINER_NAME = "postgres10"

clit/db.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"""Database module."""
2+
import argparse
3+
from pathlib import Path
24
from typing import List, Optional
35

4-
from clit.files import shell
6+
from clit.constants import POSTGRES_DOCKER_CONTAINER_NAME
7+
from clit.docker import DockerContainer
8+
from clit.files import existing_directory_type, existing_file_type, shell
59

610

711
class DatabaseServer:
@@ -80,3 +84,63 @@ def list_databases(self) -> "PostgreSQLServer":
8084

8185
self.databases = sorted(db.strip() for db in process.stdout.strip().split())
8286
return self
87+
88+
89+
def backup(parser, args):
90+
"""Backup PostgreSQL databases."""
91+
pg = PostgreSQLServer(args.server_uri).list_databases()
92+
container = DockerContainer(POSTGRES_DOCKER_CONTAINER_NAME)
93+
for database in pg.databases:
94+
sql_file: Path = Path(args.backup_dir) / f"{pg.protocol}_{pg.server}_{pg.port}" / f"{database}.sql"
95+
sql_file.parent.mkdir(parents=True, exist_ok=True)
96+
97+
if pg.inside_docker:
98+
sql_file = container.replace_mount_dir(sql_file)
99+
shell(f"{pg.pg_dump} --clean --create --if-exists --file={sql_file} {pg.docker_uri}/{database}")
100+
101+
102+
def restore(parser, args):
103+
"""Restore PostgreSQL databases."""
104+
pg = PostgreSQLServer(args.server_uri).list_databases()
105+
new_database = args.database_name or args.sql_file.stem
106+
if new_database in pg.databases:
107+
print(f"The database {new_database!r} already exists in the server. Provide a new database name.")
108+
exit(1)
109+
110+
if new_database != args.sql_file.stem:
111+
# TODO Optional argument --owner to set the database owner
112+
print(f"TODO: Create a user named {new_database!r} if it doesn't exist (or raise an error)")
113+
print(f"TODO: Parse the .sql file and replace DATABASE/OWNER {args.sql_file.stem!r} by {new_database!r}")
114+
exit(2)
115+
116+
shell(f"{pg.psql} {args.server_uri} < {args.sql_file}")
117+
118+
119+
# TODO: Convert to click
120+
def extra_postgres():
121+
"""Extra PostgreSQL tools like backup, restore, user creation, etc."""
122+
parser = argparse.ArgumentParser(description="PostgreSQL helper tools")
123+
parser.add_argument("server_uri", help="database server URI (postgresql://user:password@server:port)")
124+
parser.set_defaults(chosen_function=None)
125+
subparsers = parser.add_subparsers(title="commands")
126+
127+
parser_backup = subparsers.add_parser("backup", help="backup a PostgreSQL database to a SQL file")
128+
parser_backup.add_argument("backup_dir", type=existing_directory_type, help="directory to store the backups")
129+
parser_backup.set_defaults(chosen_function=backup)
130+
131+
parser_restore = subparsers.add_parser("restore", help="restore a PostgreSQL database from a SQL file")
132+
parser_restore.add_argument(
133+
"sql_file", type=existing_file_type, help="full path of the .sql file created by the 'backup' command"
134+
)
135+
parser_restore.add_argument("database_name", nargs="?", help="database name (default: basename of .sql file)")
136+
parser_restore.set_defaults(chosen_function=restore)
137+
138+
# TODO Subcommand create-user new-user-name or alias user new-user-name to create a new user
139+
# TODO xpostgres user myuser [mypass]
140+
141+
args = parser.parse_args()
142+
if not args.chosen_function:
143+
parser.print_help()
144+
return
145+
args.chosen_function(parser, args)
146+
return

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pycharm-cli = "clit.dev:pycharm_cli"
3030
xpytest = "clit.dev:extra_pytest"
3131
pypi = "clit.dev:pypi"
3232
xpoetry = "clit.dev:extra_poetry"
33+
xpostgres = "clit.db:extra_postgres"
3334

3435
[tool.poetry.dependencies]
3536
python = "^3.6 || ^3.7"

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"pycharm-cli = clit.dev:pycharm_cli",
2626
"pypi = clit.dev:pypi",
2727
"xpoetry = clit.dev:extra_poetry",
28+
"xpostgres = clit.db:extra_postgres",
2829
"xpytest = clit.dev:extra_pytest",
2930
]
3031
}

0 commit comments

Comments
 (0)