Commit 48f53f2a authored by Alexis PASQUIER's avatar Alexis PASQUIER
Browse files

Création de la lib en 1.0.0

parents
Pipeline #73241 failed with stages
in 1 minute and 29 seconds
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
include: https://gitlab.ndp-systemes.fr/odoo-addons/ci-files/-/raw/master/complete-python-libs.yml
variables:
SUPPORT_PYTHON_2: "True"
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/odoo_launcher" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/odoo_launcher.egg-info" />
</content>
<orderEntry type="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
import os
import sys
from . import api, mapper, config_section # noqa
from .odoo_config_maker import OdooConfig # noqa
from . import laucher # noqa
import logging
_logger = logging.getLogger(__name__)
def main():
env_vars = dict(os.environ)
launcher = laucher.Launcher(
args=sys.argv[:1],
odoo_path=env_vars.get("ODOO_PATH"),
odoo_rc=env_vars.get("ODOO_RC"),
server_path=env_vars.get("ODOO_SERVER_PATH"),
)
_logger.info("create config")
if env_vars.get("UPDATE") or env_vars.get("INSTALL"):
return_code = launcher.launch_config_file(env_vars).wait()
if return_code:
sys.exit(return_code)
_logger.info("Update or init detected")
with launcher.launch_maintenance_server() as maintenance_server_proc:
return_code = launcher.launch_update(env_vars).wait()
maintenance_server_proc.kill()
if return_code:
sys.exit(return_code)
_logger.info("#############################################")
_logger.info("Run Odoo")
sys.exit(launcher.launch(env_vars).wait())
import abc
from typing import Any, Dict, Union
class Dictable(abc.ABC):
def to_dict(self):
# type: () -> Dict[str, Any]
raise NotImplementedError()
@staticmethod
def clean_config_dict(values):
# type: (Union[Dict[str, Any], Dictable]) -> Dict[str, str]
new_values = {}
if isinstance(values, Dictable):
values = values.to_dict()
for key, value in values.items():
if isinstance(value, dict):
value = Dictable.clean_config_dict(value)
elif isinstance(value, (list, tuple, set)):
value = ",".join([str(x) for x in value]) or ""
if value and value is not None and not isinstance(value, dict):
new_values[key] = str(value)
return new_values
@staticmethod
def clean_none_env_vars(dict_value):
# type: (Union[Dict[str, Any], Dictable]) -> Dict[str, Any]
result = {}
if isinstance(dict_value, Dictable):
dict_value = dict_value.to_dict()
for key, value in dict_value.items():
if value is not None:
result[key] = value
return result
class ConfigConvert(abc.ABC):
def is_true(self, any):
# type: (Union[str, bool, int, None]) -> bool
if not isinstance(any, (str, bool, int)):
return False
return bool(any) and (str(any).isdigit() and bool(int(any))) or (str(any).capitalize() == str(True)) or False
def to_int(self, any):
# type: (Union[str, bool, int, None]) -> int
if not any or not isinstance(any, (str, bool, int)):
return 0
if isinstance(any, str):
return any.isdigit() and int(any) or "." in any and int(float(any)) or 0
return int(any)
class EnvMapper(ConfigConvert):
def map_vars(self, env_vars):
# type: (Dict[str, str]) -> Dict[str, str]
raise NotImplementedError()
class OdooConfigABC(ConfigConvert, abc.ABC):
def __init__(self, main_instance=True):
super(OdooConfigABC, self).__init__()
self.main_instance = main_instance
@property
def odoo_version(self):
raise NotImplementedError
class OdooConfigSection(ConfigConvert, Dictable, abc.ABC):
def __init__(self, odoo_config_maker, env_vars):
# type: (OdooConfigABC, Dict[str, Union[str, bool, int, None]]) -> None
self.config_maker = odoo_config_maker
self.enable = True
def to_dict(self):
# type: () -> Dict[str, Any]
if not self.enable:
return {}
return self.get_info()
import enum
from typing import Dict, Union
from addons_installer import addons_installer
from api import OdooConfigSection, OdooConfigABC
class WorkersOdooConfigSection(OdooConfigSection):
class UseCase(enum.Enum):
CLASSIC = "CLASSIC"
ONLY_HTTP = "ONLY_HTTP"
ONLY_JOB_RUNNER = "ONLY_JOB_RUNNER"
ONLY_JOB_WORKER = "ONLY_JOB_WORKER"
ONLY_CRON = "ONLY_CRON"
def __init__(self, odoo_config_maker, env_vars):
# type: (OdooConfigABC, Dict[str, Union[str, bool, int, None]]) -> None
super(WorkersOdooConfigSection, self).__init__(odoo_config_maker, env_vars)
self.http = self.to_int(env_vars.get("WORKER_HTTP", 1))
self.cron = self.to_int(env_vars.get("WORKER_CRON", 2))
self.job = self.to_int(env_vars.get("WORKER_JOB", 0))
self.split_use_case = self.is_true(env_vars.get("SPLIT_ODOO_USE_CASE", str(False)))
use_case_env = env_vars.get("ODOO_USE_CASE")
if not use_case_env or use_case_env not in (list(WorkersOdooConfigSection.UseCase)):
self.odoo_use_case = WorkersOdooConfigSection.UseCase.CLASSIC
else:
self.odoo_use_case = WorkersOdooConfigSection.UseCase[use_case_env]
if not odoo_config_maker.main_instance and self.odoo_use_case != WorkersOdooConfigSection.UseCase.ONLY_CRON:
self.cron = 0
@property
def total(self):
return self.http + self.cron + self.job
@property
def worker(self):
if self.odoo_use_case == WorkersOdooConfigSection.UseCase.ONLY_JOB_WORKER:
return self.job
if self.odoo_use_case == WorkersOdooConfigSection.UseCase.ONLY_JOB_RUNNER:
return 0
if self.odoo_use_case == WorkersOdooConfigSection.UseCase.ONLY_HTTP:
return self.http
if self.odoo_use_case == WorkersOdooConfigSection.UseCase.ONLY_CRON:
return 0
return self.http + self.job
def to_dict(self):
if not self.enable:
return {}
return {
"--workers": self.worker,
"--max-cron-threads": self.cron,
}
class LimitOdooConfigSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.limit_request = int(env_vars.get("LIMIT_REQUEST", 0)) or None
self.limit_time_cpu = int(env_vars.get("LIMIT_TIME_CPU", 0)) or None
self.limit_time_real = int(env_vars.get("LIMIT_TIME_REAL", 0)) or None
self.osv_memory_count_limit = int(env_vars.get("OSV_MEMORY_COUNT_LIMIT", 0)) or None
self.osv_memory_age_limit = int(env_vars.get("OSV_MEMORY_AGE_LIMIT", 0)) or None
self.limit_memory_hard = int(env_vars.get("LIMIT_MEMORY_HARD", 0)) or None
self.limit_memory_soft = int(env_vars.get("LIMIT_MEMORY_SOFT", 0)) or None
if not self.limit_memory_hard or not self.limit_memory_soft:
global_limit_memory_hard = int(env_vars.get("GLOBAL_LIMIT_MEMORY_HARD", 0))
global_limit_memory_soft = int(env_vars.get("GLOBAL_LIMIT_MEMORY_SOFT", 0))
total = WorkersOdooConfigSection(odoo_config_maker, env_vars).total or 1
if not self.limit_memory_soft and global_limit_memory_soft:
self.limit_memory_soft = global_limit_memory_soft // total
if not self.limit_memory_hard and global_limit_memory_hard:
self.limit_memory_hard = global_limit_memory_hard // total
def to_dict(self):
return {
"--limit-request": self.limit_request,
"--limit-time-cpu": self.limit_time_cpu,
"--limit-time-real": self.limit_time_real,
"--limit-memory-hard": self.limit_memory_hard,
"--limit-memory-soft": self.limit_memory_soft,
"--osv-memory-count-limit": self.osv_memory_count_limit,
"--osv-memory-age-limit": self.osv_memory_age_limit,
}
class DatabaseOdooConfigSection(OdooConfigSection):
class MaxConnMode(enum.Enum):
AUTO = "AUTO"
FIXED = "FIXED"
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.name = env_vars.get("DB_NAME")
self.host = env_vars.get("DB_HOST")
self.port = self.to_int(env_vars.get("DB_PORT")) or None
self.user = env_vars.get("DB_USER")
self.password = env_vars.get("DB_PASSWORD")
self.max_conn = self.to_int(env_vars.get("DB_MAX_CONN"))
self.filter = env_vars.get("DB_FILTER")
self.log_enable = env_vars.get("LOG_DB")
self.log_level = env_vars.get("LOG_DB_LEVEL")
self.show = self.is_true(env_vars.get("LIST_DB"))
mode_env = env_vars.get("DB_MAXCONN_MODE")
if not mode_env or mode_env not in (list(DatabaseOdooConfigSection.MaxConnMode)):
mode = DatabaseOdooConfigSection.MaxConnMode.AUTO
else:
mode = DatabaseOdooConfigSection.MaxConnMode[mode_env]
nb_workers = WorkersOdooConfigSection(odoo_config_maker, env_vars).total or 1
min_conn = nb_workers + int(nb_workers // 2)
if mode == DatabaseOdooConfigSection.MaxConnMode.FIXED and not self.max_conn:
# Switch to auto if no max_conn in env_vars but in mode FIXED
mode = DatabaseOdooConfigSection.MaxConnMode.AUTO
if mode == DatabaseOdooConfigSection.MaxConnMode.AUTO and not self.max_conn:
self.max_conn = min_conn
# We add some security because sometime worker open 2 or more connecions (Ex :bus.bus)
self.max_conn = max(self.max_conn, min_conn, 2)
if self.filter and not self.show:
self.show = True
if self.name and not self.show:
self.filter = self.name
if self.name and self.show and not self.filter:
self.filter = self.name + ".*"
def to_dict(self):
if not self.enable:
return {}
return {
"--db_host": self.host,
"--db_port": self.port,
"--db_user": self.user,
"--db_password": self.password,
"--database": self.name,
"--no-database-list": not self.show,
"--db_maxconn": self.max_conn,
"--db-filter": self.filter,
}
class HttpOdooConfigSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.enable = self.is_true(env_vars.get("HTTP_ENABLE", "True"))
self.interface = None
self.port = None
self.longpolling_port = None
if self.enable:
self.interface = env_vars.get("HTTP_INTERFACE") or "0.0.0.0"
self.port = self.to_int(env_vars.get("HTTP_PORT")) or 8080
self.longpolling_port = self.to_int(env_vars.get("LONGPOLLING_PORT")) or 4040
def to_dict(self):
key_http = "http" if self.config_maker.odoo_version > 10 else "xmlrpc"
if not self.enable:
return {
"--no-%s" % key_http: not self.enable,
}
return {
"--%s-interface" % key_http: self.interface,
"--%s-port" % key_http: self.port,
"--longpolling-port": self.longpolling_port,
}
class ServerWideModuleConfigSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
str_server_wide_modules = env_vars.get("SERVER_WIDE_MODULES")
self.server_wide_modules = str_server_wide_modules and str_server_wide_modules.split(",") or ["base", "web"]
self.queue_job_module_name = None
if env_vars.get("QUEUE_JOB_ENABLE"):
self.queue_job_module_name = "queue_job"
if odoo_config_maker.odoo_version < 10:
self.queue_job_module_name = "connector"
self.server_wide_modules.append(self.queue_job_module_name)
if env_vars.get("S3_FILESTORE_ENABLE"):
self.server_wide_modules.append("odoo_filestore_s3")
if env_vars.get("REDIS_SESSION_ENABLE"):
self.server_wide_modules.append("odoo_session_redis")
def remove_queue_job(self):
if self.queue_job_module_name:
self.server_wide_modules.remove(self.queue_job_module_name)
def to_dict(self):
return {
"--load": self.server_wide_modules,
}
class OtherSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.unaccent = self.is_true(env_vars.get("UNACCENT", True))
self.test_enable = self.is_true(env_vars.get("TEST_ENABLE"))
self.without_demo = self.is_true(env_vars.get("WITHOUT_DEMO"))
def to_dict(self):
if not self.enable:
return {"--unaccent": self.unaccent}
return {
"--unaccent": self.unaccent,
"--test-enable": self.test_enable,
"--without-demo": self.without_demo,
}
class LoggerSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.logfile = env_vars.get("LOGFILE")
self.log_handler = env_vars.get("LOG_HANDLER")
self.log_request = self.is_true(env_vars.get("LOG_REQUEST"))
self.log_response = self.is_true(env_vars.get("LOG_RESPONSE"))
self.log_web = self.is_true(env_vars.get("LOG_WEB"))
self.log_sql = self.is_true(env_vars.get("LOG_SQL"))
self.log_db = self.is_true(env_vars.get("LOG_DB"))
self.log_db_level = env_vars.get("LOG_DB_LEVEL")
self.log_level = env_vars.get("LOG_LEVEL")
def to_dict(self):
if not self.enable:
return {}
return {
"--logfile": self.logfile,
"--log-handler": self.log_handler,
"--log-request": self.log_request,
"--log-response": self.log_response,
"--log-web": self.log_web,
"--log-sql": self.log_sql,
"--log-db": self.log_db,
"--log-db-level": self.log_db_level,
"--log-level": self.log_level,
}
class UpdateInstallSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
self.update = [u.strip() for u in env_vars.get("UPDATE", "").split(",")]
self.install = [i.strip() for i in env_vars.get("INSTALL", "").split(",")]
self.stop_after_init = self.is_true(env_vars.get("STOP_AFTER_INIT"))
self.save_config_file = self.is_true(env_vars.get("SAVE_CONFIG_FILE"))
self.force_stop_after_init = False
self.force_save_config_file = False
def to_dict(self):
default_res = {}
if self.force_save_config_file:
default_res["--save"] = self.force_save_config_file
if self.force_stop_after_init:
default_res["--stop-after-init"] = self.force_stop_after_init
if not self.enable:
return default_res
return dict({
"--update": ",".join(self.update),
"--install": ",".join(self.install),
"--stop-after-init": self.stop_after_init,
"--save": self.save_config_file,
}, **default_res)
class AddonsPathConfigSection(OdooConfigSection):
def __init__(self, odoo_config_maker, env_vars):
super().__init__(odoo_config_maker, env_vars)
registry = addons_installer.AddonsRegistry()
result = registry.parse_env(env_vars=env_vars)
self.addons_path = [r.addons_path for r in result]
def to_dict(self):
if not self.enable:
return {}
return {
"--addons-path": self.addons_path,
}
import argparse
import configparser
import logging
import os
import subprocess
import sys
import uuid
from typing import List, Optional, Dict
from odoo_launcher import OdooConfig
_logger = logging.getLogger("launch")
_logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
_logger.addHandler(handler)
class Launcher(object):
def __init__(self, args, odoo_path=None, odoo_rc=None, server_path=None):
# type: (List[str], Optional[str], Optional[str], Optional[str]) -> Launcher
parser = self.get_parser()
ns, other = parser.parse_known_args(args=args)
odoo_path = ns.odoo_path or odoo_path
assert odoo_path, "No Odoo path is provided"
self.odoo_path = os.path.abspath(os.path.expanduser(odoo_path))
odoo_rc = ns.odoo_rc or odoo_rc
assert "No Odoo config file path is provided"
self.odoo_rc = os.path.abspath(odoo_rc)
ndp_server_path = ns.server_path or server_path
assert "Server path is provided"
self.ndp_server_path = os.path.abspath(os.path.expanduser(ndp_server_path))
def get_parser(self):
# type: () -> argparse.ArgumentParser
parser = argparse.ArgumentParser()
parser.add_argument("--odoo-path", dest="odoo_path", help="Path of odoo-bin")
parser.add_argument("--odoo-rc", "-c", dest="odoo_rc", help="Path of the base config file")
parser.add_argument("--ndp-server-path", dest="server_path", help="Server Path")
return parser
def create_config_file_args(self, env_vars):
# type: (Dict[str, str]) -> OdooConfig
config = OdooConfig(env_vars, self.odoo_rc)
config.http_config.enable = False