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
@@ -0,0 +1,187 @@
1
+ import logging
2
+ import os
3
+ import re
4
+ from pathlib import Path
5
+ from typing import Any, List
6
+
7
+ from ..cli_common import CommonCLI
8
+ from ..helpers.bootstrap import _install_py_reqs_by_odoo_cmd
9
+ from ..helpers.odoo_files import get_addon_paths, get_odoo_module_paths
10
+ from ..helpers.system import run_cmd
11
+
12
+ CLI = CommonCLI()
13
+
14
+ LOGGER = logging.getLogger(__name__)
15
+
16
+
17
+ def _add_default_argument(cmd_list: List[str], arg: str, arg_val: Any):
18
+ if not any([arg in s for s in cmd_list]):
19
+ cmd_list.append(f'{arg}="{arg_val}"')
20
+
21
+
22
+ def _boostrap_command(
23
+ odoo_main_path: Path,
24
+ odoo_conf_path: Path,
25
+ addon_paths: List[Path],
26
+ workspace_addon_path: Path,
27
+ db_host: str,
28
+ db_filter: str,
29
+ db_name: str,
30
+ db_user: str,
31
+ db_password: str,
32
+ db_port: str,
33
+ extra_cmd_args: List[str] = None,
34
+ install_base: bool = True,
35
+ install_workspace_modules: bool = True,
36
+ multithread_worker_count: int = -1,
37
+ languages: str = "de_DE,en_US",
38
+ ) -> str:
39
+ """
40
+ Generate Bootstrap Command.
41
+
42
+ Parameters
43
+ ----------
44
+ odoo_main_path : Path
45
+ folder with odoo-bin
46
+ odoo_conf_path : Path
47
+ path to odoo.conf
48
+ addon_paths : List[Path]
49
+ odoo bin --addons-path
50
+ workspace_addon_path : Path
51
+ path to addons in dev repo
52
+ db_filter : str
53
+ db filter for odoo.conf
54
+ db_host : str
55
+ db hostname for odoo.conf
56
+ db_name : str
57
+ database name for odoo.conf
58
+ db_user : str
59
+ db user
60
+ db_password : str
61
+ db user password
62
+ db_port : str
63
+ db host port
64
+ extra_cmd_args : List[str], optional
65
+ extra args to pass to odoo-bin, by default None
66
+ install_base : bool, optional
67
+ install base,web, by default True
68
+ install_workspace_modules : bool, optional
69
+ install all modules found in workspace_path, by default True
70
+ multithread_worker_count : int, optional
71
+ cound of threads. if >0 cli also sets proxy mode flag, by default 9
72
+ languages : str, optional
73
+ languages to load, by default "de_DE,en_US"
74
+
75
+ Returns
76
+ -------
77
+ str
78
+ odoo-bin command
79
+ """
80
+ LOGGER.info("Generating Bootstrap Command")
81
+
82
+ odoo_conf_path.parent.mkdir(parents=True, exist_ok=True)
83
+
84
+ db_command = [
85
+ f"--database {db_name}",
86
+ f"--db_user {db_user}",
87
+ f"--db_password {db_password}",
88
+ f"--db_host {db_host}" if db_host else "",
89
+ f"--db_port {db_port}" if db_host else "",
90
+ f"--db-filter=^{db_filter}$",
91
+ ]
92
+
93
+ LOGGER.info("Getting Addon Paths")
94
+
95
+ workspace_addons = get_odoo_module_paths(workspace_addon_path)
96
+ if any([re.match(r"( |^)(-i|--init)", i) for i in extra_cmd_args]):
97
+ init_modules = []
98
+ else:
99
+ init_modules = ["base", "web"] if install_base else []
100
+ if install_workspace_modules and workspace_addons:
101
+ init_modules += [f.name for f in workspace_addons]
102
+ init_cmd = "--init " + ",".join(init_modules) if init_modules else ""
103
+
104
+ addon_paths = [str(p.absolute()) for p in addon_paths]
105
+ addon_paths = ", ".join(list(filter(None, addon_paths)))
106
+
107
+ base_cmds = [
108
+ str(odoo_main_path.absolute()) + "/odoo-bin",
109
+ init_cmd,
110
+ f"--config {str(odoo_conf_path.absolute())}",
111
+ "--save",
112
+ f"--load-language {languages}",
113
+ "--stop-after-init",
114
+ f"--addons-path '{addon_paths}'",
115
+ ]
116
+ odoo_cmd = base_cmds + db_command
117
+ if extra_cmd_args:
118
+ odoo_cmd += extra_cmd_args
119
+
120
+ _add_default_argument(cmd_list=odoo_cmd, arg="--data-dir", arg_val="/var/lib/odoo")
121
+
122
+ if multithread_worker_count == -1:
123
+ multithread_worker_count = os.cpu_count() or 0 + 1
124
+
125
+ if multithread_worker_count > 0:
126
+ odoo_cmd += [
127
+ "--proxy-mode",
128
+ f"--workers {multithread_worker_count}",
129
+ ]
130
+
131
+ odoo_cmd = list(filter(None, odoo_cmd))
132
+ return " ".join(odoo_cmd)
133
+
134
+
135
+ @CLI.unpacker
136
+ @CLI.arg_annotator
137
+ def bootstrap_odoo(
138
+ odoo_main_path=CLI.odoo_paths.bin_path,
139
+ workspace_addon_path=CLI.odoo_paths.workspace_addon_path,
140
+ thirdparty_addon_path=CLI.odoo_paths.thirdparty_addon_path,
141
+ odoo_conf_path=CLI.odoo_paths.conf_path,
142
+ db_filter=CLI.database.db_filter,
143
+ db_host=CLI.database.db_host,
144
+ db_port=CLI.database.db_port,
145
+ db_name=CLI.database.db_name,
146
+ db_user=CLI.database.db_user,
147
+ db_password=CLI.database.db_password,
148
+ extra_cmd_args=CLI.odoo_launch.extra_cmd_args,
149
+ multithread_worker_count=CLI.odoo_launch.multithread_worker_count,
150
+ languages=CLI.odoo_launch.languages,
151
+ no_install_base=CLI.odoo_launch.no_install_base,
152
+ no_install_workspace_modules=CLI.odoo_launch.no_install_workspace_modules,
153
+ ):
154
+ """Bootstrap Odoo."""
155
+
156
+ addon_paths = get_addon_paths(
157
+ odoo_main_repo=odoo_main_path,
158
+ workspace_addon_path=workspace_addon_path,
159
+ thirdparty_addon_path=thirdparty_addon_path,
160
+ )
161
+
162
+ cmd_string = _boostrap_command(
163
+ odoo_main_path=odoo_main_path,
164
+ odoo_conf_path=odoo_conf_path,
165
+ workspace_addon_path=workspace_addon_path,
166
+ addon_paths=addon_paths,
167
+ db_host=db_host,
168
+ db_name=db_name,
169
+ db_filter=db_filter,
170
+ db_user=db_user,
171
+ db_password=db_password,
172
+ db_port=db_port,
173
+ extra_cmd_args=extra_cmd_args,
174
+ install_base=not no_install_base,
175
+ install_workspace_modules=not no_install_workspace_modules,
176
+ multithread_worker_count=multithread_worker_count,
177
+ languages=languages,
178
+ )
179
+
180
+ # Always update Pip reqs regardless of --no-update-source
181
+ _install_py_reqs_by_odoo_cmd(addon_paths=addon_paths, odoo_bin_cmd=cmd_string)
182
+
183
+ LOGGER.info("Launching Bootstrap Commandline")
184
+ ret = run_cmd(cmd_string).returncode
185
+ if ret != 0:
186
+ LOGGER.error("Odoo-Bin Returned %d", ret)
187
+ return CLI.returner(ret)
@@ -0,0 +1,43 @@
1
+ """
2
+ Set odoo.conf variables
3
+ """
4
+ import logging
5
+ from configparser import ConfigParser
6
+ from pathlib import Path
7
+ from typing import List
8
+
9
+ import typer
10
+
11
+ from ..cli_common import CommonCLI
12
+
13
+ CLI = CommonCLI()
14
+ LOGGER = logging.getLogger(__name__)
15
+
16
+
17
+ @CLI.unpacker
18
+ @CLI.arg_annotator
19
+ def set_odoo_config(
20
+ options: List[str] = typer.Argument(..., help="odoo.conf options by key=value"),
21
+ odoo_conf_path=CLI.odoo_paths.conf_path,
22
+ ):
23
+ """
24
+ Set odoo.conf values.
25
+ """
26
+ conf_path = Path(odoo_conf_path)
27
+ odoo_conf = ConfigParser()
28
+ odoo_conf.read(conf_path)
29
+ LOGGER.info("Setting Odoo Conf Options for Stage")
30
+ custom_opts = {}
31
+ for op in options:
32
+ if "=" not in op:
33
+ LOGGER.error("Cannot parse Option: '%s' --> missing = sign", op)
34
+ raise ValueError("")
35
+ op_split = op.split("=")
36
+ custom_opts[op_split[0]] = op_split[1]
37
+ LOGGER.debug("Writing Conf Options: %s", custom_opts)
38
+ if "options" not in odoo_conf:
39
+ odoo_conf.add_section("options")
40
+ odoo_conf["options"] = {}
41
+ odoo_conf["options"].update(custom_opts)
42
+ conf_path.touch(exist_ok=True)
43
+ odoo_conf.write(conf_path.open("w"))
@@ -0,0 +1 @@
1
+ from .cli import db_cli_app
@@ -0,0 +1,18 @@
1
+ import typer
2
+
3
+ from .connection import login_db
4
+ from .passwords import set_passwords
5
+ from .query import query_database
6
+
7
+
8
+ def db_cli_app():
9
+ app = typer.Typer(
10
+ no_args_is_help=True,
11
+ help="Functions that directly act on the Postgres DB",
12
+ )
13
+
14
+ app.command()(set_passwords)
15
+ app.command("login")(login_db)
16
+ app.command("query")(query_database)
17
+
18
+ return app
@@ -0,0 +1,94 @@
1
+ import logging
2
+ import subprocess
3
+ from contextlib import contextmanager
4
+ from dataclasses import dataclass
5
+
6
+ import psycopg2
7
+
8
+ from ...cli_common import CommonCLI
9
+ from ...helpers.system import run_cmd
10
+
11
+ LOGGER = logging.getLogger(__name__)
12
+ CLI = CommonCLI()
13
+
14
+
15
+ @CLI.arg_annotator
16
+ def login_db(
17
+ db_host=CLI.database.db_host,
18
+ db_port=CLI.database.db_port,
19
+ db_name=CLI.database.db_name,
20
+ db_user=CLI.database.db_user,
21
+ db_password=CLI.database.db_password,
22
+ ):
23
+ """Login Interactive psql CLI using provided credentials"""
24
+ command = ["psql", f"-h{db_host}", f"-p{db_port}", f"-U{db_user}", f"-d{db_name}"]
25
+ subprocess.run(command, env={"PGPASSWORD": db_password})
26
+
27
+
28
+ @dataclass
29
+ class DBConnection:
30
+ db_name: str
31
+ hostname: str
32
+ username: str
33
+ password: str
34
+ port: int = 0
35
+ conn_timeout: int = 5
36
+
37
+ def get_connection(self):
38
+ LOGGER.debug(
39
+ "Connecting to DB: '%s:%s' U='%s' P='%s' D='%s'",
40
+ self.hostname,
41
+ self.port,
42
+ self.username,
43
+ self.password,
44
+ self.db_name,
45
+ )
46
+ return psycopg2.connect(
47
+ host=self.hostname,
48
+ port=self.port or None,
49
+ user=self.username,
50
+ password=self.password,
51
+ dbname=self.db_name,
52
+ connect_timeout=self.conn_timeout,
53
+ )
54
+
55
+ @contextmanager
56
+ def connect(self):
57
+ connection = self.get_connection()
58
+ cr = connection.cursor()
59
+ try:
60
+ yield cr
61
+ LOGGER.debug("Committing DB cursor")
62
+ connection.commit()
63
+ except Exception as e:
64
+ LOGGER.warning("Rolling Back DB cursor. Got Exception: %s", e)
65
+ connection.rollback()
66
+ raise e
67
+ finally:
68
+ LOGGER.debug("Closing DB connection")
69
+ cr.close()
70
+ connection.close()
71
+
72
+ def run_psql_shell_command(self, command: str, **kwargs):
73
+ """Run a psql command using the provided credentials. {} in the command will get templated with the connection string"""
74
+ LOGGER.debug("Running PSQL Command: %s", command)
75
+ arg_list = []
76
+ if h := self.hostname:
77
+ arg_list += ["-h", h]
78
+ if p := self.port:
79
+ arg_list += ["-p", p]
80
+ if u := self.username:
81
+ arg_list += ["-U", u]
82
+ if d := self.db_name:
83
+ arg_list += ["-d", d]
84
+ command_env = {}
85
+ if p := self.password:
86
+ command_env["PGPASSWORD"] = p
87
+
88
+ arg_str = " ".join(arg_list)
89
+ if "{}" in command:
90
+ command = command.format(arg_str)
91
+ else:
92
+ command += " " + " ".join(arg_list)
93
+
94
+ return run_cmd(command, env=command_env, **kwargs)
@@ -0,0 +1,56 @@
1
+ import logging
2
+
3
+ import typer
4
+ from passlib.context import CryptContext
5
+
6
+ from ...cli_common import CommonCLI
7
+ from ...helpers.cli import check_dangerous_command
8
+ from .connection import DBConnection
9
+
10
+ LOGGER = logging.getLogger(__name__)
11
+ CLI = CommonCLI()
12
+
13
+
14
+ def _hash_odoo_password(password: str) -> str:
15
+ """Hash Password for Odoo
16
+
17
+ Parameters
18
+ ----------
19
+ password : str
20
+ Password to hash
21
+
22
+ Returns
23
+ -------
24
+ str
25
+ Hashed Password
26
+ """
27
+ return CryptContext(schemes=["pbkdf2_sha512", "md5_crypt"]).encrypt(password)
28
+
29
+
30
+ @CLI.arg_annotator
31
+ def set_passwords(
32
+ new_password: str = typer.Argument(..., help="Password to set for all users"),
33
+ db_host=CLI.database.db_host,
34
+ db_port=CLI.database.db_port,
35
+ db_name=CLI.database.db_name,
36
+ db_user=CLI.database.db_user,
37
+ db_password=CLI.database.db_password,
38
+ ):
39
+ """Set Login Password for all Users."""
40
+
41
+ check_dangerous_command()
42
+
43
+ connection = DBConnection(
44
+ hostname=db_host,
45
+ port=db_port,
46
+ username=db_user,
47
+ password=db_password,
48
+ db_name=db_name,
49
+ )
50
+ hashed_pw = _hash_odoo_password(new_password)
51
+ with connection.connect() as conn:
52
+ try:
53
+ conn.execute(f"UPDATE res_users SET password='{hashed_pw}'")
54
+ except Exception:
55
+ raise typer.Exit(1)
56
+ LOGGER.info("Password for all users set to: '%s'", new_password)
@@ -0,0 +1,41 @@
1
+ import logging
2
+
3
+ import typer
4
+
5
+ from ...cli_common import CommonCLI
6
+ from ...helpers.cli import check_dangerous_command
7
+ from .connection import DBConnection
8
+
9
+ LOGGER = logging.getLogger(__name__)
10
+ CLI = CommonCLI()
11
+
12
+
13
+ @CLI.arg_annotator
14
+ def query_database(
15
+ query: str = typer.Argument(..., help="SQL Query"),
16
+ db_host=CLI.database.db_host,
17
+ db_port=CLI.database.db_port,
18
+ db_name=CLI.database.db_name,
19
+ db_user=CLI.database.db_user,
20
+ db_password=CLI.database.db_password,
21
+ ):
22
+ """Run a Query against the database."""
23
+
24
+ check_dangerous_command()
25
+ # regex to check if SQL query contains writing command
26
+
27
+ connection = DBConnection(
28
+ hostname=db_host,
29
+ port=db_port,
30
+ username=db_user,
31
+ password=db_password,
32
+ db_name=db_name,
33
+ )
34
+ with connection.connect() as cursor:
35
+ try:
36
+ cursor.execute(query)
37
+ rows = cursor.fetchall()
38
+ for row in rows:
39
+ print("\t".join(row)) # pylint: disable=print-used
40
+ except Exception:
41
+ raise typer.Exit(1)