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,325 @@
1
+ import logging
2
+ import re
3
+ import threading
4
+ from pathlib import Path
5
+ from typing import List
6
+
7
+ import typer
8
+
9
+ from ..cli_common import CommonCLI
10
+ from ..helpers.odoo_files import get_odoo_module_paths, odoo_bin_get_version
11
+ from ..helpers.system import run_cmd
12
+ from .bootstrap import bootstrap_odoo
13
+ from .rpc import import_to_odoo
14
+ from .source_get import update_odoo_conf
15
+
16
+ CLI = CommonCLI()
17
+
18
+ LOGGER = logging.getLogger(__name__)
19
+
20
+
21
+ def _launch_command(
22
+ odoo_path: Path,
23
+ odoo_conf_path: Path,
24
+ extra_cmd_args: List[str],
25
+ workspace_addon_path: Path,
26
+ upgrade_workspace_modules: bool = True,
27
+ ):
28
+ """Build Odoo Launch command
29
+
30
+ Parameters
31
+ ----------
32
+ odoo_path : Path
33
+ Path to odoo-bin folder
34
+ odoo_conf_path : Path
35
+ Path to odoo.conf
36
+ extra_cmd_args : List[str]
37
+ extra args to pass to odoo-bin
38
+ workspace_addon_path : Path
39
+ Path to dev workspace addons folder
40
+ upgrade_workspace_modules : bool, optional
41
+ upgrade workspace addons, by default True
42
+ """
43
+ upgrade_addons = [f.name for f in get_odoo_module_paths(workspace_addon_path)] if upgrade_workspace_modules else []
44
+ if any(["-u" in i or "--update" in i for i in extra_cmd_args]):
45
+ upgrade_addons = []
46
+ update_addon_string = "--update " + ",".join(upgrade_addons) if upgrade_addons else ""
47
+
48
+ odoo_cmd = [
49
+ str(odoo_path.absolute()) + "/odoo-bin",
50
+ update_addon_string,
51
+ f"-c {str(odoo_conf_path.absolute())}",
52
+ ] + extra_cmd_args
53
+ odoo_cmd = list(filter(None, odoo_cmd))
54
+ return " ".join(odoo_cmd)
55
+
56
+
57
+ def pre_launch(
58
+ odoo_main_path: Path,
59
+ workspace_addon_path: Path,
60
+ thirdparty_addon_path: Path,
61
+ odoo_conf_path: Path,
62
+ db_filter: str,
63
+ db_host: str,
64
+ db_port: int,
65
+ db_name: str,
66
+ db_user: str,
67
+ db_password: str,
68
+ odoo_demo: bool,
69
+ dev_mode: bool,
70
+ multithread_worker_count: int = 0,
71
+ extra_launch_args: List[str] = None,
72
+ extra_bootstrap_args: List[str] = None,
73
+ log_file_path: Path = None,
74
+ install_workspace_addons: bool = True,
75
+ install_base: bool = True,
76
+ launch_or_bootstrap: bool = False,
77
+ ):
78
+ """Start Bootstrap if no config file is found. And return Launch CMD.
79
+
80
+ Parameters
81
+ ----------
82
+ odoo_main_path : Path
83
+ Path to Odoo-bin folder
84
+ workspace_addon_path : Path
85
+ Path to workspace addons
86
+ thirdparty_addon_path : Path
87
+ path to thirdparty addons folder
88
+ odoo_conf_path : Path
89
+ path to odoo conf
90
+ db_filter : str
91
+ odoo.conf db_filter
92
+ db_host : str
93
+ database host url. Empty string for Unix sock
94
+ db_port : int
95
+ database port. 0 for unix sock
96
+ db_name : str
97
+ odoo main database name
98
+ db_user : str
99
+ database user
100
+ db_password : str
101
+ database password
102
+ odoo_demo : bool
103
+ if false, add --without-demo to bootstrap
104
+ dev_mode : bool
105
+ add --dev... to cmd
106
+ install_base : bool
107
+ install web, and base
108
+ install_workspace_addons : bool
109
+ install all modules in workspace folder
110
+ extra_args : List[str]
111
+ extra launch CMD args
112
+ extra_bootstrap_args : List[str]
113
+ extra bootstrap cmd args
114
+ log_file_path : Path
115
+ path to odoo.log (stdout log if empty)
116
+ multithread_worker_count : int
117
+ count of multithread workser
118
+ launch_or_bootstrap: bool, optional
119
+ Only return launch cmd if bootstrap did not run
120
+
121
+ Returns
122
+ -------
123
+ Union[int,str]
124
+ Int return code of bootstrap if not 0 else launch cmd as string
125
+ """
126
+ LOGGER.info("Starting godoo Init Script")
127
+
128
+ extra_odoo_args = []
129
+ if log_file_path is not None:
130
+ log_file_path.unlink(missing_ok=True)
131
+ extra_odoo_args.append("--logfile " + str(log_file_path.absolute()))
132
+
133
+ bootstraped = odoo_conf_path.exists()
134
+ LOGGER.info("Bootstrap Flag Status: %s", bootstraped)
135
+ ret = ""
136
+ if not bootstraped:
137
+ _extra_bootstrap_args = extra_odoo_args.copy()
138
+ if ea := extra_bootstrap_args:
139
+ _extra_bootstrap_args += ea
140
+ if not odoo_demo:
141
+ _extra_bootstrap_args += ["--without-demo all"]
142
+ if not install_base:
143
+ install_workspace_addons = False
144
+ ret = bootstrap_odoo(
145
+ db_name=db_name,
146
+ db_filter=db_filter,
147
+ db_user=db_user,
148
+ db_password=db_password,
149
+ db_host=db_host,
150
+ db_port=db_port,
151
+ thirdparty_addon_path=thirdparty_addon_path,
152
+ odoo_main_path=odoo_main_path,
153
+ odoo_conf_path=odoo_conf_path,
154
+ extra_cmd_args=_extra_bootstrap_args,
155
+ no_install_base=not install_base,
156
+ no_install_workspace_modules=not install_workspace_addons,
157
+ multithread_worker_count=multithread_worker_count,
158
+ )
159
+ bootstraped = ret == 0
160
+ if not bootstraped:
161
+ return ret
162
+ if install_workspace_addons and bootstraped:
163
+ install_workspace_addons = False
164
+
165
+ if launch_or_bootstrap:
166
+ return
167
+
168
+ if ea := extra_launch_args:
169
+ extra_odoo_args += ea
170
+
171
+ odoo_main_path = odoo_main_path
172
+ odoo_version = odoo_bin_get_version(odoo_main_path)
173
+
174
+ update_odoo_conf(
175
+ odoo_conf_path=odoo_conf_path,
176
+ odoo_main_path=odoo_main_path,
177
+ workspace_addon_path=workspace_addon_path,
178
+ thirdparty_addon_path=thirdparty_addon_path,
179
+ )
180
+
181
+ if dev_mode:
182
+ extra_odoo_args.append("--dev xml,qweb,reload")
183
+ if "16.0" in odoo_version:
184
+ extra_odoo_args[-1] += ",werkzeug"
185
+
186
+ if multithread_worker_count == 0:
187
+ extra_odoo_args.append("--workers 0")
188
+
189
+ return _launch_command(
190
+ odoo_path=odoo_main_path,
191
+ odoo_conf_path=odoo_conf_path,
192
+ extra_cmd_args=extra_odoo_args,
193
+ workspace_addon_path=workspace_addon_path,
194
+ upgrade_workspace_modules=install_workspace_addons,
195
+ )
196
+
197
+
198
+ @CLI.unpacker
199
+ @CLI.arg_annotator
200
+ def launch_odoo(
201
+ odoo_main_path=CLI.odoo_paths.bin_path,
202
+ workspace_addon_path=CLI.odoo_paths.workspace_addon_path,
203
+ thirdparty_addon_path=CLI.odoo_paths.thirdparty_addon_path,
204
+ odoo_conf_path=CLI.odoo_paths.conf_path,
205
+ db_filter=CLI.database.db_filter,
206
+ db_host=CLI.database.db_host,
207
+ db_port=CLI.database.db_port,
208
+ db_name=CLI.database.db_name,
209
+ db_user=CLI.database.db_user,
210
+ db_password=CLI.database.db_password,
211
+ odoo_demo=CLI.odoo_launch.odoo_demo,
212
+ dev_mode=CLI.odoo_launch.dev_mode,
213
+ no_install_base=CLI.odoo_launch.no_install_base,
214
+ no_install_workspace_modules=CLI.odoo_launch.no_install_workspace_modules,
215
+ extra_args=CLI.odoo_launch.extra_cmd_args,
216
+ extra_bootstrap_args=CLI.odoo_launch.extra_cmd_args,
217
+ log_file_path=CLI.odoo_launch.log_file_path,
218
+ multithread_worker_count=CLI.odoo_launch.multithread_worker_count,
219
+ ):
220
+ """
221
+ Launch Odoo, Bootstrap if bootstrapflag is not present.
222
+ """
223
+
224
+ launch_cmd = pre_launch(
225
+ odoo_main_path=odoo_main_path,
226
+ workspace_addon_path=workspace_addon_path,
227
+ thirdparty_addon_path=thirdparty_addon_path,
228
+ odoo_conf_path=odoo_conf_path,
229
+ db_filter=db_filter,
230
+ db_host=db_host,
231
+ db_port=db_port,
232
+ db_name=db_name,
233
+ db_user=db_user,
234
+ db_password=db_password,
235
+ odoo_demo=odoo_demo,
236
+ dev_mode=dev_mode,
237
+ install_base=not no_install_base,
238
+ install_workspace_addons=not no_install_workspace_modules,
239
+ extra_launch_args=extra_args,
240
+ extra_bootstrap_args=extra_bootstrap_args,
241
+ log_file_path=log_file_path,
242
+ multithread_worker_count=multithread_worker_count,
243
+ )
244
+
245
+ if not isinstance(launch_cmd, str):
246
+ LOGGER.error("godoo Launch Failed. Bootstrap unsuccessfull. Aborting Launch...")
247
+ return CLI.returner(launch_cmd)
248
+
249
+ LOGGER.info("Launching Odoo")
250
+ return CLI.returner(run_cmd(launch_cmd).returncode)
251
+
252
+
253
+ @CLI.arg_annotator
254
+ def launch_import(
255
+ load_data_path: List[Path] = typer.Argument(
256
+ ...,
257
+ help="Starts Async Importer Job with provided path(s).",
258
+ ),
259
+ odoo_main_path=CLI.odoo_paths.bin_path,
260
+ workspace_addon_path=CLI.odoo_paths.workspace_addon_path,
261
+ thirdparty_addon_path=CLI.odoo_paths.thirdparty_addon_path,
262
+ odoo_conf_path=CLI.odoo_paths.conf_path,
263
+ db_filter=CLI.database.db_filter,
264
+ db_host=CLI.database.db_host,
265
+ db_port=CLI.database.db_port,
266
+ db_name=CLI.database.db_name,
267
+ db_user=CLI.database.db_user,
268
+ db_password=CLI.database.db_password,
269
+ rpc_host=CLI.rpc.rpc_host,
270
+ rpc_user=CLI.rpc.rpc_user,
271
+ rpc_password=CLI.rpc.rpc_password,
272
+ odoo_demo=CLI.odoo_launch.odoo_demo,
273
+ dev_mode=CLI.odoo_launch.dev_mode,
274
+ no_install_base=CLI.odoo_launch.no_install_base,
275
+ no_install_workspace_modules=CLI.odoo_launch.no_install_workspace_modules,
276
+ extra_launch_args=CLI.odoo_launch.extra_cmd_args,
277
+ extra_bootstrap_args=CLI.odoo_launch.extra_cmd_args,
278
+ log_file_path=CLI.odoo_launch.log_file_path,
279
+ multithread_worker_count=CLI.odoo_launch.multithread_worker_count,
280
+ ):
281
+ """Bootstrap and Start odoo. Launches RPC import in second thread."""
282
+
283
+ launch_cmd = pre_launch(
284
+ odoo_main_path=odoo_main_path,
285
+ workspace_addon_path=workspace_addon_path,
286
+ thirdparty_addon_path=thirdparty_addon_path,
287
+ odoo_conf_path=odoo_conf_path,
288
+ db_filter=db_filter,
289
+ db_host=db_host,
290
+ db_port=db_port,
291
+ db_name=db_name,
292
+ db_user=db_user,
293
+ db_password=db_password,
294
+ odoo_demo=odoo_demo,
295
+ dev_mode=dev_mode,
296
+ install_base=not no_install_base,
297
+ install_workspace_addons=not no_install_workspace_modules,
298
+ extra_launch_args=extra_launch_args,
299
+ extra_bootstrap_args=extra_bootstrap_args,
300
+ log_file_path=log_file_path,
301
+ multithread_worker_count=multithread_worker_count,
302
+ )
303
+
304
+ if not isinstance(launch_cmd, str):
305
+ LOGGER.error("godoo Launch Failed. Bootstrap unsuccessfull. Aborting Launch...")
306
+ return CLI.returner(launch_cmd)
307
+
308
+ launch_cmd = re.sub(r"(--dev [\w,]+)(,reload)", r"\1", launch_cmd) # Remove reload option from CMD String
309
+
310
+ LOGGER.info("Starting Data Importer Thread for: '%s'", ", ".join(map(str, load_data_path)))
311
+ loader_thread = threading.Thread(
312
+ target=import_to_odoo,
313
+ name="DataLoader",
314
+ kwargs={
315
+ "read_paths": load_data_path,
316
+ "rpc_host": rpc_host,
317
+ "rpc_database": db_name,
318
+ "rpc_user": rpc_user,
319
+ "rpc_password": rpc_password,
320
+ },
321
+ )
322
+ loader_thread.start()
323
+
324
+ LOGGER.info("Launching Odoo")
325
+ return CLI.returner(run_cmd(launch_cmd).returncode)
@@ -0,0 +1,8 @@
1
+ """
2
+ Things that interact with Odoo RPC.
3
+ Must Provide username and Password
4
+ """
5
+ import typer
6
+
7
+ from .cli import rpc_cli_app
8
+ from .importer import import_to_odoo as import_to_odoo
@@ -0,0 +1,34 @@
1
+ import typer
2
+
3
+ from .config_parameters import set_config_parameter
4
+ from .importer import import_to_odoo
5
+ from .modules import install_modules, uninstall_modules
6
+ from .translations import dump_translations
7
+
8
+
9
+ def modules_cli_app():
10
+ app = typer.Typer(
11
+ no_args_is_help=True,
12
+ help="Wrapper around Odoo modules. (Install/upgrade, etc)",
13
+ )
14
+
15
+ app.command(name="install")(install_modules)
16
+ app.command(name="uninstall")(uninstall_modules)
17
+ app.command(name="dump-translation")(dump_translations)
18
+ return app
19
+
20
+
21
+ def rpc_cli_app():
22
+ app = typer.Typer(
23
+ no_args_is_help=True,
24
+ help="Functions that act on a running Odoo instance via RPC.",
25
+ )
26
+
27
+ app.add_typer(
28
+ typer_instance=modules_cli_app(),
29
+ name="modules",
30
+ )
31
+ app.command(name="set-config-param")(set_config_parameter)
32
+ app.command("import")(import_to_odoo)
33
+
34
+ return app
@@ -0,0 +1,48 @@
1
+ import logging
2
+
3
+ import typer
4
+ from godoo_rpc.login import wait_for_odoo
5
+
6
+ from ...cli_common import CommonCLI
7
+
8
+ CLI = CommonCLI()
9
+ LOGGER = logging.getLogger(__name__)
10
+
11
+
12
+ @CLI.arg_annotator
13
+ def set_config_parameter(
14
+ param_name: str = typer.Argument(..., help=r"name of ir.config.parameter"),
15
+ param_value: str = typer.Argument(..., help="Value to set config parameter to (:unlink to delete the parameter)"),
16
+ rpc_host=CLI.rpc.rpc_host,
17
+ rpc_database=CLI.rpc.rpc_db_name,
18
+ rpc_user=CLI.rpc.rpc_user,
19
+ rpc_password=CLI.rpc.rpc_password,
20
+ ):
21
+ """Create/Set/Delete ir.config_parameter in Odoo"""
22
+
23
+ odoo_api = wait_for_odoo(
24
+ odoo_host=rpc_host,
25
+ odoo_db=rpc_database,
26
+ odoo_user=rpc_user,
27
+ odoo_password=rpc_password,
28
+ )
29
+
30
+ paramteter_model = odoo_api.session.env["ir.config_parameter"]
31
+
32
+ param_id = paramteter_model.search([("key", "=", param_name)])
33
+ param = paramteter_model.browse(param_id[0]) if param_id else None
34
+
35
+ if param_value == ":unlink":
36
+ if param:
37
+ LOGGER.warning("Removing Config Parameter: %s", param_name)
38
+ param.unlink()
39
+ else:
40
+ LOGGER.info("Param '%s' does not exist", param_name)
41
+ return
42
+
43
+ if param:
44
+ LOGGER.info("Setting param value for %s", param_name)
45
+ param.value = param_value
46
+ else:
47
+ LOGGER.info("Creating new Config Parameter: %s", param_name)
48
+ paramteter_model.create({"key": param_name, "value": param_value})
@@ -0,0 +1,70 @@
1
+ """
2
+ Import read_path into Odoo.
3
+ Will wait until Odoo is Online.
4
+ Places Systemparam to Track if import was already done.
5
+ """
6
+
7
+ import logging
8
+ from pathlib import Path
9
+ from typing import List
10
+
11
+ import typer
12
+ from godoo_rpc import import_data
13
+ from godoo_rpc.login import wait_for_odoo
14
+
15
+ from ...cli_common import CommonCLI
16
+
17
+ CLI = CommonCLI()
18
+ LOGGER = logging.getLogger(__name__)
19
+
20
+
21
+ @CLI.unpacker
22
+ @CLI.arg_annotator
23
+ def import_to_odoo(
24
+ read_paths: List[Path] = typer.Argument(
25
+ ...,
26
+ readable=True,
27
+ exists=True,
28
+ help="Folder in which to search for import",
29
+ ),
30
+ rpc_host=CLI.rpc.rpc_host,
31
+ rpc_database=CLI.rpc.rpc_db_name,
32
+ rpc_user=CLI.rpc.rpc_user,
33
+ rpc_password=CLI.rpc.rpc_password,
34
+ file_regex: str = typer.Option(
35
+ r"(?P<module>.*)\.(csv|py|xlsx|json)$",
36
+ help="Regex for filesearch. Add group 'module' to set a Module for RPC import",
37
+ ),
38
+ product_image_regex: str = typer.Option(
39
+ r"(?P<default_code>\d{6})\.(jpeg|png|jpg)$",
40
+ help="Regex to search for Product images. Add Fields as regex group for Matching.",
41
+ ),
42
+ check_data_timestamp: bool = typer.Option(
43
+ True,
44
+ help="If true, Odoo remembers the Name of an uploaded File in a Serverparameter. Subsequent Imports will ignore the file if it hasnt changed.",
45
+ ),
46
+ skip_existing_ids: bool = typer.Option(False, help="Will skip import of already existing External IDs."),
47
+ ):
48
+ """
49
+ Import [bold green]csv, xlsx, json, .py [/bold green] files into Odoo.
50
+ Adds an ir.config_parameter containing timestamp of each imported file.
51
+ """
52
+ odoo_api = wait_for_odoo(
53
+ odoo_host=rpc_host,
54
+ odoo_db=rpc_database,
55
+ odoo_user=rpc_user,
56
+ odoo_password=rpc_password,
57
+ )
58
+
59
+ if missing_paths := [p for p in read_paths if not p.exists()]:
60
+ raise ValueError("Provided import Paths: %s doesn't exist", ", ".join(missing_paths))
61
+
62
+ for path in read_paths:
63
+ import_data(
64
+ odoo_api=odoo_api,
65
+ read_path=path.absolute(),
66
+ data_regex=file_regex,
67
+ product_image_regex=False if path.is_file() else product_image_regex,
68
+ check_dataset_timestamp=check_data_timestamp,
69
+ skip_existing_ids=skip_existing_ids,
70
+ )
@@ -0,0 +1,144 @@
1
+ import logging
2
+ from typing import Any, List
3
+
4
+ import typer
5
+ from godoo_rpc import OdooApiWrapper
6
+ from godoo_rpc.login import wait_for_odoo
7
+
8
+ from ...cli_common import CommonCLI
9
+
10
+ CLI = CommonCLI()
11
+ LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ def rpc_get_modules(odoo_api: OdooApiWrapper, module_query: str, valid_module_names: List[str] = None):
15
+ """Get ir.module.module records by a query search string.
16
+
17
+ Parameters
18
+ ----------
19
+ odoo_api : OdooApiWrapper
20
+ Odoo Wrapper
21
+ module_query : str
22
+ Custom query. Module name. Comma sep list of modules or % wildcards are supported
23
+ valid_module_names : List[str], optional
24
+ only allow certain model names to be returned, by default None
25
+
26
+ Returns
27
+ -------
28
+ _type_
29
+ _description_
30
+ """
31
+ mod_env = odoo_api.session.env["ir.module.module"]
32
+ mod_env.update_list()
33
+
34
+ base_domain = []
35
+ if "," in module_query:
36
+ search_domain = [("name", "in", module_query.split(","))]
37
+ else:
38
+ if "%" in module_query:
39
+ search_domain = [("name", "=ilike", module_query)]
40
+ else:
41
+ search_domain = [("name", "=", module_query)]
42
+
43
+ if valid_module_names:
44
+ base_domain.insert(1, "&")
45
+ base_domain.append(("name", "in", valid_module_names))
46
+
47
+ LOGGER.debug("Searching for Modules with Domain: %s", base_domain + search_domain)
48
+ if ids := mod_env.search(base_domain + search_domain):
49
+ modules = mod_env.browse(ids)
50
+ LOGGER.debug("Found Modules: %s", [(m.id, m.name, m.state) for m in modules])
51
+ return modules
52
+
53
+
54
+ def rpc_install_modules(
55
+ modules: Any,
56
+ upgrade: bool = True,
57
+ ):
58
+ """Install and upgrade Modules to Database.
59
+
60
+ Parameters
61
+ ----------
62
+ modules : Iterable RPC ir.module.module records
63
+ List of
64
+ upgrade : bool, optional
65
+ Upgrade module if already installed, by default True
66
+ """
67
+ did_something = False
68
+ install_module_ids = [m.id for m in modules if m.state == "uninstalled"]
69
+ if install_module_ids:
70
+ install_modules = modules.browse(install_module_ids)
71
+ LOGGER.info("Installing Module: " + ", ".join(install_modules.mapped("name")))
72
+ install_modules.button_immediate_install()
73
+ did_something = True
74
+
75
+ if upgrade and (
76
+ up_module_ids := [m.id for m in modules if m.state == "installed" and m.id not in install_module_ids]
77
+ ):
78
+ up_modules = modules.browse(up_module_ids)
79
+ LOGGER.info("Updating Module: " + ", ".join(up_modules.mapped("name")))
80
+ up_modules.button_immediate_upgrade()
81
+ did_something = True
82
+ return did_something
83
+
84
+
85
+ @CLI.arg_annotator
86
+ def install_modules(
87
+ module_name_query: str = typer.Argument(
88
+ ..., help=r"Module Internal name(s), comma seperated. Will use ilike Match if \% is present"
89
+ ),
90
+ rpc_host=CLI.rpc.rpc_host,
91
+ rpc_database=CLI.rpc.rpc_db_name,
92
+ rpc_user=CLI.rpc.rpc_user,
93
+ rpc_password=CLI.rpc.rpc_password,
94
+ upgrade: bool = typer.Option(True, help="Upgrae Module if already installed"),
95
+ ):
96
+ """Install or upgrade Odoo modules via RPC. Can act on multiple modules with % wildcard"""
97
+
98
+ odoo_api = wait_for_odoo(
99
+ odoo_host=rpc_host,
100
+ odoo_db=rpc_database,
101
+ odoo_user=rpc_user,
102
+ odoo_password=rpc_password,
103
+ )
104
+
105
+ if modules := rpc_get_modules(odoo_api, module_name_query):
106
+ if rpc_install_modules(modules, upgrade=upgrade):
107
+ return
108
+ else:
109
+ LOGGER.warn("Found Modules, but didn't do anything on DB.")
110
+ else:
111
+ LOGGER.warn("Could not find modules with Query: '%s'", module_name_query)
112
+ return CLI.returner(1)
113
+
114
+
115
+ @CLI.arg_annotator
116
+ def uninstall_modules(
117
+ module_name_query: str = typer.Argument(
118
+ ..., help=r"Module Internal name(s), comma seperated. Will use ilike Match if \% is present"
119
+ ),
120
+ rpc_host=CLI.rpc.rpc_host,
121
+ rpc_database=CLI.rpc.rpc_db_name,
122
+ rpc_user=CLI.rpc.rpc_user,
123
+ rpc_password=CLI.rpc.rpc_password,
124
+ ):
125
+ """Uninstall odoo Modules via RPC. Can act on multiple modules with % wildcard"""
126
+
127
+ odoo_api = wait_for_odoo(
128
+ odoo_host=rpc_host,
129
+ odoo_db=rpc_database,
130
+ odoo_user=rpc_user,
131
+ odoo_password=rpc_password,
132
+ )
133
+
134
+ if modules := rpc_get_modules(odoo_api, module_name_query):
135
+ uninstall_module_ids = [m.id for m in modules if m.state == "installed"]
136
+ if uninstall_module_ids:
137
+ uninstall_modules = modules.browse(uninstall_module_ids)
138
+ LOGGER.info("Uninstalling Module: " + ", ".join(uninstall_modules.mapped("name")))
139
+ uninstall_modules.button_immediate_uninstall()
140
+ else:
141
+ LOGGER.warn("Found Modules, but didn't do anything on DB.")
142
+ else:
143
+ LOGGER.warn("Could not find modules with Query: '%s'", module_name_query)
144
+ return CLI.returner(1)