gOdoo-cli 0.1.5__tar.gz → 0.2.0__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 (33) hide show
  1. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/PKG-INFO +1 -1
  2. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/pyproject.toml +1 -1
  3. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/setup.py +1 -1
  4. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/__init__.py +1 -1
  5. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/cli.py +7 -3
  6. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/__init__.py +1 -1
  7. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/bootstrap.py +4 -47
  8. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/launch.py +1 -1
  9. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/shell.py +1 -1
  10. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/source_get.py +65 -21
  11. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/zip_download.py +1 -1
  12. godoo_cli-0.2.0/src/godoo_cli/helpers/__init__.py +1 -0
  13. godoo_cli-0.2.0/src/godoo_cli/helpers/bootstrap.py +58 -0
  14. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/helpers/odoo_files.py +43 -10
  15. godoo_cli-0.1.5/src/godoo_cli/helpers/__init__.py → godoo_cli-0.2.0/src/godoo_cli/helpers/system.py +10 -9
  16. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/LICENSE +0 -0
  17. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/README.md +0 -0
  18. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/__main__.py +0 -0
  19. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/makedev.py +0 -0
  20. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/__init__.py +0 -0
  21. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/cli.py +0 -0
  22. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/cli_callbacks.py +0 -0
  23. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/importer.py +0 -0
  24. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/modules.py +0 -0
  25. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/rpc/translations.py +0 -0
  26. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/commands/test.py +0 -0
  27. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/__init__.py +0 -0
  28. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/git_odoo.py +0 -0
  29. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/git_odoo_addons.py +0 -0
  30. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/git_repo.py +0 -0
  31. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/git/git_url.py +0 -0
  32. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/src/godoo_cli/helpers/cli.py +0 -0
  33. {godoo_cli-0.1.5 → godoo_cli-0.2.0}/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.5
3
+ Version: 0.2.0
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.5"
3
+ version = "0.2.0"
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.5',
43
+ 'version': '0.2.0',
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.5"
1
+ __version__ = "0.2.0"
2
2
  from .cli import launch_cli
@@ -9,6 +9,7 @@ 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
14
  makedec_cli_app,
14
15
  odoo_shell,
@@ -16,7 +17,7 @@ from .commands import (
16
17
  rpc_cli_app,
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(
@@ -65,8 +66,11 @@ def main_cli():
65
66
  # Normal Subcommands
66
67
  app.command("launch", help="Launch Odoo, Bootstrap if bootstrapflag is not present")(launch_odoo)
67
68
  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)
69
+ app.command("source-get-file", help="Get Raw file from odoo git remote or specific git remote.")(get_source_file)
70
+ app.command("source-get-depends", help="Install dependencies from __manifest__.py in specified modules")(
71
+ install_module_dependencies
72
+ )
73
+ app.command("source-get", help="Download/Unzip Odoo Source and thirdparty addons.")(get_source)
70
74
  app.command("test", help="Bootstrap or Launch odoo in Testing Mode")(odoo_test)
71
75
  app.command("shell", help="Shell into Odoo")(odoo_shell)
72
76
  app.command("uninstall", help="Uninstall Modules")(uninstall_modules)
@@ -3,5 +3,5 @@ from .launch import launch_odoo
3
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
@@ -5,56 +5,15 @@ from typing import List
5
5
 
6
6
  import typer
7
7
 
8
- from ..helpers import run_cmd
8
+ from ..helpers.bootstrap import _install_py_reqs_by_odoo_cmd
9
9
  from ..helpers.cli import typer_retuner, typer_unpacker
10
- 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
11
12
  from .source_get import get_source
12
13
 
13
14
  LOGGER = logging.getLogger(__name__)
14
15
 
15
16
 
16
- def _install_py_reqs_for_modules(addon_paths: List[Path], module_names: List[str] = None):
17
- """Install Python Requirements mentioned in odoo module manifests of given modules
18
-
19
- Parameters
20
- ----------
21
- addon_paths : List[Path]
22
- odoo-bin addons path
23
- module_names : List[str], Optional
24
- List of modules to filter for, by default "all available modules"
25
-
26
- Returns
27
- -------
28
- CompletedProcess
29
- """
30
- py_reqs = _get_python_requirements_of_modules(addon_paths=addon_paths, filter_module_names=module_names)
31
- if py_reqs:
32
- LOGGER.info("Installing Python requirements: %s", ", ".join(py_reqs))
33
- return run_cmd(f"pip install {' '.join(py_reqs)}")
34
- LOGGER.debug("No py Requirements to be installed")
35
-
36
-
37
- def _install_py_reqs_by_odoo_cmd(addon_paths: List[Path], odoo_bin_cmd: str):
38
- """Install Python reqs for modules mentioned in odoo-bin commandline --init or -i directives.
39
-
40
- Parameters
41
- ----------
42
- addon_paths : List[Path]
43
- odoo-bin addons-path
44
- odoo_bin_cmd : str
45
- odoo-bin commandline
46
-
47
- Returns
48
- -------
49
- CompletedProcess
50
- """
51
- install_modules = []
52
- for m in re.finditer(r'(--init|-i) "?([^ \n]+)"?', odoo_bin_cmd):
53
- install_modules += m.group(2).split(",")
54
- if install_modules:
55
- return _install_py_reqs_for_modules(addon_paths=addon_paths, module_names=install_modules)
56
-
57
-
58
17
  def _boostrap_command(
59
18
  odoo_main_path: Path,
60
19
  odoo_conf_path: Path,
@@ -195,7 +154,6 @@ def bootstrap_odoo(
195
154
  addon_paths = get_addon_paths(
196
155
  odoo_main_repo=ctx.obj.odoo_main_path,
197
156
  workspace_addon_path=ctx.obj.workspace_addon_path,
198
- zip_addon_path=thirdparty_addon_path / "custom", # !Todo Pull out into variable
199
157
  thirdparty_addon_path=thirdparty_addon_path,
200
158
  )
201
159
 
@@ -217,8 +175,7 @@ def bootstrap_odoo(
217
175
  languages=languages,
218
176
  )
219
177
 
220
- if update_source:
221
- _install_py_reqs_by_odoo_cmd(addon_paths=addon_paths, odoo_bin_cmd=cmd_string)
178
+ _install_py_reqs_by_odoo_cmd(addon_paths=addon_paths, odoo_bin_cmd=cmd_string)
222
179
 
223
180
  LOGGER.info("Launching Bootstrap Commandline")
224
181
  ret = run_cmd(cmd_string).returncode
@@ -6,9 +6,9 @@ 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
13
  from .makedev import makedev_config, makedev_rpc
14
14
  from .rpc import import_to_odoo
@@ -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,12 +27,12 @@ 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
@@ -38,14 +40,33 @@ def unzip_addons(zip_folder: Path, target_addon_folder: Path, remove_excess: boo
38
40
  remove all and then unzip, by default False
39
41
  """
40
42
  if remove_excess:
43
+ LOGGER.debug("Clearing out unarchive folder: %s", target_addon_folder)
41
44
  for folder in target_addon_folder.iterdir():
42
45
  shutil.rmtree(folder)
43
- LOGGER.info("Extracting Zip Addons to: %s", target_addon_folder)
44
- for zip_file in zip_folder.glob("*.zip"):
46
+ LOGGER.info("Extracting archive addons to: %s", target_addon_folder)
47
+ for zip_file in archive_folder.glob("*.zip"):
45
48
  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)
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)
@@ -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,9 +1,7 @@
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
 
9
7
  import requests
@@ -12,21 +10,24 @@ from rich.logging import RichHandler
12
10
  LOGGER = logging.getLogger(__name__)
13
11
 
14
12
 
15
- def run_cmd(command: str) -> subprocess.CompletedProcess:
16
- """Runs command via subprocess
13
+ def run_cmd(command: str, **kwargs) -> subprocess.CompletedProcess:
14
+ """Runs command via subprocess.run
17
15
 
18
16
  Parameters
19
17
  ----------
20
18
  command : str
21
- _description_
19
+ Command string
20
+ **kwargs
21
+ get passed down to Run
22
22
 
23
23
  Returns
24
24
  -------
25
- _type_
26
- _description_
25
+ CompletedProcess
27
26
  """
28
27
  LOGGER.debug("Launching Commandline: '%s'", command)
29
- proc = subprocess.run(command, shell=True)
28
+ if not kwargs.get("shell"):
29
+ kwargs["shell"] = True
30
+ proc = subprocess.run(command, **kwargs)
30
31
  return proc
31
32
 
32
33
 
File without changes
File without changes