gOdoo-cli 0.1.6__tar.gz → 0.3.3__tar.gz

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 (34) hide show
  1. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/PKG-INFO +1 -1
  2. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/pyproject.toml +1 -1
  3. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/setup.py +1 -1
  4. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/__init__.py +1 -1
  5. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/cli.py +11 -11
  6. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/__init__.py +2 -2
  7. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/bootstrap.py +3 -52
  8. godoo_cli-0.3.3/src/godoo_cli/commands/config.py +37 -0
  9. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/launch.py +14 -24
  10. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/shell.py +1 -1
  11. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/source_get.py +66 -22
  12. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/git_repo.py +63 -25
  13. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/zip_download.py +1 -1
  14. godoo_cli-0.3.3/src/godoo_cli/helpers/__init__.py +1 -0
  15. godoo_cli-0.3.3/src/godoo_cli/helpers/bootstrap.py +58 -0
  16. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/helpers/odoo_files.py +43 -10
  17. godoo_cli-0.1.6/src/godoo_cli/helpers/__init__.py → godoo_cli-0.3.3/src/godoo_cli/helpers/system.py +6 -3
  18. godoo_cli-0.1.6/src/godoo_cli/commands/makedev.py +0 -138
  19. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/LICENSE +0 -0
  20. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/README.md +0 -0
  21. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/__main__.py +0 -0
  22. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/__init__.py +0 -0
  23. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/cli.py +0 -0
  24. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/cli_callbacks.py +0 -0
  25. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/importer.py +0 -0
  26. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/modules.py +0 -0
  27. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/rpc/translations.py +0 -0
  28. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/commands/test.py +0 -0
  29. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/__init__.py +0 -0
  30. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/git_odoo.py +0 -0
  31. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/git_odoo_addons.py +0 -0
  32. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/git/git_url.py +0 -0
  33. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/helpers/cli.py +0 -0
  34. {godoo_cli-0.1.6 → godoo_cli-0.3.3}/src/godoo_cli/helpers/odoo_manifest.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: godoo-cli
3
- Version: 0.1.6
3
+ Version: 0.3.3
4
4
  Summary: Wrapper around Odoo-Bin with some convinience RPC functions.
5
5
  Home-page: https://github.com/OpenJKSoftware/gOdoo
6
6
  License: LGPL-3
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "gOdoo-cli"
3
- version = "0.1.6"
3
+ version = "0.3.3"
4
4
  description = "Wrapper around Odoo-Bin with some convinience RPC functions."
5
5
  authors = ["Joshua Kreuder <Joshua_Kreuder@outlook.com>"]
6
6
  license = "LGPL-3"
@@ -40,7 +40,7 @@ entry_points = \
40
40
 
41
41
  setup_kwargs = {
42
42
  'name': 'godoo-cli',
43
- 'version': '0.1.6',
43
+ 'version': '0.3.3',
44
44
  'description': 'Wrapper around Odoo-Bin with some convinience RPC functions.',
45
45
  'long_description': '# gOdoo Dev Environment\n\n![OdooLogo](https://raw.githubusercontent.com/OpenJKSoftware/gOdoo/main/assets/odoo_logo.png)\n![ComposeLogo](https://raw.githubusercontent.com/docker/compose/v2/logo.png)\n\n[<img src="https://raw.githubusercontent.com/OpenJKSoftware/gOdoo/main/assets/godoo-main-cli.png" width="1000"/>](image.png)\n\n**gOdoo** is short for **go Odoo**. \\\nIt is a [Vscode Devcontainer](https://code.visualstudio.com/docs/remote/containers) Environment for [Odoo](https://odoo.com/)\nwith Python CLI `godoo` convenience wrapper around `odoo-bin`.\n\nThis repository is the base source for the Python package [godoo-cli](https://pypi.org/project/godoo-cli/) and serves as\nan all batteries included development environment.\n\nMade Possible by: [WEMPE Elektronic GmbH](https://wetech.de)\n\n# gOdoo-cli\n\nPython package that provides `godoo` command line interface around `odoo-bin`.\n\nIt\'s build with [Typer](https://github.com/tiangolo/typer) to provide some convenience Wrappers for Odoo development and\nDeployment.\n\nMost flags can be configured by Env variables. \\\nUse `godoo --help` to find out more. HINT: Install tab-completion with `godoo --install-completion`\n\n# Docker\n\nThis workspace also contains Docker and Docker-Compose files. \\\n\nThey are used to provide either easy Odoo instances where the source is pulled according to\n[ODOO_MANIFEST.yml](./ODOO_MANIFEST.yml), or as a all batteries included devcontainer for VScode.\n\n## Requirements\n\n- [Docker Compose](https://github.com/docker/compose)\n- [Traefik](https://doc.traefik.io/traefik/) container running with docker provider and "traefik" named docker network.\n Example: [Traefik Devproxy](https://github.com/joshkreud/traefik_devproxy)\n- SSH Agent running. (check `echo $SSH_AUTH_SOCK`)\\\n This gets passed trough in the Buildprocess to clone Thirdparty repos.\n\n## Just wanna have a quick and easy Odoo Instance?\n\n```bash\ngit clone https://github.com/OpenJKSoftware/gOdoo\ncd godoo\n. scripts/container_requirements.sh # Check Requirements\ndocker-compose build\ndocker-compose up\n# wait......\n# wait a bit mode ...\n# just a little bit longer ..\n# There we go.\n# Odoo should be reachable on \'https://godoo.docker.localhost\' assuming you didn\'t change .env TRAEFIK_HOST_RULE or COMPOSE_PROJECT_NAME\n```\n\n# Devcontainer\n\n## Features\n\n- All batteries included [Devcontainer](https://code.visualstudio.com/docs/remote/containers) with postgres service\n Container and local DNS resolvig managed by [Traefik](https://doc.traefik.io/traefik/).\n- Easy fully working Odoo instance by `docker-compose up` with https access.\n- `godoo` CLI wrapper around Odoo. (Most flags can be configured by Environment Variables and are already preconfigured\n in the Containers. See [.env.sample](./.env.sample))\n- `odoo-bin` is added to PATH and can thus be invoked from every folder.\n- Odoo will run in Proxy_Mode behind a Traefik reverse proxy for easy access on\n `https://$COMPOSE_PROJECT_NAME.docker.localhost`\n- [Odoo Pylint plugin](https://github.com/OCA/pylint-odoo) preconfigured in vscode\n- Preinstalled vscode Extensions Highlights:\n - [SQL Tools](https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools) with preconfigured connection for\n easy Database access in the Sidebar.\n - [Docker Extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) controls\n container host.\n - [Odoo Snippets](https://marketplace.visualstudio.com/items?itemName=mstuttgart.odoo-snippets)\n - [Odoo Developments](https://marketplace.visualstudio.com/items?itemName=scapigliato.vsc-odoo-development) can Grab\n Odoo Model information from a running Server\n - [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree)\n\n## Usage\n\n1. For Docker on windows: Clone the repo into the WSL2 Filesystem for better IO performance\n2. Have [Traefik](https://github.com/traefik/traefik) Running on `docker.localhost`\n [Example](https://github.com/joshkreud/traefik_devproxy) \\\n There must be a Docker network called `traefik` that can reach traefik.\n3. Open Devcontianer:\n - If you have the Devcontainer CLI: `devcontainer open .`\n - If not open the workspace in Local Vscode. In the Command pallete search for `Reopen in container`\n4. From **within the container** start Odoo using one of the following commands:\n - You can enable godoo tab-completion by `godoo --install-completion`\n - `make` -> Loads Odoo + Workspace Addons\n - `make bare` -> Loads Odoo with ony `web` installed.\n - `make kill` -> Search for `odoo-bin` processes and kill them\n - `make reset` -> Drops DB, deletes config file and datafolder\n - The full init script is available via "`godoo`". (See --help for Options)\n5. Open Odoo `https://$COMPOSE_PROJECT_NAME.docker.localhost`\\\n For example `COMPOSE_PROJECT_NAME=godoo` --> [https://godoo.docker.localhost](https://godoo.docker.localhost)\n6. Login with `admin:admin`\n7. Profit!\n\n### Access to Odoo and Thirdparty addon Source\n\nYou can access the Odoo source by opening the VsCode workspace [full.code-workspace](full.code-workspace) from within\nthe Container. This will open a [Multi-Root Workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces).\nReally waiting for https://github.com/microsoft/vscode-remote-release/issues/3665 here.\n\n## Reset Devcontainer Data\n\nWhen you screwed up so bad its time to just start Over godoo has you covered:\n\n### Automatic Reset\n\nThere are 3 Options to reset the Dev Env.\n\n1. From **Outside** the Container run `make reset` in the project root to delete docker volumes and restart the\n container. (Vscode will prompt to reconnect if still open)\n2. From **Outside** the Container run `make reset-hard` in the project root to force rebuild the main Odoo container and\n then do the same as `make reset`\n3. From **Inside** the Container run `make reset` to drop the DB and delete varlib and the bootstrap flag, which is way\n quicker than the other options.\n\n### Manual Reset\n\n1. Close vscode\n2. Remove `app` and `db` container from docker.\n3. Remove volumes: `db, odoo_thirdparty, odoo_web, vscode_extensions`\n4. Restart Devcontainer\n\n## Python Debugging\n\n### VsCode Debugging\n\nDebugging doesn\'t reliably work with\n[Odoo Multiprocess](https://www.odoo.com/documentation/14.0/developer/misc/other/cmdline.html#multiprocessing) mode\nenabled. \\\nThe container ships with a Vscode Debug profile, that sets `--workers 0` to allow for Debugging Breakpoints. See [.vscode/launch.json](./.vscode/launch.json)\n\n### Interactive Shell\n\nUse `godoo shell` to enter an interactive shell on the Database.\n\n# Odoo Modules\n\n## Third Party Modules (manifest.yml)\n\nThe `godoo` bootstrap function, will download some modules using git. \\\nWhich Repos to download is specified in `ODOO_MANIFEST.yml` ([Default](./ODOO_MANIFEST.yml)) \\\nNot all of the cloned addons are automatically installed. \\\nInstall them via the Apps Page in Odoo using `godoo rpc modules install` or using `odoo-bin`.\\\nModules downloaded on the Odoo Marketplace can be dropped as a `.zip` archive in [./thirdparty](./thirdparty)\n',
46
46
  'author': 'Joshua Kreuder',
@@ -1,2 +1,2 @@
1
- __version__ = "0.1.6"
1
+ __version__ = "0.3.3"
2
2
  from .cli import launch_cli
@@ -9,14 +9,15 @@ from .commands import (
9
9
  bootstrap_odoo,
10
10
  get_source,
11
11
  get_source_file,
12
+ install_module_dependencies,
12
13
  launch_odoo,
13
- makedec_cli_app,
14
14
  odoo_shell,
15
15
  odoo_test,
16
16
  rpc_cli_app,
17
+ set_odoo_config,
17
18
  uninstall_modules,
18
19
  )
19
- from .helpers import set_logging
20
+ from .helpers.system import set_logging
20
21
 
21
22
 
22
23
  def main_callback(
@@ -54,21 +55,20 @@ def main_cli():
54
55
  app.add_typer(
55
56
  typer_instance=rpc_cli_app(),
56
57
  name="rpc",
57
- help="Various RPC Wrappers",
58
- )
59
- app.add_typer(
60
- typer_instance=makedec_cli_app(),
61
- name="makedev",
62
- help="Set config and RPC settings to generate a staging environment",
58
+ help="Commands that act on a running Odoo instance through RPC",
63
59
  )
64
60
 
65
61
  # Normal Subcommands
62
+ app.command("config", help="Set odoo.conf options")(set_odoo_config)
66
63
  app.command("launch", help="Launch Odoo, Bootstrap if bootstrapflag is not present")(launch_odoo)
67
64
  app.command("bootstrap", help="Bootstrap Odoo")(bootstrap_odoo)
68
- app.command("get-source-file", help="Get Raw file from odoo git remote or specific git remote.")(get_source_file)
69
- app.command("get-source", help="Download/Unzip Odoo Source and thirdparty addons.")(get_source)
65
+ app.command("source-get-file", help="Get Raw file from odoo git remote or specific git remote.")(get_source_file)
66
+ app.command("source-get-depends", help="Install dependencies from __manifest__.py in specified modules")(
67
+ install_module_dependencies
68
+ )
69
+ app.command("source-get", help="Download/Unzip Odoo Source and thirdparty addons.")(get_source)
70
70
  app.command("test", help="Bootstrap or Launch odoo in Testing Mode")(odoo_test)
71
- app.command("shell", help="Shell into Odoo")(odoo_shell)
71
+ app.command("shell", help="Start interactive Odoo shell")(odoo_shell)
72
72
  app.command("uninstall", help="Uninstall Modules")(uninstall_modules)
73
73
  return app
74
74
 
@@ -1,7 +1,7 @@
1
1
  from .bootstrap import bootstrap_odoo
2
+ from .config import set_odoo_config
2
3
  from .launch import launch_odoo
3
- from .makedev import makedec_cli_app
4
4
  from .rpc import rpc_cli_app
5
5
  from .shell import odoo_shell, uninstall_modules
6
- from .source_get import get_source, get_source_file
6
+ from .source_get import get_source, get_source_file, install_module_dependencies
7
7
  from .test import odoo_test
@@ -1,67 +1,19 @@
1
1
  import logging
2
2
  import re
3
- import subprocess
4
- from ast import literal_eval
5
3
  from pathlib import Path
6
4
  from typing import List
7
5
 
8
6
  import typer
9
7
 
10
- from ..helpers import run_cmd
8
+ from ..helpers.bootstrap import _install_py_reqs_by_odoo_cmd
11
9
  from ..helpers.cli import typer_retuner, typer_unpacker
12
- from ..helpers.odoo_files import _get_python_requirements_of_modules, get_addon_paths, get_odoo_module_paths
10
+ from ..helpers.odoo_files import get_addon_paths, get_odoo_module_paths
11
+ from ..helpers.system import run_cmd
13
12
  from .source_get import get_source
14
13
 
15
14
  LOGGER = logging.getLogger(__name__)
16
15
 
17
16
 
18
- def _install_py_reqs_for_modules(addon_paths: List[Path], module_names: List[str] = None):
19
- """Install Python Requirements mentioned in odoo module manifests of given modules
20
-
21
- Parameters
22
- ----------
23
- addon_paths : List[Path]
24
- odoo-bin addons path
25
- module_names : List[str], Optional
26
- List of modules to filter for, by default "all available modules"
27
-
28
- Returns
29
- -------
30
- CompletedProcess
31
- """
32
- py_reqs = _get_python_requirements_of_modules(addon_paths=addon_paths, filter_module_names=module_names)
33
- if py_reqs:
34
- installed_packages = run_cmd(
35
- "pip list --format json --disable-pip-version-check", check=True, shell=True, stdout=subprocess.PIPE
36
- ).stdout.decode("utf-8")
37
- installed_packages = [m.get("name") for m in literal_eval(installed_packages)]
38
- if missing_packages := [p for p in py_reqs if p not in installed_packages]:
39
- LOGGER.info("Installing Python requirements: '%s'", ", ".join(missing_packages))
40
- return run_cmd(f"pip install {' '.join(missing_packages)} --disable-pip-version-check", shell=True)
41
- LOGGER.debug("No py Requirements to be installed")
42
-
43
-
44
- def _install_py_reqs_by_odoo_cmd(addon_paths: List[Path], odoo_bin_cmd: str):
45
- """Install Python reqs for modules mentioned in odoo-bin commandline --init or -i directives.
46
-
47
- Parameters
48
- ----------
49
- addon_paths : List[Path]
50
- odoo-bin addons-path
51
- odoo_bin_cmd : str
52
- odoo-bin commandline
53
-
54
- Returns
55
- -------
56
- CompletedProcess
57
- """
58
- install_modules = []
59
- for m in re.finditer(r'(--init|-i) "?([^ \n]+)"?', odoo_bin_cmd):
60
- install_modules += m.group(2).split(",")
61
- if install_modules:
62
- return _install_py_reqs_for_modules(addon_paths=addon_paths, module_names=install_modules)
63
-
64
-
65
17
  def _boostrap_command(
66
18
  odoo_main_path: Path,
67
19
  odoo_conf_path: Path,
@@ -202,7 +154,6 @@ def bootstrap_odoo(
202
154
  addon_paths = get_addon_paths(
203
155
  odoo_main_repo=ctx.obj.odoo_main_path,
204
156
  workspace_addon_path=ctx.obj.workspace_addon_path,
205
- zip_addon_path=thirdparty_addon_path / "custom", # !Todo Pull out into variable
206
157
  thirdparty_addon_path=thirdparty_addon_path,
207
158
  )
208
159
 
@@ -0,0 +1,37 @@
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 ..helpers.cli import typer_unpacker
12
+
13
+ LOGGER = logging.getLogger(__name__)
14
+
15
+
16
+ @typer_unpacker
17
+ def set_odoo_config(
18
+ ctx: typer.Context,
19
+ options: List[str] = typer.Argument(..., help="odoo.conf options by key=value"),
20
+ ):
21
+ """
22
+ Set odoo.conf values.
23
+ """
24
+ conf_path = Path(ctx.obj.odoo_conf_path)
25
+ odoo_conf = ConfigParser()
26
+ odoo_conf.read(conf_path)
27
+ LOGGER.info("Setting Odoo Conf Options for Stage")
28
+ custom_opts = {}
29
+ for op in options:
30
+ if "=" not in op:
31
+ LOGGER.error("Cannot parse Option: '%s' --> missing = sign", op)
32
+ raise ValueError("")
33
+ op_split = op.split("=")
34
+ custom_opts[op_split[0]] = op_split[1]
35
+ LOGGER.debug("Writing Conf Options: %s", custom_opts)
36
+ odoo_conf["options"].update(custom_opts)
37
+ odoo_conf.write(conf_path.open("w"))
@@ -6,11 +6,10 @@ from typing import List
6
6
  import typer
7
7
 
8
8
  from ..commands.rpc.cli import rpc_callback
9
- from ..helpers import run_cmd
10
9
  from ..helpers.cli import typer_retuner, typer_unpacker
11
10
  from ..helpers.odoo_files import get_odoo_module_paths
11
+ from ..helpers.system import run_cmd
12
12
  from .bootstrap import bootstrap_odoo
13
- from .makedev import makedev_config, makedev_rpc
14
13
  from .rpc import import_to_odoo
15
14
 
16
15
  LOGGER = logging.getLogger(__name__)
@@ -62,8 +61,7 @@ def launch_odoo(
62
61
  install_workspace_addons: bool = typer.Option(True, help="Install Workspace addons"),
63
62
  update_source: bool = typer.Option(True, help="Git Pull Addons"),
64
63
  addons_remove_unspecified: bool = typer.Option(True, help="Cleanup/Remove unspecified Addons"),
65
- load_data_path: Path = typer.Option(None, help="Starts Async Importer Job with provided path"),
66
- prep_stage: bool = typer.Option(False, help="Starts Async Stage Prepper"),
64
+ load_data_path: List[Path] = typer.Option(None, help="Starts Async Importer Job with provided path(s)"),
67
65
  extra_args: List[str] = typer.Option([], help="Extra args to Pass to odoo Launch"),
68
66
  extra_bootstrap_args: List[str] = typer.Option([], help="Extra args to Pass to odoo Bootstrap"),
69
67
  log_file_path: Path = typer.Option(None, dir_okay=False, writable=True, help="Logfile Path"),
@@ -79,8 +77,6 @@ def launch_odoo(
79
77
  log_file_path.unlink(missing_ok=True)
80
78
  extra_odoo_args.append("--logfile " + str(log_file_path.absolute()))
81
79
 
82
- if ctx.obj.odoo_conf_path.exists() and prep_stage:
83
- makedev_config(ctx)
84
80
  LOGGER.info("Bootstrap Flag Status: %s", ctx.obj.bootstrap_flag_location.exists())
85
81
  bootstraped = False
86
82
  ret = ""
@@ -110,31 +106,25 @@ def launch_odoo(
110
106
  extra_odoo_args += ea
111
107
 
112
108
  if dev_mode:
113
- extra_odoo_args.append("--dev xml,qweb" if load_data_path else "--dev xml,qweb,reload")
109
+ extra_odoo_args.append(
110
+ "--dev xml,qweb" if load_data_path else "--dev xml,qweb,reload"
111
+ ) # Prevent server restart if Importer threads will be spawned.
114
112
 
115
113
  if bootstraped and not launch:
116
114
  return typer_retuner(ret)
117
115
 
118
116
  rpc_callback(ctx) # Add RPC Options using Defaults and Envvars
119
117
 
120
- if prep_stage:
121
- LOGGER.info("Starting Stage Prepper Thread")
122
- loader_thread = threading.Thread(
123
- target=makedev_rpc,
124
- args=(ctx,),
125
- name="Stage Cutter",
126
- )
127
- loader_thread.start()
128
-
129
118
  if load_data_path:
130
- LOGGER.info("Starting Data Importer Thread")
131
- loader_thread = threading.Thread(
132
- target=import_to_odoo,
133
- name="DataLoader",
134
- args=(ctx,),
135
- kwargs={"read_path": load_data_path.absolute()},
136
- )
137
- loader_thread.start()
119
+ for p in load_data_path:
120
+ LOGGER.info("Starting Data Importer Thread for: '%s'", str(p))
121
+ loader_thread = threading.Thread(
122
+ target=import_to_odoo,
123
+ name="DataLoader",
124
+ args=(ctx,),
125
+ kwargs={"read_path": p.absolute()},
126
+ )
127
+ loader_thread.start()
138
128
 
139
129
  cmd_string = _launch_command(
140
130
  odoo_path=ctx.obj.odoo_main_path,
@@ -3,8 +3,8 @@ from typing import List
3
3
 
4
4
  import typer
5
5
 
6
- from ..helpers import run_cmd
7
6
  from ..helpers.cli import typer_retuner, typer_unpacker
7
+ from ..helpers.system import run_cmd
8
8
 
9
9
  LOGGER = logging.getLogger(__name__)
10
10
 
@@ -1,7 +1,8 @@
1
+ """Commands to clone Odoo and addon source code"""
1
2
  import configparser
2
3
  import logging
3
4
  import shutil
4
- import zipfile
5
+ import tempfile
5
6
  from enum import Enum
6
7
  from pathlib import Path
7
8
  from typing import List
@@ -10,10 +11,11 @@ import typer
10
11
  from ruamel.yaml import YAML
11
12
 
12
13
  from ..git import GitUrl, git_ensure_addon_repos, git_ensure_odoo_repo
13
- from ..helpers import download_file
14
+ from ..helpers.bootstrap import _install_py_reqs_for_modules
14
15
  from ..helpers.cli import typer_unpacker
15
- from ..helpers.odoo_files import get_addon_paths
16
+ from ..helpers.odoo_files import get_addon_paths, get_odoo_module_paths, get_zip_addon_path
16
17
  from ..helpers.odoo_manifest import remove_unused_folders
18
+ from ..helpers.system import download_file
17
19
 
18
20
  LOGGER = logging.getLogger(__name__)
19
21
 
@@ -25,27 +27,46 @@ class UpdateMode(str, Enum):
25
27
  thirdparty = "thirdparty"
26
28
 
27
29
 
28
- def unzip_addons(zip_folder: Path, target_addon_folder: Path, remove_excess: bool = False):
29
- """Take .zip files from zip_folder and extracts them into the odoo addons folder.
30
+ def unpack_addon_archives(archive_folder: Path, target_addon_folder: Path, remove_excess: bool = False):
31
+ """Take archive files from archive_folder and extract them into target_addon_folder.
30
32
 
31
33
  Parameters
32
34
  ----------
33
- zip_folder : Path
35
+ archive_folder : Path
34
36
  Where to look for zip files
35
37
  target_addon_folder : Path
36
38
  where to place them
37
39
  remove_excess : bool , optional
38
40
  remove all and then unzip, by default False
39
41
  """
42
+ target_addon_folder.mkdir(exist_ok=True, parents=True)
40
43
  if remove_excess:
44
+ LOGGER.debug("Clearing out unarchive folder: %s", target_addon_folder)
41
45
  for folder in target_addon_folder.iterdir():
42
46
  shutil.rmtree(folder)
43
- LOGGER.info("Extracting Zip Addons to: %s", target_addon_folder)
44
- for zip_file in zip_folder.glob("*.zip"):
45
- target_addon_folder.mkdir(exist_ok=True, parents=True)
46
- LOGGER.info("Extracting Zip Addon: %s", zip_file)
47
- with zipfile.ZipFile(zip_file, "r") as zip_ref:
48
- zip_ref.extractall(target_addon_folder)
47
+ LOGGER.info("Extracting archive addons to: %s", target_addon_folder)
48
+ for zip_file in archive_folder.glob("*.zip"):
49
+ LOGGER.info("Extracting addon archive: %s", zip_file)
50
+ with tempfile.TemporaryDirectory() as td:
51
+ td = Path(td)
52
+ shutil.unpack_archive(zip_file, td)
53
+ # We can have zip files with one or more modules.
54
+ # Either the first folder contains multiple or its a module by itself
55
+ # So first get the real modules form the zip root or one level down and then move them to subpaths
56
+ zip_module_paths = get_odoo_module_paths([td] + list(td.glob("*/")))
57
+ if not zip_module_paths:
58
+ LOGGER.warning("Could not find valid modules in thirdparty zip: %s", zip_file)
59
+ continue
60
+ LOGGER.debug(
61
+ "Found modules in Zipfile:\n%s",
62
+ "\n".join([str(f.relative_to(td)) for f in zip_module_paths]),
63
+ )
64
+ target_folder = target_addon_folder / ("single_mods" if len(zip_module_paths) == 1 else zip_file.stem)
65
+ target_folder.mkdir(exist_ok=True)
66
+ for m in zip_module_paths:
67
+ module_target = target_folder / m.stem
68
+ shutil.rmtree(module_target, ignore_errors=True)
69
+ shutil.move(m, module_target)
49
70
 
50
71
 
51
72
  def update_odoo_conf_addon_paths(odoo_conf: Path, addon_paths: List[Path]):
@@ -67,6 +88,30 @@ def update_odoo_conf_addon_paths(odoo_conf: Path, addon_paths: List[Path]):
67
88
  config.write(odoo_conf.open("w"))
68
89
 
69
90
 
91
+ @typer_unpacker
92
+ def install_module_dependencies(
93
+ ctx: typer.Context,
94
+ thirdparty_addon_path: Path = typer.Option(
95
+ ...,
96
+ envvar="ODOO_THIRDPARTY_LOCATION",
97
+ help="Root folder of the Thirdparty addon repos",
98
+ ),
99
+ module_list: List[str] = typer.Argument(
100
+ ...,
101
+ help="Modules to check for dependencies (can use all for all available addons)",
102
+ ),
103
+ ):
104
+ odoo_addon_paths = get_addon_paths(
105
+ odoo_main_repo=ctx.obj.odoo_main_path,
106
+ workspace_addon_path=ctx.obj.workspace_addon_path,
107
+ thirdparty_addon_path=thirdparty_addon_path,
108
+ )
109
+ if len(module_list) == 1 and module_list[0] == "all":
110
+ search_addon_paths = [p for p in odoo_addon_paths if ctx.obj.odoo_main_path not in p.parents]
111
+ module_list = [p.stem for p in get_odoo_module_paths(search_addon_paths)]
112
+ _install_py_reqs_for_modules(odoo_addon_paths, module_list)
113
+
114
+
70
115
  @typer_unpacker
71
116
  def get_source_file(
72
117
  manifest_yml: Path = typer.Option(
@@ -101,6 +146,7 @@ def get_source_file(
101
146
  @typer_unpacker
102
147
  def get_source(
103
148
  ctx: typer.Context,
149
+ update_mode: UpdateMode = typer.Argument(UpdateMode.all, help="What to Update"),
104
150
  manifest_yml: Path = typer.Option(
105
151
  ..., envvar="ODOO_MANIFEST", help="Git.yml file, that specified what to download with wich prefix"
106
152
  ),
@@ -110,7 +156,6 @@ def get_source(
110
156
  thirdparty_zip_source: Path = typer.Option(
111
157
  ..., envvar="ODOO_THIRDPARTY_ZIP_LOCATION", help="Source folder, where to look for Addon zips"
112
158
  ),
113
- update_mode: UpdateMode = typer.Option(UpdateMode.all, help="What to Update"),
114
159
  add_compare_comments: bool = typer.Option(
115
160
  False, help="Wether to add github.com three dot compare links as comments."
116
161
  ),
@@ -124,10 +169,10 @@ def get_source(
124
169
  ):
125
170
  """Update Odoo Source and Thirdparty source."""
126
171
  LOGGER.info("Updating Source Repos")
127
- zip_addon_path = thirdparty_addon_path / "custom" # !Todo Pull out into variable (same in bootstrap)
172
+ zip_addon_path = get_zip_addon_path(thirdparty_addon_path)
128
173
 
129
174
  if update_mode in ["all", "zip"]:
130
- unzip_addons(thirdparty_zip_source, zip_addon_path)
175
+ unpack_addon_archives(thirdparty_zip_source, zip_addon_path, remove_excess=remove_unspecified_addons)
131
176
 
132
177
  if update_mode in ["all", "odoo"]:
133
178
  git_ensure_odoo_repo(
@@ -145,18 +190,17 @@ def get_source(
145
190
  generate_yml_compare_comments=add_compare_comments,
146
191
  download_archive=ctx.obj.source_download_archive,
147
192
  )
148
- if remove_unspecified_addons:
149
- remove_unused_folders(
150
- thirdparty_addon_path=thirdparty_addon_path,
151
- thirdparty_repos=git_repos.get("thirdparty", []),
152
- keep_folders=[zip_addon_path],
153
- )
193
+ if remove_unspecified_addons:
194
+ remove_unused_folders(
195
+ thirdparty_addon_path=thirdparty_addon_path,
196
+ thirdparty_repos=git_repos.get("thirdparty", []),
197
+ keep_folders=[zip_addon_path],
198
+ )
154
199
 
155
200
  if (conf_path := ctx.obj.odoo_conf_path).exists():
156
201
  odoo_addon_paths = get_addon_paths(
157
202
  odoo_main_repo=ctx.obj.odoo_main_path,
158
203
  workspace_addon_path=ctx.obj.workspace_addon_path,
159
- zip_addon_path=zip_addon_path,
160
204
  thirdparty_addon_path=thirdparty_addon_path,
161
205
  )
162
206
  update_odoo_conf_addon_paths(odoo_conf=conf_path, addon_paths=odoo_addon_paths)
@@ -1,7 +1,9 @@
1
+ """ Module to provide GIT interaction."""
1
2
  import logging
3
+ import shutil
2
4
  from pathlib import Path
3
5
 
4
- from git import InvalidGitRepositoryError, Repo
6
+ from git import GitCommandError, InvalidGitRepositoryError, Repo
5
7
 
6
8
  from .git_url import GitUrl
7
9
  from .zip_download import git_download_zip
@@ -9,6 +11,32 @@ from .zip_download import git_download_zip
9
11
  LOGGER = logging.getLogger(__name__)
10
12
 
11
13
 
14
+ def _git_clean_clone(repo_src: str, target_folder: Path, **kwargs):
15
+ """Clears targetfolder and does a clean clone_from
16
+
17
+ Parameters
18
+ ----------
19
+ repo_src : str
20
+ Clone url
21
+ target_folder : Path
22
+ Download folder
23
+ branch : str
24
+ branch to clone
25
+
26
+ Returns
27
+ -------
28
+ _type_re
29
+ _description_
30
+ """
31
+ LOGGER.debug("Cloning Repo: %s, to '%s', Kwargs: '%s'", repo_src, target_folder, kwargs)
32
+ if not isinstance(target_folder, Path):
33
+ target_folder = Path(target_folder)
34
+ if target_folder.exists():
35
+ LOGGER.debug("Clearing Repo folder: %s", target_folder)
36
+ shutil.rmtree(target_folder)
37
+ return Repo.clone_from(repo_src, target_folder, **kwargs)
38
+
39
+
12
40
  def git_pull_checkout_reset(
13
41
  repo: Repo, branch: str = "master", commit: str = "", pull: str = "", reset_hard: bool = True
14
42
  ):
@@ -30,24 +58,28 @@ def git_pull_checkout_reset(
30
58
  will call reset --hard after checkout to ensure clean git repo, by default True
31
59
  """
32
60
 
33
- try:
34
- if pull:
35
- LOGGER.debug("Pulling Repo: %s, %s", repo.git_dir, pull)
61
+ if pull:
62
+ LOGGER.debug("Pulling Repo: %s, %s", repo.working_dir, pull)
63
+ try:
36
64
  repo.remotes[0].pull(pull)
37
- if commit:
38
- if str(repo.head.commit) != str(commit):
39
- LOGGER.debug("Checking out %s to Commit: %s", repo.git_dir, commit)
40
- repo.git.checkout(commit)
41
- return
42
- if branch:
43
- LOGGER.debug("Checking Out repo %s to Branch: %s", repo.git_dir, branch)
44
- repo.git.checkout(branch)
45
- if reset_hard:
46
- repo.git.reset("--hard")
47
- except Exception as e:
48
- raise Exception(
49
- str(f"Error while ensuring Git repo: {str(repo)}, branch='{branch}', commit='{commit}', fetch='{pull}'")
50
- ) from e
65
+ except GitCommandError as e:
66
+ if "fatal: refusing to merge unrelated histories" in e.stderr:
67
+ clone_kwargs = {}
68
+ if branch:
69
+ clone_kwargs["branch"] = branch
70
+ repo = _git_clean_clone(repo.remotes[0].url, repo.working_dir, **clone_kwargs)
71
+ else:
72
+ raise e
73
+ if commit:
74
+ if str(repo.head.commit) != str(commit):
75
+ LOGGER.debug("Checking out %s to Commit: %s", repo.git_dir, commit)
76
+ repo.git.checkout(commit)
77
+ return
78
+ if branch:
79
+ LOGGER.debug("Checking Out repo %s to Branch: %s", repo.git_dir, branch)
80
+ repo.git.checkout(branch)
81
+ if reset_hard:
82
+ repo.git.reset("--hard")
51
83
 
52
84
 
53
85
  def git_ensure_ref(
@@ -81,23 +113,29 @@ def git_ensure_ref(
81
113
  target_folder.mkdir(exist_ok=True, parents=True)
82
114
  try:
83
115
  repo = Repo(target_folder)
84
- current = repo.head.commit
116
+ current = str(repo.head.commit)
85
117
 
86
118
  if not pull and commit and str(commit) != str(current):
87
119
  pull = str(commit)
88
120
 
89
121
  if not pull and branch and not commit:
90
- pull = str(branch)
91
- git_pull_checkout_reset(repo=repo, branch=branch, commit=commit, pull=pull)
122
+ remote_name = str(repo.remotes[0].name)
123
+ remote_commit = repo.git.rev_parse(remote_name + "/" + str(branch))
124
+ LOGGER.debug(
125
+ "Repo: %s comparing local head '%s' with remote head '%s'", repo.working_dir, current, remote_commit
126
+ )
127
+ if str(remote_commit) != current:
128
+ pull = str(branch)
129
+
130
+ git_pull_checkout_reset(repo=repo, branch=branch, commit=commit, pull=pull)
92
131
 
93
- if current == repo.head.commit:
132
+ if current == str(repo.head.commit):
94
133
  LOGGER.info("Repo Commit matches. Skipping: '%s' --> '%s'", repo_src, target_folder)
95
134
  else:
96
135
  LOGGER.info("Pulled Repo from: '%s'. Head is now at: %s", repo_src, repo.head.commit)
97
136
  except InvalidGitRepositoryError:
98
- LOGGER.debug("Cloning Repo: %s, to '%s', branch '%s'", repo_src, target_folder, branch)
99
- repo = Repo.clone_from(repo_src, target_folder, branch=branch, **kwargs)
100
- git_pull_checkout_reset(repo=repo, branch=branch, commit=commit, pull=pull)
137
+ repo = _git_clean_clone(repo_src, target_folder, branch=branch, **kwargs)
138
+ git_pull_checkout_reset(repo=repo, branch=branch, commit=commit, pull=False)
101
139
 
102
140
  LOGGER.info(
103
141
  "Cloned Repo: '%s'. Branch='%s' Head='%s'",
@@ -3,7 +3,7 @@ import tempfile
3
3
  import zipfile
4
4
  from pathlib import Path
5
5
 
6
- from ..helpers import download_file
6
+ from ..helpers.system import download_file
7
7
  from .git_url import GitUrl
8
8
 
9
9
  LOGGER = logging.getLogger(__name__)
@@ -0,0 +1 @@
1
+ """Provides Various Helper Functions for Odoo"""
@@ -0,0 +1,58 @@
1
+ import logging
2
+ import re
3
+ import subprocess
4
+ from ast import literal_eval
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+ from .odoo_files import _get_python_requirements_of_modules
9
+ from .system import run_cmd
10
+
11
+ LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ def _install_py_reqs_for_modules(addon_paths: List[Path], module_names: List[str] = None):
15
+ """Install Python Requirements mentioned in odoo module manifests of given modules
16
+
17
+ Parameters
18
+ ----------
19
+ addon_paths : List[Path]
20
+ odoo-bin addons path
21
+ module_names : List[str], Optional
22
+ List of modules to filter for, by default "all available modules"
23
+
24
+ Returns
25
+ -------
26
+ CompletedProcess
27
+ """
28
+ py_reqs = _get_python_requirements_of_modules(addon_paths=addon_paths, filter_module_names=module_names)
29
+ if py_reqs:
30
+ installed_packages = run_cmd(
31
+ "pip list --format json --disable-pip-version-check", check=True, shell=True, stdout=subprocess.PIPE
32
+ ).stdout.decode("utf-8")
33
+ installed_packages = [m.get("name") for m in literal_eval(installed_packages)]
34
+ if missing_packages := [p for p in py_reqs if p not in installed_packages]:
35
+ LOGGER.info("Installing Python requirements: '%s'", ", ".join(missing_packages))
36
+ return run_cmd(f"pip install {' '.join(missing_packages)} --disable-pip-version-check", shell=True)
37
+ LOGGER.debug("No py Requirements to be installed")
38
+
39
+
40
+ def _install_py_reqs_by_odoo_cmd(addon_paths: List[Path], odoo_bin_cmd: str):
41
+ """Install Python reqs for modules mentioned in odoo-bin commandline --init or -i directives.
42
+
43
+ Parameters
44
+ ----------
45
+ addon_paths : List[Path]
46
+ odoo-bin addons-path
47
+ odoo_bin_cmd : str
48
+ odoo-bin commandline
49
+
50
+ Returns
51
+ -------
52
+ CompletedProcess
53
+ """
54
+ install_modules = []
55
+ for m in re.finditer(r'(--init|-i) "?([^ \n]+)"?', odoo_bin_cmd):
56
+ install_modules += m.group(2).split(",")
57
+ if install_modules:
58
+ return _install_py_reqs_for_modules(addon_paths=addon_paths, module_names=install_modules)
@@ -9,6 +9,10 @@ from git import Repo
9
9
  LOGGER = logging.getLogger(__name__)
10
10
 
11
11
 
12
+ def get_zip_addon_path(thirdparty_path: Path) -> Path:
13
+ return thirdparty_path / "custom"
14
+
15
+
12
16
  def get_odoo_module_paths(search_folders: Union[List[Path], Path]) -> List[Path]:
13
17
  """List all Valid odoo module names in one or many Odoo addons folder.
14
18
 
@@ -101,7 +105,6 @@ def get_depends_of_module(
101
105
  return []
102
106
  already_done_modules.append(module_to_check.absolute())
103
107
 
104
- LOGGER.debug("Loading Manifest: %s", manifest_path.absolute())
105
108
  manifest = literal_eval(manifest_path.read_text())
106
109
  module_depends = manifest.get("depends", [])
107
110
  sub_depends = []
@@ -122,7 +125,6 @@ def get_depends_of_module(
122
125
  def get_addon_paths(
123
126
  odoo_main_repo: Path,
124
127
  workspace_addon_path: Path,
125
- zip_addon_path: Path,
126
128
  thirdparty_addon_path: Path,
127
129
  ) -> List[Path]:
128
130
  """Get Odoo Addon Paths for odoo.conf.
@@ -133,8 +135,6 @@ def get_addon_paths(
133
135
  Path to main odoo repo
134
136
  workspace_addon_path : Path
135
137
  Path to workspace addons
136
- zip_addon_path : Path
137
- path to zip addons
138
138
  thirdparty_addon_path : Path
139
139
  path to git cloned addon repos
140
140
 
@@ -146,6 +146,7 @@ def get_addon_paths(
146
146
  odoo_addon_paths = [odoo_main_repo / "addons"]
147
147
  if get_odoo_module_paths(workspace_addon_path):
148
148
  odoo_addon_paths.append(workspace_addon_path)
149
+ zip_addon_path = get_zip_addon_path(thirdparty_addon_path)
149
150
  zip_addon_repos = [f for f in zip_addon_path.iterdir() if f.is_dir() and get_odoo_module_paths(f)]
150
151
  odoo_addon_paths += zip_addon_repos
151
152
  git_thirdparty_addon_repos = [
@@ -155,6 +156,27 @@ def get_addon_paths(
155
156
  return odoo_addon_paths
156
157
 
157
158
 
159
+ def _get_odoo_main_path(addon_paths: List[Path]) -> Path:
160
+ """Get Odoo main path by location of odoo-bin from addon folders.
161
+
162
+ Parameters
163
+ ----------
164
+ addon_paths : List[Path]
165
+ List of possible paths
166
+
167
+ Returns
168
+ -------
169
+ Path
170
+ Path with odoo-bin and main addons folder
171
+ """
172
+ for path in addon_paths:
173
+ # The main odoo addon path is odoo/addons.
174
+ # so one up should be the launch script
175
+ bin_path = path.parent / "odoo-bin"
176
+ if bin_path.exists() and bin_path.is_file():
177
+ return path
178
+
179
+
158
180
  def _get_python_requirements_of_modules(addon_paths: List[Path], filter_module_names: List[str] = None):
159
181
  """Install python requirements mentioned in module manifests
160
182
 
@@ -170,31 +192,42 @@ def _get_python_requirements_of_modules(addon_paths: List[Path], filter_module_n
170
192
 
171
193
  if not filter_module_names:
172
194
  filter_module_names = available_module_names
173
- filter_module_names = [f for f in filter_module_names if f not in ["base", "web"]]
174
- LOGGER.info("Checking python requirements of Modules: %s", ", ".join(sorted(filter_module_names)))
195
+ filter_module_names = [f for f in filter_module_names if f != "base"]
175
196
 
176
- if unavailable_modules := [m for m in filter_module_names if m not in available_module_names]:
177
- LOGGER.warning("Couldn't search Python reqs for unavailable Modules: %s", ", ".join(unavailable_modules))
197
+ LOGGER.info("Checking python requirements of Modules:\n%s", "\n".join(sorted(filter_module_names)))
198
+ if unavailable_modules := set(filter_module_names).difference(available_module_names):
199
+ LOGGER.warning("Could not find __manifest__ for:\n%s", "\n".join(unavailable_modules))
200
+ LOGGER.debug("Search Paths:\n%s", "\n".join(map(str, addon_paths)))
178
201
 
179
202
  check_modules = [mp for mp in available_modules if mp.stem in filter_module_names]
203
+
204
+ if odoo_main_path := _get_odoo_main_path(addon_paths):
205
+ # When the Odoo main path is in the supplied path, exclude those modules.
206
+ # Odoos base requirements are set in their requirements.txt
207
+ LOGGER.debug("Py install: Excluding Odoo main Modules in: '%s'", odoo_main_path)
208
+ check_modules = [mp for mp in check_modules if odoo_main_path not in mp.parents]
209
+
180
210
  check_modules_dependencies = []
181
211
  for module in check_modules:
182
212
  check_modules_dependencies += get_depends_of_module(
183
213
  available_modules, module, already_done_modules=check_modules_dependencies
184
214
  )
185
215
  LOGGER.debug(
186
- "adding child modules to check list: %s", ", ".join(sorted([p.stem for p in check_modules_dependencies]))
216
+ "adding children of requested modules to check list:\n%s",
217
+ "\n".join(sorted([p.stem for p in check_modules_dependencies])),
187
218
  )
188
219
 
189
220
  check_modules += check_modules_dependencies
190
221
 
222
+ check_modules = set(check_modules)
223
+
191
224
  if not check_modules:
192
225
  LOGGER.debug("No Modules provided to check for python Requirements")
193
226
  return
194
227
  python_depends = []
195
228
  for module_path in check_modules:
229
+ LOGGER.debug("Checking for External Depends: %s", module_path)
196
230
  manifest_path = module_path / "__manifest__.py"
197
- LOGGER.debug("Loading Manifest: %s", manifest_path.absolute())
198
231
  manifest = literal_eval(manifest_path.read_text())
199
232
  if module_depends := manifest.get("external_dependencies", {}).get("python"):
200
233
  python_depends += module_depends
@@ -1,13 +1,15 @@
1
- """Provides Various Helper Functions for Odoo"""
2
-
1
+ """Helper functions around the host system"""
3
2
  import logging
4
3
  import os
5
4
  import subprocess
6
- import sys
7
5
  from pathlib import Path
8
6
 
7
+ import click
9
8
  import requests
10
9
  from rich.logging import RichHandler
10
+ from rich.traceback import install as install_rich_traceback
11
+
12
+ from . import cli as godoo_cli_helpers
11
13
 
12
14
  LOGGER = logging.getLogger(__name__)
13
15
 
@@ -68,6 +70,7 @@ def set_logging(verbose: bool = False) -> None:
68
70
  verbose : bool
69
71
  Wether to Log debug Messages
70
72
  """
73
+ install_rich_traceback(suppress=[click, godoo_cli_helpers])
71
74
  if verbose:
72
75
  logging.basicConfig(
73
76
  level=logging.DEBUG,
@@ -1,138 +0,0 @@
1
- """
2
- Disconnects SMTP From odoo via Config.
3
- Disconnects Label Printers via RPC.
4
- Installs and configures Web Ribbon Banner.
5
- Disables Audit rules via RPC.
6
- """
7
-
8
- import logging
9
- from configparser import ConfigParser
10
-
11
- import typer
12
- from godoo_rpc.login import wait_for_odoo
13
-
14
- from ..commands.rpc.cli import rpc_callback
15
- from ..helpers.cli import typer_unpacker
16
-
17
- LOGGER = logging.getLogger(__name__)
18
-
19
-
20
- def remove_label_printers(odoo_api, printer_url="host.docker.internal"):
21
- """Set Odoo Label Printer URL.
22
-
23
- Parameters
24
- ----------
25
- odoo_api : _type_
26
- Logged in Odoo API
27
- printer_url : str, optional
28
- printer url, by default "host.docker.internal"
29
- """
30
- printer_env = odoo_api.session.env["wetech.label.printer"]
31
- l_printer_ids = printer_env.search([])
32
- l_printers = printer_env.browse(l_printer_ids)
33
- LOGGER.info("Setting Label Printer URL for %s Printers", len(l_printers))
34
- l_printers.write({"hostname": printer_url})
35
-
36
-
37
- def staging_banner(odoo_api, banner_text: str = "", banner_background_color: str = ""):
38
- """Set Odoo top left Banner.
39
-
40
- Parameters
41
- ----------
42
- odoo_api : _type_
43
- Logged in Odoo API
44
- banner_text : str, optional
45
- Text to display on banner, by default ""
46
- banner_background_color : str, optional
47
- rbg("","","",""), by default ""
48
- """
49
- mod = odoo_api.session.env["ir.module.module"]
50
- mod_ids = mod.search(["&", ("name", "in", ["web_environment_ribbon"]), ("state", "=", "uninstalled")])
51
- modules = mod.browse(mod_ids)
52
- if modules:
53
- LOGGER.info("Installing Modules: %s", ",".join(modules.mapped("name")))
54
- modules.button_immediate_install()
55
- param_env = odoo_api.session.env["ir.config_parameter"]
56
- ribbon_text_id = param_env.search([("key", "=", "ribbon.name")])
57
- param_env.browse(ribbon_text_id).value = banner_text
58
- LOGGER.info("Setting Banner Text to: %s", banner_text)
59
- ribbon_text_id = param_env.search([("key", "=", "ribbon.background.color")])
60
- param_env.browse(ribbon_text_id).value = banner_background_color
61
- LOGGER.info("Setting Banner background color: %s", banner_background_color)
62
-
63
-
64
- def disable_audit_logs(odoo_api):
65
- """Disable audit log rules.
66
-
67
- Parameters
68
- ----------
69
- odoo_api : _type_
70
- Logged in Odoo API
71
- """
72
- mod = odoo_api.session.env["auditlog.rule"]
73
- rule_ids = mod.search([("state", "=", "subscribed")])
74
- rules = mod.browse(rule_ids)
75
- if rules:
76
- LOGGER.info("Disabling '%s' audit log rules", len(rules))
77
- rules.unsubscribe()
78
-
79
-
80
- @typer_unpacker
81
- def makedev_config(ctx: typer.Context):
82
- """
83
- Set odoo.conf values for Staging Env.
84
- """
85
- odoo_conf = ConfigParser()
86
- odoo_conf.read(ctx.obj.odoo_conf_path)
87
- LOGGER.info("Setting Odoo Conf Options for Stage")
88
- odoo_conf["options"].update(
89
- {
90
- "smtp_server": "localhost",
91
- "smtp_password": "False",
92
- "smtp_user": "False",
93
- "logfile": "",
94
- "limit_memory_hard": "2684354560",
95
- "limit_memory_soft": "2147483648",
96
- "workers": "3",
97
- "max_cron_threads": "1",
98
- "limit_time_cpu": "36000",
99
- "limit_time_real": "42000",
100
- }
101
- )
102
-
103
- with ctx.obj.odoo_conf_path.open("w") as conf:
104
- odoo_conf.write(conf)
105
-
106
-
107
- @typer_unpacker
108
- def makedev_rpc(
109
- ctx: typer.Context,
110
- banner_text: str = typer.Option(
111
- "Development", envvar="ODOO_BANNER_TEXT", help="Text to display in Top left ribbon banner"
112
- ),
113
- banner_background_color: str = typer.Option(
114
- "rgba(255,0,0,.6)", envvar="ODOO_BANNER_BG_COLOR", help="Top left ribbon banner color"
115
- ),
116
- ):
117
- """
118
- Set some Odoo Options via RPC to disable prod features.
119
- """
120
-
121
- LOGGER.info("Starting Stagesplitter")
122
- odoo_api = wait_for_odoo(
123
- odoo_host=ctx.obj.odoo_rpc_host,
124
- odoo_db=ctx.obj.odoo_main_db,
125
- odoo_user=ctx.obj.odoo_rpc_user,
126
- odoo_password=ctx.obj.odoo_rpc_password,
127
- )
128
-
129
- remove_label_printers(odoo_api=odoo_api)
130
- staging_banner(odoo_api=odoo_api, banner_text=banner_text, banner_background_color=banner_background_color)
131
- disable_audit_logs(odoo_api=odoo_api)
132
-
133
-
134
- def makedec_cli_app():
135
- app = typer.Typer(callback=rpc_callback, no_args_is_help=True)
136
- app.command("rpc", help="Set odoo.conf values for Staging Env.")(makedev_rpc)
137
- app.command("config", help="Set some Odoo Options via RPC to disable prod features.")(makedev_config)
138
- return app
File without changes
File without changes