gOdoo-cli 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. godoo_cli/__init__.py +2 -0
  2. godoo_cli/__main__.py +5 -0
  3. godoo_cli/cli.py +87 -0
  4. godoo_cli/cli_common.py +183 -0
  5. godoo_cli/commands/__init__.py +9 -0
  6. godoo_cli/commands/backup/__init__.py +1 -0
  7. godoo_cli/commands/backup/cli.py +17 -0
  8. godoo_cli/commands/backup/load.py +110 -0
  9. godoo_cli/commands/backup/pull.py +134 -0
  10. godoo_cli/commands/backup/util.py +35 -0
  11. godoo_cli/commands/bootstrap.py +187 -0
  12. godoo_cli/commands/config.py +43 -0
  13. godoo_cli/commands/db/__init__.py +1 -0
  14. godoo_cli/commands/db/cli.py +18 -0
  15. godoo_cli/commands/db/connection.py +94 -0
  16. godoo_cli/commands/db/passwords.py +56 -0
  17. godoo_cli/commands/db/query.py +41 -0
  18. godoo_cli/commands/launch.py +325 -0
  19. godoo_cli/commands/rpc/__init__.py +8 -0
  20. godoo_cli/commands/rpc/cli.py +34 -0
  21. godoo_cli/commands/rpc/config_parameters.py +48 -0
  22. godoo_cli/commands/rpc/importer.py +70 -0
  23. godoo_cli/commands/rpc/modules.py +144 -0
  24. godoo_cli/commands/rpc/translations.py +129 -0
  25. godoo_cli/commands/shell.py +45 -0
  26. godoo_cli/commands/source_get.py +279 -0
  27. godoo_cli/commands/test.py +126 -0
  28. godoo_cli/git/__init__.py +4 -0
  29. godoo_cli/git/git_odoo.py +89 -0
  30. godoo_cli/git/git_odoo_addons.py +95 -0
  31. godoo_cli/git/git_repo.py +207 -0
  32. godoo_cli/git/git_url.py +152 -0
  33. godoo_cli/git/zip_download.py +49 -0
  34. godoo_cli/helpers/__init__.py +1 -0
  35. godoo_cli/helpers/bootstrap.py +61 -0
  36. godoo_cli/helpers/cli.py +15 -0
  37. godoo_cli/helpers/odoo_files.py +278 -0
  38. godoo_cli/helpers/odoo_manifest.py +112 -0
  39. godoo_cli/helpers/system.py +176 -0
  40. godoo_cli/version.py +1 -0
  41. godoo_cli-0.7.0.dist-info/LICENSE +165 -0
  42. godoo_cli-0.7.0.dist-info/METADATA +197 -0
  43. godoo_cli-0.7.0.dist-info/RECORD +45 -0
  44. godoo_cli-0.7.0.dist-info/WHEEL +4 -0
  45. godoo_cli-0.7.0.dist-info/entry_points.txt +3 -0
godoo_cli/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .cli import launch_cli
2
+ from .version import __version__
godoo_cli/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Main CLI"""
2
+ from .cli import launch_cli
3
+
4
+ if __name__ == "__main__":
5
+ launch_cli()
godoo_cli/cli.py ADDED
@@ -0,0 +1,87 @@
1
+ """Main CLI."""
2
+ from typing import Optional
3
+
4
+ import typer
5
+ from dotenv import load_dotenv
6
+ from rich import print as rich_print
7
+
8
+ from .cli_common import CommonCLI
9
+ from .commands import (
10
+ backup_cli_app,
11
+ bootstrap_odoo,
12
+ db_cli_app,
13
+ launch_import,
14
+ launch_odoo,
15
+ odoo_shell,
16
+ odoo_test,
17
+ rpc_cli_app,
18
+ set_odoo_config,
19
+ source_cli_app,
20
+ uninstall_modules,
21
+ )
22
+ from .helpers.odoo_files import odoo_bin_get_version
23
+ from .helpers.system import set_logging
24
+ from .version import __version__
25
+
26
+ CLI = CommonCLI()
27
+
28
+
29
+ def main_callback(
30
+ verbose: Optional[bool] = typer.Option(
31
+ False,
32
+ "--verbose",
33
+ "-v",
34
+ envvar="GODOO_VERBOSE",
35
+ help="Verbose Logging with Error stacktraces",
36
+ )
37
+ ):
38
+ set_logging(verbose=verbose)
39
+
40
+
41
+ @CLI.arg_annotator
42
+ def print_versions(
43
+ odoo_main_path=CLI.odoo_paths.bin_path,
44
+ ):
45
+ """
46
+ Print gOdoo and Odoo Version info.
47
+ """
48
+ rich_print(f"gOdoo Version: [bold green]{__version__}[/bold green]")
49
+ odoo_version = odoo_bin_get_version(odoo_main_path)
50
+ rich_print(f"Odoo Version: [bold green]{odoo_version}[/bold green]")
51
+
52
+
53
+ def main_cli():
54
+ load_dotenv(".env", override=True)
55
+
56
+ help_text = "gOdoo CLI for Interacting with Odoo"
57
+ app = typer.Typer(no_args_is_help=True, callback=main_callback, rich_markup_mode="rich", help=help_text)
58
+ # Nested Subcommands
59
+ app.add_typer(
60
+ typer_instance=rpc_cli_app(),
61
+ name="rpc",
62
+ )
63
+ app.add_typer(
64
+ typer_instance=db_cli_app(),
65
+ name="db",
66
+ )
67
+ app.add_typer(
68
+ typer_instance=source_cli_app(),
69
+ name="source",
70
+ )
71
+ app.add_typer(typer_instance=backup_cli_app(), name="backup")
72
+
73
+ # Normal Subcommands
74
+ app.command("version")(print_versions)
75
+ app.command("bootstrap")(bootstrap_odoo)
76
+ app.command("launch")(launch_odoo)
77
+ app.command("launch-import")(launch_import)
78
+ app.command("test")(odoo_test)
79
+ app.command("config")(set_odoo_config)
80
+ app.command("shell")(odoo_shell)
81
+ app.command("uninstall")(uninstall_modules)
82
+ return app
83
+
84
+
85
+ def launch_cli():
86
+ app = main_cli()
87
+ app()
@@ -0,0 +1,183 @@
1
+ from dataclasses import dataclass
2
+ from pathlib import Path
3
+ from typing import List, Optional
4
+
5
+ from typer import Option
6
+ from typer_common_functions import get_type_from_default, typer_retuner, typer_unpacker
7
+
8
+
9
+ @dataclass
10
+ class OdooLaunchArgs:
11
+ extra_cmd_args: List[str] = Option(None, help="extra agruments to pass to odoo-bin", rich_help_panel="Odoo")
12
+ multithread_worker_count: int = Option(
13
+ -1, help="count of worker threads. will enable proxy_mode if >0. (Autodetect with -1)", rich_help_panel="Odoo"
14
+ )
15
+ languages: str = Option("de_DE,en_US", help="languages to load by default", rich_help_panel="Odoo")
16
+ no_install_base: bool = Option(
17
+ False,
18
+ "--no-install-base",
19
+ help="dont install [bold]base[/bold] and [bold]web[/bold] module",
20
+ rich_help_panel="Odoo",
21
+ )
22
+ no_install_workspace_modules: bool = Option(
23
+ False,
24
+ "--no-install-workspace-modules",
25
+ help="dont automatically install modules found in [bold cyan]--workspace_path[/bold cyan]",
26
+ rich_help_panel="Odoo",
27
+ )
28
+ no_update_source: bool = Option(
29
+ False, "--no-update-source", help="Update Odoo Source and Thirdparty Addons", rich_help_panel="Source Code"
30
+ )
31
+ no_addons_remove_unspecified: bool = Option(
32
+ False,
33
+ "--no-addons-remove-unspecified",
34
+ help="don't remove unspecified addons if not '[bold cyan]--no-update-source[/bold cyan]'",
35
+ rich_help_panel="Source Code",
36
+ )
37
+ odoo_demo: bool = Option(False, "--odoo-demo", help="Load Demo Data", rich_help_panel="Odoo")
38
+ dev_mode: bool = Option(
39
+ False,
40
+ "--dev-mode",
41
+ help="Passes '[bold cyan]--dev xml,qweb,reload[/bold cyan]' to odoo",
42
+ rich_help_panel="Odoo",
43
+ )
44
+ log_file_path: Path = Option(None, dir_okay=False, writable=True, help="Logfile Path", rich_help_panel="Odoo")
45
+
46
+
47
+ @dataclass
48
+ class OdooPathCLIArgs:
49
+ bin_path: Path = Option(
50
+ ...,
51
+ envvar="ODOO_MAIN_FOLDER",
52
+ help="folder that contains odoo-bin",
53
+ rich_help_panel="Path Options",
54
+ )
55
+
56
+ conf_path: Path = Option(
57
+ ...,
58
+ envvar="ODOO_CONF_PATH",
59
+ help="odoo.conf path",
60
+ rich_help_panel="Path Options",
61
+ )
62
+
63
+ workspace_addon_path: Path = Option(
64
+ ...,
65
+ envvar="ODOO_WORKSPACE_ADDON_LOCATION",
66
+ help="path to dev workspace addons",
67
+ rich_help_panel="Path Options",
68
+ )
69
+ thirdparty_addon_path: Path = Option(
70
+ ...,
71
+ envvar="ODOO_THIRDPARTY_LOCATION",
72
+ help="folder that contains thirdparty repos like OCA",
73
+ rich_help_panel="Path Options",
74
+ )
75
+
76
+
77
+ @dataclass
78
+ class RpcCLIArgs:
79
+ rpc_host: str = Option(
80
+ ...,
81
+ envvar="ODOO_RPC_HOST",
82
+ help="Odoo RPC Host",
83
+ rich_help_panel="RPC Options",
84
+ )
85
+
86
+ rpc_user: str = Option(
87
+ ...,
88
+ envvar="ODOO_RPC_USER",
89
+ help="User for RPC login",
90
+ rich_help_panel="RPC Options",
91
+ )
92
+
93
+ rpc_password: str = Option(
94
+ ...,
95
+ envvar="ODOO_RPC_PASSWORD",
96
+ help="Password RPC Login Password",
97
+ rich_help_panel="RPC Options",
98
+ )
99
+ rpc_db_name: str = Option(
100
+ ...,
101
+ envvar=["ODOO_RPC_DB_NAME", "ODOO_MAIN_DB"],
102
+ help="RPC database name",
103
+ rich_help_panel="RPC Options",
104
+ )
105
+
106
+
107
+ @dataclass
108
+ class DatabaseCLIArgs:
109
+ db_filter: str = Option(
110
+ ...,
111
+ envvar="ODOO_DB_FILTER",
112
+ help="database filter for odoo_conf",
113
+ rich_help_panel="Database Options",
114
+ )
115
+ db_host: str = Option(
116
+ "",
117
+ envvar="ODOO_DB_HOST",
118
+ help="db hostname (empty for default socket)",
119
+ rich_help_panel="Database Options",
120
+ )
121
+ db_name: str = Option(
122
+ ...,
123
+ envvar="ODOO_MAIN_DB",
124
+ help="launch database name",
125
+ rich_help_panel="Database Options",
126
+ )
127
+ db_user: str = Option(
128
+ ...,
129
+ envvar="ODOO_DB_USER",
130
+ help="db user",
131
+ rich_help_panel="Database Options",
132
+ )
133
+ db_password: str = Option(
134
+ ...,
135
+ envvar="ODOO_DB_PASSWORD",
136
+ help="db password",
137
+ rich_help_panel="Database Options",
138
+ )
139
+ db_port: str = Option(
140
+ "",
141
+ envvar="ODOO_DB_PORT",
142
+ help="db host port (empty for socket)",
143
+ rich_help_panel="Database Options",
144
+ )
145
+
146
+
147
+ @dataclass
148
+ class SourceGetArgs:
149
+ mainfest_path: Path = Option(
150
+ "",
151
+ envvar="ODOO_MANIFEST",
152
+ help="godoo manifest path, when downloading odoo source (skip repo_url)",
153
+ )
154
+
155
+ source_download_archive: Optional[bool] = Option(
156
+ False,
157
+ "--source-download-archive",
158
+ envvar="SOURCE_CLONE_ARCHIVE",
159
+ help="When using a HTTPs Repo Url for Github we can download a snapshop without the Repo history",
160
+ )
161
+
162
+
163
+ class CommonCLI:
164
+ def __init__(self) -> None:
165
+ self.odoo_paths = OdooPathCLIArgs
166
+ self.odoo_launch = OdooLaunchArgs
167
+ self.database = DatabaseCLIArgs
168
+ self.rpc = RpcCLIArgs
169
+ self.source = SourceGetArgs
170
+ self.returner = typer_retuner
171
+ self.unpacker = typer_unpacker
172
+
173
+ @property
174
+ def arg_annotator(self):
175
+ """Add type annotations for
176
+
177
+ Returns
178
+ -------
179
+ Callback
180
+ Annotator function with CommonCLI Props as arguments
181
+ """
182
+ my_args = self.__dict__
183
+ return get_type_from_default(*list(my_args.values()))
@@ -0,0 +1,9 @@
1
+ from .bootstrap import bootstrap_odoo
2
+ from .config import set_odoo_config
3
+ from .db import db_cli_app
4
+ from .launch import launch_import, launch_odoo
5
+ from .rpc import rpc_cli_app
6
+ from .shell import odoo_shell, uninstall_modules
7
+ from .source_get import source_cli_app
8
+ from .test import odoo_test
9
+ from .backup import backup_cli_app
@@ -0,0 +1 @@
1
+ from .cli import backup_cli_app
@@ -0,0 +1,17 @@
1
+ import typer
2
+
3
+ from .load import load_instance_data
4
+ from .pull import InstancePuller
5
+
6
+
7
+ def backup_cli_app():
8
+ app = typer.Typer(
9
+ no_args_is_help=True,
10
+ help="Functions around Backing up and Restoring Odoo",
11
+ )
12
+ puller = InstancePuller()
13
+
14
+ app.command("pull")(puller.pull_instance_data)
15
+ app.command("load")(load_instance_data)
16
+
17
+ return app
@@ -0,0 +1,110 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import typer
5
+ from typing_extensions import Annotated
6
+
7
+ from ...cli_common import CommonCLI
8
+ from ..db.connection import DBConnection
9
+ from .util import call_rsync, create_db, drop_db
10
+
11
+ LOGGER = logging.getLogger(__name__)
12
+ CLI = CommonCLI()
13
+
14
+
15
+ def load_pg_dump(
16
+ dump_path: Path,
17
+ db_name: str,
18
+ db_host: str = None,
19
+ db_port: int = 0,
20
+ db_user: str = None,
21
+ db_password: str = None,
22
+ ):
23
+ """Drop and recreate db_name and restore dump_path into it."""
24
+ if not dump_path.exists():
25
+ raise FileNotFoundError("Cannot find PG dump @ %s" % dump_path)
26
+
27
+ conn = DBConnection(
28
+ db_name="postgres",
29
+ hostname=db_host,
30
+ port=db_port,
31
+ username=db_user,
32
+ password=db_password,
33
+ )
34
+
35
+ drop_db(conn, db_name)
36
+ create_db(conn, db_name)
37
+
38
+ conn.db_name = db_name
39
+
40
+ LOGGER.info(
41
+ "Loading DB Dump: %s [%s mb] --> %s",
42
+ dump_path,
43
+ round(dump_path.stat().st_size / (1024 * 1024), 2),
44
+ db_name,
45
+ )
46
+ if dump_path.suffix == ".dump":
47
+ command = "pg_restore --no-owner --format c --dbname %s --jobs 8 {} %s" % (db_name, dump_path)
48
+ else:
49
+ command = "cat %s | psql {} >/dev/null" % dump_path
50
+ load_return = conn.run_psql_shell_command(
51
+ command=command,
52
+ log_name="Reading DB",
53
+ text=True,
54
+ capture_output=True,
55
+ )
56
+ if load_return.returncode != 0:
57
+ raise typer.Exit(1)
58
+ LOGGER.info("Deleting RPC Import Cache using plain SQL")
59
+ with conn.connect() as cur:
60
+ cur.execute("DELETE FROM ir_config_parameter WHERE key='godoo_rpc_import_cache';")
61
+ return load_return.returncode
62
+
63
+
64
+ @CLI.arg_annotator
65
+ def load_instance_data(
66
+ source_folder: Annotated[
67
+ Path,
68
+ typer.Argument(
69
+ ...,
70
+ help="Source Folder to load data from.",
71
+ file_okay=False,
72
+ dir_okay=True,
73
+ exists=True,
74
+ ),
75
+ ],
76
+ filestore_target_folder: Annotated[
77
+ Path,
78
+ typer.Argument(
79
+ ...,
80
+ help="Target Folder to load filestore to.",
81
+ file_okay=False,
82
+ dir_okay=True,
83
+ ),
84
+ ],
85
+ db_host=CLI.database.db_host,
86
+ db_port=CLI.database.db_port,
87
+ db_name=CLI.database.db_name,
88
+ db_user=CLI.database.db_user,
89
+ db_password=CLI.database.db_password,
90
+ dump_file_name: Annotated[
91
+ str,
92
+ typer.Option(help="Optional Changeable filename of Odoo SQL Dump within source_folder"),
93
+ ] = "odoo.dump",
94
+ ):
95
+ """Copy Filestore cache and load SQL Dump into Postgres for gOdoo."""
96
+ load_pg_dump(
97
+ dump_path=source_folder / dump_file_name,
98
+ db_host=db_host,
99
+ db_port=db_port,
100
+ db_name=db_name,
101
+ db_user=db_user,
102
+ db_password=db_password,
103
+ )
104
+ LOGGER.info("Done Loading Odoo instance from %s", source_folder)
105
+
106
+ filestore_target_folder.mkdir(parents=True, exist_ok=True)
107
+ call_rsync(
108
+ source_folder=source_folder / "odoo_filestore",
109
+ target_folder=filestore_target_folder,
110
+ )
@@ -0,0 +1,134 @@
1
+ import logging
2
+ import subprocess
3
+ from pathlib import Path
4
+
5
+ import typer
6
+ from rich.progress import track
7
+ from typing_extensions import Annotated
8
+
9
+ from ...cli_common import CommonCLI
10
+ from ...helpers.system import typer_ask_overwrite_path
11
+
12
+ LOGGER = logging.getLogger(__name__)
13
+ CLI = CommonCLI()
14
+
15
+
16
+ class InstancePuller:
17
+ ssh_hostname: str
18
+ ssh_user: str
19
+ pg_container: str # Does Postgres Live in a container?
20
+ pg_user: str
21
+
22
+ def set_exec_target(self, command):
23
+ """Prepend ssh execution, if ssh args are provided"""
24
+ if self.ssh_hostname:
25
+ return f"ssh {self.ssh_user}@{self.ssh_hostname} '{command}'"
26
+ return command
27
+
28
+ def get_docker_volume_path(self, volume_name: str):
29
+ command = f"docker volume inspect {volume_name} | jq -r .[0].Mountpoint"
30
+ command = self.set_exec_target(command)
31
+ LOGGER.debug("Running: '%s'", command)
32
+ path = subprocess.run(
33
+ command,
34
+ shell=True,
35
+ capture_output=True,
36
+ text=True,
37
+ ).stdout.strip("\n")
38
+ LOGGER.debug("Docker Volume Path: %s", path)
39
+ return path
40
+
41
+ def rsync_filestore(self, filestore_folder, target_folder: Path):
42
+ src_path = filestore_folder
43
+ if self.ssh_hostname:
44
+ src_path = f"{self.ssh_user}@{self.ssh_hostname}:{src_path}/"
45
+
46
+ command = f"rsync --rsync-path 'sudo rsync' -a --no-perms --no-owner --no-group --delete --info=progress2 {src_path} {target_folder}"
47
+ LOGGER.info("Rysnc filestore from: %s", filestore_folder)
48
+ LOGGER.debug("Running: %s", command)
49
+ return subprocess.run(command, shell=True).returncode
50
+
51
+ def download_db_dump(self, db_name, target_sql_path: Path):
52
+ command = f"pg_dump --no-owner -Fc {db_name}"
53
+ if n := self.pg_container:
54
+ command = f"docker exec {n} {command}"
55
+ if u := self.pg_user:
56
+ command += f" -U {u}"
57
+ else:
58
+ # Lets assume we run pg_dump locally here.
59
+ # Totally need to think about a neat way to handle the multiple combinations of this.
60
+ if u := self.pg_user:
61
+ command = f"sudo -u {u} {command}"
62
+
63
+ command = self.set_exec_target(command)
64
+ LOGGER.info("Downloading DB Dump: %s", db_name)
65
+ target_sql_path.touch(exist_ok=True)
66
+ with target_sql_path.open("wb") as sql_dump_file:
67
+ LOGGER.debug("Running: %s", command)
68
+ dbdumper = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
69
+ for line in track(dbdumper.stdout, description="Downloading DB Dump", show_speed=False):
70
+ sql_dump_file.write(line)
71
+
72
+ @CLI.arg_annotator
73
+ def pull_instance_data(
74
+ self,
75
+ target_folder: Annotated[
76
+ Path, typer.Argument(..., help="Target Folder to pull data to.", file_okay=False, dir_okay=True)
77
+ ],
78
+ ssh_user: Annotated[
79
+ str,
80
+ typer.Option(
81
+ ..., help="SSH User of remote instance.", rich_help_panel="Remote Options", envvar="ODOO_PULL_SSH_USER"
82
+ ),
83
+ ] = None,
84
+ ssh_hostname: Annotated[
85
+ str,
86
+ typer.Option(
87
+ help="SSH Hostname of remote instance.", rich_help_panel="Remote Options", envvar="ODOO_PULL_HOST"
88
+ ),
89
+ ] = None,
90
+ filestore_folder: Annotated[
91
+ Path,
92
+ typer.Option(help="Path to odoo web folder.", rich_help_panel="Filestore Options"),
93
+ ] = None,
94
+ filestore_volume: Annotated[
95
+ str,
96
+ typer.Option(
97
+ help="Alternative to valib-folder. A Docker volume name, that gets used to derive filestore-folder",
98
+ rich_help_panel="Filestore Options",
99
+ ),
100
+ ] = None,
101
+ pg_container: Annotated[
102
+ str,
103
+ typer.Option(
104
+ help="Postgres Container Name. (Optional)",
105
+ rich_help_panel="Database Options",
106
+ ),
107
+ ] = None,
108
+ pg_db_user=CLI.database.db_user,
109
+ pg_db_name=CLI.database.db_name,
110
+ ):
111
+ """Pull filestore folder and Database Dump and save to TARGET_FOLDER"""
112
+ self.ssh_hostname = ssh_hostname
113
+ self.ssh_user = ssh_user
114
+ filestore_target = target_folder / "odoo_filestore"
115
+ sql_target = target_folder / "odoo.dump"
116
+
117
+ if filestore_folder:
118
+ volume_path = filestore_folder
119
+ elif filestore_volume:
120
+ volume_path = self.get_docker_volume_path(filestore_volume)
121
+ else:
122
+ LOGGER.error("You need to either Supply a filestore-folder or a filestore-volume")
123
+ raise typer.Exit(1)
124
+
125
+ if not typer_ask_overwrite_path([filestore_target, sql_target]):
126
+ raise typer.Exit(2)
127
+
128
+ filestore_target.mkdir(parents=True, exist_ok=True)
129
+ self.rsync_filestore(volume_path, filestore_target)
130
+
131
+ self.pg_container = pg_container
132
+ self.pg_user = pg_db_user
133
+ self.download_db_dump(pg_db_name, sql_target)
134
+ LOGGER.info("Done Pulling Odoo Instance")
@@ -0,0 +1,35 @@
1
+ import subprocess
2
+ from logging import getLogger
3
+ from pathlib import Path
4
+
5
+ from ..db.connection import DBConnection
6
+
7
+ LOGGER = getLogger(__name__)
8
+
9
+
10
+ def call_rsync(source_folder: Path, target_folder: Path, rsync_delete: bool = True):
11
+ """Copy Folder to anohter using Rsync"""
12
+ if not source_folder.exists() and not source_folder.glob("*"):
13
+ raise FileNotFoundError("Cannot find filestore Backup @ %s" % source_folder)
14
+ args = ["rsync", "-a", "--no-perms", "--no-owner", "--no-group", "--info=progress2"]
15
+ if rsync_delete:
16
+ args += ["--delete"]
17
+ args += [f"{source_folder}/", f"{target_folder}/"]
18
+ command = " ".join(map(str, args))
19
+ LOGGER.info("Rysnc filestore to: %s", source_folder)
20
+ LOGGER.debug("Running: %s", command)
21
+ return subprocess.run(command, shell=True).returncode
22
+
23
+
24
+ def drop_db(connection: DBConnection, db_name: str):
25
+ """Drop a DB in postgres"""
26
+ with connection.connect() as cur:
27
+ LOGGER.info("Dropping DB: %s", db_name)
28
+ cur.execute("DROP DATABASE IF EXISTS %s" % db_name)
29
+
30
+
31
+ def create_db(connection: DBConnection, db_name: str):
32
+ """Create DB In Postgres"""
33
+ with connection.connect() as cur:
34
+ LOGGER.info("Creating DB: %s", db_name)
35
+ cur.execute("CREATE DATABASE %s" % db_name)