gOdoo-cli 0.14.3__tar.gz → 0.14.5__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.
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.pre-commit-config.yaml +1 -1
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/PKG-INFO +1 -1
- godoo_cli-0.14.5/addons/godoo_test_succ_mod/__init__.py +3 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/addons/godoo_test_succ_mod/models/__init__.py +2 -0
- godoo_cli-0.14.5/addons/godoo_test_succ_mod/tests/__init__.py +3 -0
- godoo_cli-0.14.5/addons/godoo_test_succ_mod/tests/data.py +10 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/addons/godoo_test_succ_mod/tests/test_succ.py +1 -1
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/Dockerfile +3 -2
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/pyproject.toml +30 -4
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/scripts/migrations/development/shrink_database.py +3 -2
- godoo_cli-0.14.5/src/godoo_cli/__about__.py +11 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/cli.py +2 -1
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/dump.py +7 -3
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/load.py +12 -9
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/pull.py +6 -6
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/util.py +5 -3
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/bootstrap.py +11 -13
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/config.py +5 -4
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/db/connection.py +5 -4
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/db/query.py +11 -12
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/launch.py +20 -19
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/importer.py +5 -3
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/modules.py +5 -6
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/translations.py +10 -8
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/shell/scripts/odoo_banner.py +4 -5
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/shell/shell.py +34 -15
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/source_get.py +24 -20
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/test/test_load_data.py +6 -6
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/test/test_run.py +18 -11
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/git_odoo.py +6 -2
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/git_odoo_addons.py +4 -5
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/git_repo.py +4 -3
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/git_url.py +25 -16
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/zip_download.py +3 -1
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/cli.py +4 -2
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/modules.py +40 -33
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/modules_git.py +5 -6
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/modules_py.py +4 -5
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/odoo_files.py +3 -1
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/odoo_manifest.py +8 -6
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/pip.py +13 -10
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/system.py +8 -8
- godoo_cli-0.14.3/addons/godoo_test_succ_mod/__init__.py +0 -1
- godoo_cli-0.14.3/addons/godoo_test_succ_mod/tests/__init__.py +0 -1
- godoo_cli-0.14.3/addons/godoo_test_succ_mod/tests/data.py +0 -10
- godoo_cli-0.14.3/src/godoo_cli/__about__.py +0 -11
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.codecovrc +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.devcontainer/devcontainer.json +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.env.sample +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.eslintignore +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.eslintrc.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.github/FUNDING.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.github/workflows/README.md +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.github/workflows/quality.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.github/workflows/version-bump.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.github/workflows/version-publish.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.gitignore +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.prettierrc.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/.vscode/launch.json +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/LICENSE +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/README.md +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/addons/.gitkeep +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/addons/godoo_test_succ_mod/__manifest__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/assets/godoo-main-cli.png +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/assets/odoo_logo.png +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/config/nginx.conf +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/config/postgresql.conf +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/config/supervisord.conf +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/cups/Dockerfile +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/cups/config/cups-pdf.conf +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/cups/config/cupsd.conf +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/cups/cups_entrypoint.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/depends_build.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/depends_runtime.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/docker-compose.base.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/docker-compose.devcontainer-traefik.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/docker-compose.devcontainer.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/docker/docker-compose.traefik.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/godoo_src.code-workspace +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/makefile +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/odoo_manifest.yml +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/scripts/container_requirements.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/scripts/launchodoo.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/scripts/reset_devcontainer.sh +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/__main__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/cli_common.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/backup/cli.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/db/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/db/cli.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/db/passwords.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/cli.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/rpc/config_parameters.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/test/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/commands/test/cli.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/git/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/godoo_cli/helpers/__init__.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/src/tests/test_git_clone.py +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/thirdparty/.gitkeep +0 -0
- {godoo_cli-0.14.3 → godoo_cli-0.14.5}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gOdoo-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.5
|
|
4
4
|
Summary: Wrapper around Odoo-Bin with some convinience RPC functions.
|
|
5
5
|
Project-URL: repository, https://github.com/OpenJKSoftware/gOdoo
|
|
6
6
|
Author-email: Joshua Kreuder <Joshua_Kreuder@outlook.com>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Data Generation for the Test Succ Mod."""
|
|
2
|
+
|
|
3
|
+
from odoo import api
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# pylint: disable=unused-argument
|
|
7
|
+
# ruff: noqa: ARG001
|
|
8
|
+
def generate_test_data(env: api.Environment):
|
|
9
|
+
"""Generate Test Data for the ven Environment."""
|
|
10
|
+
# Add your Test Data Generation code here
|
|
@@ -30,7 +30,8 @@ ARG VIRTUAL_ENV
|
|
|
30
30
|
ARG USERNAME
|
|
31
31
|
# Path Env Vars:
|
|
32
32
|
ENV VIRTUAL_ENV=${VIRTUAL_ENV} \
|
|
33
|
-
UV_PROJECT_ENVIRONMENT=${VIRTUAL_ENV}
|
|
33
|
+
UV_PROJECT_ENVIRONMENT=${VIRTUAL_ENV} \
|
|
34
|
+
UV_COMPILE_BYTECODE=1
|
|
34
35
|
ENV PYTHONPATH="$ODOO_MAIN_FOLDER:$WORKSPACE:$PYTHONPATH" \
|
|
35
36
|
PATH="$ODOO_MAIN_FOLDER:$WORKSPACE:$WORKSPACE/scripts:$VIRTUAL_ENV/bin:$PATH"
|
|
36
37
|
RUN --mount=type=cache,target=$UV_CACHE_DIR,uid=1000,gid=1000 uv venv ${VIRTUAL_ENV}
|
|
@@ -51,7 +52,7 @@ COPY pyproject.toml uv.lock README.md ./
|
|
|
51
52
|
RUN --mount=type=cache,target=$UV_CACHE_DIR,uid=1000,gid=1000 uv sync --no-install-project --compile-bytecode
|
|
52
53
|
|
|
53
54
|
COPY --chown=$USERNAME:$USERNAME ./src ./src
|
|
54
|
-
RUN --mount=type=cache,target=$UV_CACHE_DIR,uid=1000,gid=1000 uv sync --compile-bytecode
|
|
55
|
+
RUN --mount=type=cache,target=$UV_CACHE_DIR,uid=1000,gid=1000 uv sync --all-extras --compile-bytecode
|
|
55
56
|
# In the Devcontainer stage we remove everything in $WORKSPACE and replace it with a Bind-Mount
|
|
56
57
|
# ------------------------------------------------------------------------------------------------------
|
|
57
58
|
# Godoo Pypi Install via pip
|
|
@@ -82,9 +82,9 @@ installer = "uv"
|
|
|
82
82
|
|
|
83
83
|
# Linting commands
|
|
84
84
|
lint = [
|
|
85
|
-
"ruff check
|
|
86
|
-
"ruff format --check
|
|
87
|
-
"pylint
|
|
85
|
+
"ruff check .",
|
|
86
|
+
"ruff format --check .",
|
|
87
|
+
"pylint .", # Keep pylint for Odoo-specific checks
|
|
88
88
|
]
|
|
89
89
|
|
|
90
90
|
# Testing commands
|
|
@@ -102,6 +102,7 @@ ci = [
|
|
|
102
102
|
[tool.ruff]
|
|
103
103
|
line-length = 120
|
|
104
104
|
target-version = "py39"
|
|
105
|
+
exclude = [".venv"]
|
|
105
106
|
|
|
106
107
|
[tool.ruff.lint]
|
|
107
108
|
select = [
|
|
@@ -112,11 +113,34 @@ select = [
|
|
|
112
113
|
"C", # flake8-comprehensions
|
|
113
114
|
"B", # flake8-bugbear
|
|
114
115
|
"D", # pydocstyle
|
|
116
|
+
"ANN", # flake8-annotations (type hints)
|
|
117
|
+
"ARG", # flake8-unused-arguments
|
|
118
|
+
"COM", # flake8-commas
|
|
119
|
+
"DTZ", # flake8-datetimez
|
|
120
|
+
"EM", # flake8-errmsg (better error messages)
|
|
121
|
+
"ERA", # eradicate (commented out code)
|
|
122
|
+
"N", # pep8-naming
|
|
123
|
+
"PIE", # flake8-pie
|
|
124
|
+
"PT", # flake8-pytest-style
|
|
125
|
+
"RUF", # Ruff-specific rules
|
|
126
|
+
"SIM", # flake8-simplify
|
|
127
|
+
"TD", # flake8-todos
|
|
128
|
+
"TRY", # flake8-try-except-raise
|
|
129
|
+
"UP", # pyupgrade
|
|
115
130
|
]
|
|
116
131
|
ignore = [
|
|
117
132
|
"E203", # Whitespace before ':'
|
|
118
133
|
"E266", # Too many leading '#' for block comment
|
|
119
134
|
"E501", # Line too long (handled by formatter)
|
|
135
|
+
"ANN401", # Dynamically typed expressions (Any) are disallowed
|
|
136
|
+
"ANN201", # Missing return type for public method
|
|
137
|
+
"ANN202", # Missing type for private method
|
|
138
|
+
"TD002", # Missing author in TODO
|
|
139
|
+
"TD003", # Missing issue link in TODO
|
|
140
|
+
"COM812", # enforce trailing comma in broken up lists
|
|
141
|
+
"TRY003", # Dont enforce exception subclasses
|
|
142
|
+
"TRY201", # Allow reraise of caught exception
|
|
143
|
+
"DTZ006", # Datetime timezone requrement
|
|
120
144
|
]
|
|
121
145
|
|
|
122
146
|
[tool.ruff.lint.pydocstyle]
|
|
@@ -129,6 +153,7 @@ skip-magic-trailing-comma = false
|
|
|
129
153
|
line-ending = "auto"
|
|
130
154
|
|
|
131
155
|
[tool.ruff.lint.per-file-ignores]
|
|
156
|
+
"__manifest__.py" = ["D101","D100","B018"]
|
|
132
157
|
"__init__.py" = ["F401", "F403"] # Ignore unused and * imports in __init__.py files
|
|
133
158
|
"tests/*" = ["S101", "D100", "D101", "D102", "D103", "D104", "D105", "D107"] # Ignore assert usage and docstrings in tests
|
|
134
159
|
"test_*.py" = ["S101", "D100", "D101", "D102", "D103", "D104", "D105", "D107"] # Same for test files in any directory
|
|
@@ -136,7 +161,7 @@ line-ending = "auto"
|
|
|
136
161
|
|
|
137
162
|
[tool.pylint.master]
|
|
138
163
|
load-plugins = "pylint_odoo,pylint.extensions.no_self_use"
|
|
139
|
-
ignore = ["CVS", ".git", ".hg", ".tox", ".eggs", "*.egg", "build", "dist"]
|
|
164
|
+
ignore = ["CVS", ".git", ".hg", ".tox", ".eggs", "*.egg", "build", "dist", ".venv"]
|
|
140
165
|
persistent = true
|
|
141
166
|
jobs = 0
|
|
142
167
|
|
|
@@ -177,6 +202,7 @@ enable = [
|
|
|
177
202
|
"missing-return",
|
|
178
203
|
"syntax-error",
|
|
179
204
|
"undefined-variable",
|
|
205
|
+
"no-value-for-parameter", # E1120
|
|
180
206
|
]
|
|
181
207
|
|
|
182
208
|
[tool.pylint.similarities]
|
|
@@ -4,7 +4,7 @@ from logging import getLogger
|
|
|
4
4
|
|
|
5
5
|
LOGGER = getLogger("migrations.shrink_database")
|
|
6
6
|
|
|
7
|
-
env = env #
|
|
7
|
+
env = env # noqa: F821 # pylint: disable=undefined-variable # pyright: ignore
|
|
8
8
|
|
|
9
9
|
LOGGER.info("Shrinking Database")
|
|
10
10
|
att = env["ir.attachment"].search(
|
|
@@ -22,7 +22,8 @@ LOGGER.info("Attachments to Delete: %d", len(att))
|
|
|
22
22
|
LOGGER.info("Size: %dMB", round(sum(att.mapped("file_size")) / 1024 / 1024, 2))
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def chunks(lst, n):
|
|
25
|
+
def chunks(lst: list, n: int):
|
|
26
|
+
"""Chunk an iterable into chunks of size n."""
|
|
26
27
|
for i in range(0, len(lst), n):
|
|
27
28
|
yield lst[i : i + n]
|
|
28
29
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Version information."""
|
|
2
|
+
|
|
3
|
+
from packaging import version
|
|
4
|
+
|
|
5
|
+
__version__ = "0.14.5" # Initial version, will be managed by Hatch
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_version_tuple() -> tuple[int, int, int]:
|
|
9
|
+
"""Convert the version string into a tuple of integers."""
|
|
10
|
+
vers = version.parse(__version__)
|
|
11
|
+
return vers.major, vers.minor, vers.micro
|
|
@@ -5,6 +5,7 @@ It sets up the command structure, configures logging, and provides the core CLI
|
|
|
5
5
|
for interacting with Odoo instances.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from pathlib import Path
|
|
8
9
|
from typing import Annotated, Optional
|
|
9
10
|
|
|
10
11
|
import typer
|
|
@@ -34,7 +35,7 @@ from .helpers.system import set_logging
|
|
|
34
35
|
CLI = CommonCLI()
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def print_versions(odoo_main_path
|
|
38
|
+
def print_versions(odoo_main_path: Annotated[Path, CLI.odoo_paths.bin_path]):
|
|
38
39
|
"""Print gOdoo and Odoo Version info."""
|
|
39
40
|
rich_print(f"gOdoo Version: [bold green]{__about__.__version__}[/bold green]")
|
|
40
41
|
odoo_version = odoo_bin_get_version(odoo_main_path)
|
|
@@ -50,10 +50,14 @@ def dump_instance(
|
|
|
50
50
|
port=db_port,
|
|
51
51
|
)
|
|
52
52
|
if not conf_path.exists():
|
|
53
|
-
|
|
53
|
+
msg = f"No Odoo Conf Path provided or doesnt exists: '{conf_path}'"
|
|
54
|
+
LOGGER.error(msg)
|
|
55
|
+
raise typer.Exit(msg)
|
|
54
56
|
|
|
55
57
|
if not dump_path.exists():
|
|
56
|
-
|
|
58
|
+
msg = f"No Dump Path provided or doesnt exists: '{dump_path}'"
|
|
59
|
+
LOGGER.error(msg)
|
|
60
|
+
raise typer.Exit(msg)
|
|
57
61
|
|
|
58
62
|
# Read .conf value [options] datad_dir
|
|
59
63
|
parser = ConfigParser()
|
|
@@ -70,7 +74,7 @@ def dump_instance(
|
|
|
70
74
|
db_dump_target = dump_path / "odoo.dump"
|
|
71
75
|
LOGGER.info("Dumping DB -> %s", db_dump_target)
|
|
72
76
|
db_dump_target.unlink(missing_ok=True)
|
|
73
|
-
db_connection.run_psql_shell_command("pg_dump --format c {} >
|
|
77
|
+
db_connection.run_psql_shell_command(f"pg_dump --format c {{}} > {db_dump_target}")
|
|
74
78
|
LOGGER.info("SQL Dump Completed with size -> %.2f MB", db_dump_target.stat().st_size / (1024 * 1024))
|
|
75
79
|
|
|
76
80
|
readme_path = dump_path / "README.md"
|
|
@@ -6,9 +6,9 @@ supporting various dump formats and handling database creation and restoration.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
from pathlib import Path
|
|
9
|
+
from typing import Annotated, Optional
|
|
9
10
|
|
|
10
11
|
import typer
|
|
11
|
-
from typing_extensions import Annotated
|
|
12
12
|
|
|
13
13
|
from ...cli_common import CommonCLI
|
|
14
14
|
from ..db.connection import DBConnection
|
|
@@ -21,14 +21,16 @@ CLI = CommonCLI()
|
|
|
21
21
|
def load_pg_dump(
|
|
22
22
|
dump_path: Path,
|
|
23
23
|
db_name: str,
|
|
24
|
-
db_host: str = None,
|
|
24
|
+
db_host: Optional[str] = None,
|
|
25
25
|
db_port: int = 0,
|
|
26
|
-
db_user: str = None,
|
|
27
|
-
db_password: str = None,
|
|
26
|
+
db_user: Optional[str] = None,
|
|
27
|
+
db_password: Optional[str] = None,
|
|
28
28
|
):
|
|
29
29
|
"""Drop and recreate db_name and restore dump_path into it."""
|
|
30
30
|
if not dump_path.exists():
|
|
31
|
-
|
|
31
|
+
msg = f"Cannot find Odoo Dump @ {dump_path}"
|
|
32
|
+
LOGGER.error(msg)
|
|
33
|
+
raise FileNotFoundError(msg)
|
|
32
34
|
|
|
33
35
|
conn = DBConnection(
|
|
34
36
|
db_name="postgres",
|
|
@@ -49,10 +51,11 @@ def load_pg_dump(
|
|
|
49
51
|
round(dump_path.stat().st_size / (1024 * 1024), 2),
|
|
50
52
|
db_name,
|
|
51
53
|
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
command = (
|
|
55
|
+
f"pg_restore --no-owner --format c --dbname {db_name} --jobs 8 {dump_path}"
|
|
56
|
+
if dump_path.suffix == ".dump"
|
|
57
|
+
else f"cat {dump_path} | psql {db_name} >/dev/null"
|
|
58
|
+
)
|
|
56
59
|
load_return = conn.run_psql_shell_command(
|
|
57
60
|
command=command,
|
|
58
61
|
text=True,
|
|
@@ -7,10 +7,10 @@ supporting various transfer methods and backup formats.
|
|
|
7
7
|
import logging
|
|
8
8
|
import subprocess
|
|
9
9
|
from pathlib import Path
|
|
10
|
+
from typing import Annotated, Optional
|
|
10
11
|
|
|
11
12
|
import typer
|
|
12
13
|
from rich.progress import track
|
|
13
|
-
from typing_extensions import Annotated
|
|
14
14
|
|
|
15
15
|
from ...cli_common import CommonCLI
|
|
16
16
|
from ...helpers.system import typer_ask_overwrite_path
|
|
@@ -147,30 +147,30 @@ class InstancePuller:
|
|
|
147
147
|
pg_db_user: Annotated[str, CLI.database.db_user],
|
|
148
148
|
pg_db_name: Annotated[str, CLI.database.db_name],
|
|
149
149
|
ssh_user: Annotated[
|
|
150
|
-
str,
|
|
150
|
+
Optional[str],
|
|
151
151
|
typer.Option(
|
|
152
152
|
help="SSH User of remote instance.", rich_help_panel="Remote Options", envvar="ODOO_PULL_SSH_USER"
|
|
153
153
|
),
|
|
154
154
|
] = None,
|
|
155
155
|
ssh_hostname: Annotated[
|
|
156
|
-
str,
|
|
156
|
+
Optional[str],
|
|
157
157
|
typer.Option(
|
|
158
158
|
help="SSH Hostname of remote instance.", rich_help_panel="Remote Options", envvar="ODOO_PULL_HOST"
|
|
159
159
|
),
|
|
160
160
|
] = None,
|
|
161
161
|
filestore_folder: Annotated[
|
|
162
|
-
Path,
|
|
162
|
+
Optional[Path],
|
|
163
163
|
typer.Option(help="Path to odoo web folder.", rich_help_panel="Filestore Options"),
|
|
164
164
|
] = None,
|
|
165
165
|
filestore_volume: Annotated[
|
|
166
|
-
str,
|
|
166
|
+
Optional[str],
|
|
167
167
|
typer.Option(
|
|
168
168
|
help="Alternative to valib-folder. A Docker volume name, that gets used to derive filestore-folder.",
|
|
169
169
|
rich_help_panel="Filestore Options",
|
|
170
170
|
),
|
|
171
171
|
] = None,
|
|
172
172
|
pg_container: Annotated[
|
|
173
|
-
str,
|
|
173
|
+
Optional[str],
|
|
174
174
|
typer.Option(
|
|
175
175
|
help="Postgres Container Name. (Optional)",
|
|
176
176
|
rich_help_panel="Database Options",
|
|
@@ -25,7 +25,9 @@ def call_rsync(source_folder: Path, target_folder: Path, rsync_delete: bool = Tr
|
|
|
25
25
|
FileNotFoundError: If source folder doesn't exist or is empty.
|
|
26
26
|
"""
|
|
27
27
|
if not source_folder.exists() and not source_folder.glob("*"):
|
|
28
|
-
|
|
28
|
+
msg = f"Cannot find filestore Backup @ {source_folder}"
|
|
29
|
+
LOGGER.error(msg)
|
|
30
|
+
raise FileNotFoundError(msg)
|
|
29
31
|
args = ["rsync", "-a", "--no-perms", "--no-owner", "--no-group", "--info=progress2"]
|
|
30
32
|
if rsync_delete:
|
|
31
33
|
args += ["--delete"]
|
|
@@ -40,7 +42,7 @@ def drop_db(connection: DBConnection, db_name: str):
|
|
|
40
42
|
with connection.connect() as cur:
|
|
41
43
|
cur.connection.autocommit = True
|
|
42
44
|
LOGGER.info("Dropping DB: %s", db_name)
|
|
43
|
-
cur.execute("DROP DATABASE IF EXISTS
|
|
45
|
+
cur.execute(f"DROP DATABASE IF EXISTS {db_name}")
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
def create_db(connection: DBConnection, db_name: str):
|
|
@@ -48,4 +50,4 @@ def create_db(connection: DBConnection, db_name: str):
|
|
|
48
50
|
with connection.connect() as cur:
|
|
49
51
|
cur.connection.autocommit = True
|
|
50
52
|
LOGGER.info("Creating DB: %s", db_name)
|
|
51
|
-
cur.execute("CREATE DATABASE
|
|
53
|
+
cur.execute(f"CREATE DATABASE {db_name}")
|
|
@@ -9,13 +9,12 @@ import logging
|
|
|
9
9
|
import os
|
|
10
10
|
import re
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import
|
|
12
|
+
from typing import Annotated, Any, Optional
|
|
13
13
|
|
|
14
14
|
import typer
|
|
15
|
-
from typing_extensions import Annotated
|
|
16
15
|
|
|
17
16
|
from ..cli_common import CommonCLI
|
|
18
|
-
from ..helpers.modules import
|
|
17
|
+
from ..helpers.modules import GodooModules, get_addon_paths
|
|
19
18
|
from ..helpers.modules_py import _install_py_reqs_by_odoo_cmd
|
|
20
19
|
from ..helpers.system import run_cmd
|
|
21
20
|
from .db.connection import DBConnection
|
|
@@ -26,7 +25,7 @@ CLI = CommonCLI()
|
|
|
26
25
|
LOGGER = logging.getLogger(__name__)
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
def _add_default_argument(cmd_list:
|
|
28
|
+
def _add_default_argument(cmd_list: list[str], arg: str, arg_val: Any):
|
|
30
29
|
"""Add a default argument to the command list if not already present.
|
|
31
30
|
|
|
32
31
|
Args:
|
|
@@ -41,11 +40,11 @@ def _add_default_argument(cmd_list: List[str], arg: str, arg_val: Any):
|
|
|
41
40
|
def _boostrap_command(
|
|
42
41
|
odoo_main_path: Path,
|
|
43
42
|
odoo_conf_path: Path,
|
|
44
|
-
addon_paths:
|
|
43
|
+
addon_paths: list[Path],
|
|
45
44
|
workspace_addon_path: Path,
|
|
46
45
|
db_filter: str,
|
|
47
46
|
db_connection: DBConnection,
|
|
48
|
-
extra_cmd_args: Optional[
|
|
47
|
+
extra_cmd_args: Optional[list[str]] = None,
|
|
49
48
|
install_workspace_modules: bool = True,
|
|
50
49
|
multithread_worker_count: int = -1,
|
|
51
50
|
languages: str = "de_DE,en_US",
|
|
@@ -87,11 +86,10 @@ def _boostrap_command(
|
|
|
87
86
|
|
|
88
87
|
init_modules = []
|
|
89
88
|
extra_cmd_args_str = " ".join(extra_cmd_args or [])
|
|
90
|
-
if not re.search(r"(-i|--init) ", extra_cmd_args_str):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
init_modules += [f.name for f in workspace_addons]
|
|
89
|
+
if install_workspace_modules and not re.search(r"(-i|--init) ", extra_cmd_args_str):
|
|
90
|
+
workspace_modules = GodooModules([workspace_addon_path])
|
|
91
|
+
if workspace_addons := workspace_modules.get_modules():
|
|
92
|
+
init_modules += [f.name for f in workspace_addons]
|
|
95
93
|
init_cmd = "--init " + ",".join(init_modules) if init_modules else ""
|
|
96
94
|
|
|
97
95
|
addon_paths_str_list = [str(p.absolute()) for p in addon_paths if p and p.exists()]
|
|
@@ -100,7 +98,7 @@ def _boostrap_command(
|
|
|
100
98
|
base_cmds = [
|
|
101
99
|
str(odoo_main_path.absolute()) + "/odoo-bin",
|
|
102
100
|
init_cmd,
|
|
103
|
-
f"--config {
|
|
101
|
+
f"--config {odoo_conf_path.absolute()!s}",
|
|
104
102
|
"--save",
|
|
105
103
|
f"--load-language {languages}",
|
|
106
104
|
"--stop-after-init",
|
|
@@ -137,7 +135,7 @@ def bootstrap_odoo(
|
|
|
137
135
|
db_host: Annotated[str, CLI.database.db_host],
|
|
138
136
|
db_port: Annotated[int, CLI.database.db_port] = 0,
|
|
139
137
|
db_password: Annotated[str, CLI.database.db_password] = "",
|
|
140
|
-
extra_cmd_args: Annotated[
|
|
138
|
+
extra_cmd_args: Annotated[Optional[list[str]], CLI.odoo_launch.extra_cmd_args_bootstrap] = None,
|
|
141
139
|
multithread_worker_count: Annotated[int, CLI.odoo_launch.multithread_worker_count] = 2,
|
|
142
140
|
languages: Annotated[str, CLI.odoo_launch.languages] = "de_DE,en_US",
|
|
143
141
|
install_workspace_modules: Annotated[bool, CLI.odoo_launch.install_workspace_modules] = True,
|
|
@@ -8,7 +8,7 @@ command-line arguments.
|
|
|
8
8
|
import logging
|
|
9
9
|
from configparser import ConfigParser
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Annotated
|
|
11
|
+
from typing import Annotated
|
|
12
12
|
|
|
13
13
|
import typer
|
|
14
14
|
|
|
@@ -19,7 +19,7 @@ LOGGER = logging.getLogger(__name__)
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def set_odoo_config(
|
|
22
|
-
options: Annotated[
|
|
22
|
+
options: Annotated[list[str], typer.Argument(help="odoo.conf options by key=value")],
|
|
23
23
|
odoo_conf_path: Annotated[Path, CLI.odoo_paths.conf_path],
|
|
24
24
|
):
|
|
25
25
|
"""Set odoo.conf values."""
|
|
@@ -30,8 +30,9 @@ def set_odoo_config(
|
|
|
30
30
|
custom_opts = {}
|
|
31
31
|
for op in options:
|
|
32
32
|
if "=" not in op:
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
msg = f"Cannot parse Option: '{op}' --> missing '=' sign (key=value)"
|
|
34
|
+
LOGGER.error(msg)
|
|
35
|
+
raise ValueError(msg)
|
|
35
36
|
op_split = op.split("=")
|
|
36
37
|
custom_opts[op_split[0]] = op_split[1]
|
|
37
38
|
LOGGER.debug("Writing Conf Options: %s", custom_opts)
|
|
@@ -6,9 +6,10 @@ executing database queries using the psycopg2 library.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
import subprocess
|
|
9
|
+
from collections.abc import Generator
|
|
9
10
|
from contextlib import contextmanager
|
|
10
11
|
from dataclasses import dataclass
|
|
11
|
-
from typing import Annotated,
|
|
12
|
+
from typing import Annotated, Any, Optional
|
|
12
13
|
|
|
13
14
|
import psycopg2
|
|
14
15
|
|
|
@@ -86,7 +87,7 @@ class DBConnection:
|
|
|
86
87
|
)
|
|
87
88
|
|
|
88
89
|
@property
|
|
89
|
-
def cli_dict(self) ->
|
|
90
|
+
def cli_dict(self) -> dict[str, Optional[str]]:
|
|
90
91
|
"""Get connection parameters as a dictionary.
|
|
91
92
|
|
|
92
93
|
Returns:
|
|
@@ -101,7 +102,7 @@ class DBConnection:
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
@contextmanager
|
|
104
|
-
def connect(self):
|
|
105
|
+
def connect(self) -> Generator[psycopg2.extensions.cursor, None, None]:
|
|
105
106
|
"""Create a database connection and cursor.
|
|
106
107
|
|
|
107
108
|
This context manager creates a database connection and cursor,
|
|
@@ -129,7 +130,7 @@ class DBConnection:
|
|
|
129
130
|
cr.close()
|
|
130
131
|
connection.close()
|
|
131
132
|
|
|
132
|
-
def run_psql_shell_command(self, command: str, **kwargs):
|
|
133
|
+
def run_psql_shell_command(self, command: str, **kwargs: dict[str, Any]) -> subprocess.CompletedProcess:
|
|
133
134
|
"""Run a psql command using the provided credentials.
|
|
134
135
|
|
|
135
136
|
{} in the command will get templated with the connection string.
|
|
@@ -16,7 +16,7 @@ from ...helpers.cli import check_dangerous_command
|
|
|
16
16
|
from .connection import DBConnection
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class
|
|
19
|
+
class DbBootstrapStatus(enum.Enum):
|
|
20
20
|
"""Database bootstrap status enumeration.
|
|
21
21
|
|
|
22
22
|
This enum represents the possible states of database bootstrapping:
|
|
@@ -78,24 +78,23 @@ def query_database(
|
|
|
78
78
|
except ProgrammingError:
|
|
79
79
|
# When there is nothing to fetch, fetchall() raises a ProgrammingError
|
|
80
80
|
pass
|
|
81
|
-
except Exception
|
|
82
|
-
LOGGER.exception(e)
|
|
81
|
+
except Exception:
|
|
83
82
|
raise typer.Exit(1) # noqa: B904
|
|
84
83
|
|
|
85
84
|
|
|
86
|
-
def _is_bootstrapped(db_connection: DBConnection) ->
|
|
85
|
+
def _is_bootstrapped(db_connection: DBConnection) -> DbBootstrapStatus:
|
|
87
86
|
"""Check if postgres contains database db_name and if this database has any tables present."""
|
|
88
87
|
try:
|
|
89
88
|
with db_connection.connect() as cursor:
|
|
90
89
|
cursor.execute("SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public');")
|
|
91
90
|
if not cursor.fetchone()[0]:
|
|
92
91
|
LOGGER.debug("Database '%s' is empty", db_connection.db_name)
|
|
93
|
-
return
|
|
92
|
+
return DbBootstrapStatus.EMPTY_DB
|
|
94
93
|
LOGGER.debug("Database '%s' is not empty", db_connection.db_name)
|
|
95
|
-
return
|
|
94
|
+
return DbBootstrapStatus.BOOTSTRAPPED
|
|
96
95
|
except OperationalError:
|
|
97
96
|
LOGGER.debug("Database '%s' does not exist", db_connection.db_name)
|
|
98
|
-
return
|
|
97
|
+
return DbBootstrapStatus.NO_DB
|
|
99
98
|
|
|
100
99
|
|
|
101
100
|
def is_bootstrapped(
|
|
@@ -119,16 +118,16 @@ def is_bootstrapped(
|
|
|
119
118
|
bootstrap_value = _is_bootstrapped(db_connection=connection)
|
|
120
119
|
LOGGER.info("Odoo Database Status: %s", bootstrap_value.value)
|
|
121
120
|
ret_mapping = {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
DbBootstrapStatus.BOOTSTRAPPED: 0,
|
|
122
|
+
DbBootstrapStatus.NO_DB: 20,
|
|
123
|
+
DbBootstrapStatus.EMPTY_DB: 21,
|
|
125
124
|
}
|
|
126
125
|
raise typer.Exit(ret_mapping[bootstrap_value])
|
|
127
126
|
|
|
128
127
|
|
|
129
|
-
def _get_installed_modules(db_connection: DBConnection, to_install=False):
|
|
128
|
+
def _get_installed_modules(db_connection: DBConnection, to_install: bool = False) -> list[str]:
|
|
130
129
|
"""Get list of installed modules in database (to_install includes the modules marked for installation)."""
|
|
131
|
-
if (boot := _is_bootstrapped(db_connection=db_connection)) !=
|
|
130
|
+
if (boot := _is_bootstrapped(db_connection=db_connection)) != DbBootstrapStatus.BOOTSTRAPPED:
|
|
132
131
|
return boot.value
|
|
133
132
|
lookup_states = ["installed", "to upgrade"]
|
|
134
133
|
if to_install:
|