mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 06:12:04 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -82,6 +82,12 @@ def initialize(cr: Cursor) -> None:
|
|||
(module_id, d, d in (info['auto_install'] or ()))
|
||||
)
|
||||
|
||||
from odoo.tools import config # noqa: PLC0415
|
||||
if config.get('skip_auto_install'):
|
||||
# even if skip_auto_install is enabled we still want to have base
|
||||
cr.execute("""UPDATE ir_module_module SET state='to install' WHERE name = 'base'""")
|
||||
return
|
||||
|
||||
# Install recursively all auto-installing modules
|
||||
while True:
|
||||
# this selects all the auto_install modules whose auto_install_required
|
||||
|
|
@ -168,10 +174,9 @@ def has_unaccent(cr: BaseCursor) -> FunctionStatus:
|
|||
cr.execute("""
|
||||
SELECT p.provolatile
|
||||
FROM pg_proc p
|
||||
LEFT JOIN pg_catalog.pg_namespace ns ON p.pronamespace = ns.oid
|
||||
WHERE p.proname = 'unaccent'
|
||||
AND p.pronamespace = current_schema::regnamespace
|
||||
AND p.pronargs = 1
|
||||
AND ns.nspname = 'public'
|
||||
""")
|
||||
result = cr.fetchone()
|
||||
if not result:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import odoo.sql_db
|
|||
import odoo.tools.sql
|
||||
import odoo.tools.translate
|
||||
from odoo import api, tools
|
||||
from odoo.tools import OrderedSet
|
||||
from odoo.tools.convert import convert_file, IdRef, ConvertMode as LoadMode
|
||||
|
||||
from . import db as modules_db
|
||||
|
|
@ -69,7 +70,7 @@ def load_demo(env: Environment, package: ModuleNode, idref: IdRef, mode: LoadMod
|
|||
if package.manifest.get('demo') or package.manifest.get('demo_xml'):
|
||||
_logger.info("Module %s: loading demo", package.name)
|
||||
with env.cr.savepoint(flush=False):
|
||||
load_data(env(su=True), idref, mode, kind='demo', package=package)
|
||||
load_data(env(su=True, context=dict(env.context, install_demo=True)), idref, mode, kind='demo', package=package)
|
||||
return True
|
||||
except Exception: # noqa: BLE001
|
||||
# If we could not install demo data for this module
|
||||
|
|
@ -89,6 +90,7 @@ def force_demo(env: Environment) -> None:
|
|||
"""
|
||||
Forces the `demo` flag on all modules, and installs demo data for all installed modules.
|
||||
"""
|
||||
assert env.registry.ready
|
||||
env.cr.execute('UPDATE ir_module_module SET demo=True')
|
||||
env.cr.execute(
|
||||
"SELECT name FROM ir_module_module WHERE state IN ('installed', 'to upgrade', 'to remove')"
|
||||
|
|
@ -102,13 +104,20 @@ def force_demo(env: Environment) -> None:
|
|||
|
||||
env['ir.module.module'].invalidate_model(['demo'])
|
||||
|
||||
# If demo data triggered module state changes (to install/upgrade/remove),
|
||||
# commit and rebuild registry to process button_install/upgrade calls.
|
||||
if env['ir.module.module'].search_count([('state', 'in', ('to install', 'to upgrade', 'to remove'))], limit=1):
|
||||
env.cr.commit()
|
||||
Registry.new(env.cr.dbname, update_module=True)
|
||||
env.transaction.reset()
|
||||
|
||||
|
||||
def load_module_graph(
|
||||
env: Environment,
|
||||
graph: ModuleGraph,
|
||||
update_module: bool = False,
|
||||
report: OdooTestResult | None = None,
|
||||
models_to_check: set[str] | None = None,
|
||||
models_to_check: OrderedSet[str] | None = None,
|
||||
install_demo: bool = True,
|
||||
) -> None:
|
||||
""" Load, upgrade and install not loaded module nodes in the ``graph`` for ``env.registry``
|
||||
|
|
@ -121,7 +130,7 @@ def load_module_graph(
|
|||
:param install_demo: whether to attempt installing demo data for newly installed modules
|
||||
"""
|
||||
if models_to_check is None:
|
||||
models_to_check = set()
|
||||
models_to_check = OrderedSet()
|
||||
|
||||
registry = env.registry
|
||||
assert isinstance(env.cr, odoo.sql_db.Cursor), "Need for a real Cursor to load modules"
|
||||
|
|
@ -179,8 +188,8 @@ def load_module_graph(
|
|||
|
||||
if update_operation:
|
||||
model_names = registry.descendants(model_names, '_inherit', '_inherits')
|
||||
models_updated |= set(model_names)
|
||||
models_to_check -= set(model_names)
|
||||
models_updated |= model_names
|
||||
models_to_check -= model_names
|
||||
registry._setup_models__(env.cr, []) # incremental setup
|
||||
registry.init_models(env.cr, model_names, {'module': package.name}, update_operation == 'install')
|
||||
elif update_module and package.state != 'to remove':
|
||||
|
|
@ -190,7 +199,11 @@ def load_module_graph(
|
|||
# e.g. adding required=True to an existing field, but the schema has not been
|
||||
# updated by this module because it's not marked as 'to upgrade/to install'.
|
||||
model_names = registry.descendants(model_names, '_inherit', '_inherits')
|
||||
models_to_check |= set(model_names) & models_updated
|
||||
models_to_check |= model_names & models_updated
|
||||
elif update_module and package.state == 'to remove':
|
||||
# For all model extented (with _inherit) in the package to uninstall, we need to
|
||||
# update ir.model / ir.model.fields along side not-null SQL constrains.
|
||||
models_to_check |= model_names
|
||||
|
||||
if update_operation:
|
||||
# Can't put this line out of the loop: ir.module.module will be
|
||||
|
|
@ -332,6 +345,7 @@ def load_modules(
|
|||
install_modules: Collection[str] = (),
|
||||
reinit_modules: Collection[str] = (),
|
||||
new_db_demo: bool = False,
|
||||
models_to_check: OrderedSet[str] | None = None,
|
||||
) -> None:
|
||||
""" Load the modules for a registry object that has just been created. This
|
||||
function is part of Registry.new() and should not be used anywhere else.
|
||||
|
|
@ -343,9 +357,10 @@ def load_modules(
|
|||
:param reinit_modules: A collection of module names to reinitialize.
|
||||
:param new_db_demo: Whether to install demo data for new database. Defaults to ``False``
|
||||
"""
|
||||
initialize_sys_path()
|
||||
if models_to_check is None:
|
||||
models_to_check = OrderedSet()
|
||||
|
||||
models_to_check: set[str] = set()
|
||||
initialize_sys_path()
|
||||
|
||||
with registry.cursor() as cr:
|
||||
# prevent endless wait for locks on schema changes (during online
|
||||
|
|
@ -536,11 +551,8 @@ def load_modules(
|
|||
cr.commit()
|
||||
_logger.info('Reloading registry once more after uninstalling modules')
|
||||
registry = Registry.new(
|
||||
cr.dbname, update_module=update_module
|
||||
cr.dbname, update_module=update_module, models_to_check=models_to_check,
|
||||
)
|
||||
cr.reset()
|
||||
registry.check_tables_exist(cr)
|
||||
cr.commit()
|
||||
return
|
||||
|
||||
# STEP 5.5: Verify extended fields on every model
|
||||
|
|
@ -555,7 +567,9 @@ def load_modules(
|
|||
cr.execute("""SELECT DISTINCT model FROM ir_model_fields WHERE state = 'manual'""")
|
||||
models_to_check.update(model_name for model_name, in cr.fetchall() if model_name in registry)
|
||||
if models_to_check:
|
||||
registry.init_models(cr, list(models_to_check), {'models_to_check': True, 'update_custom_fields': True})
|
||||
# Doesn't check models that didn't exist anymore, it might happen during uninstallation
|
||||
models_to_check = [model for model in models_to_check if model in registry]
|
||||
registry.init_models(cr, models_to_check, {'models_to_check': True, 'update_custom_fields': True})
|
||||
|
||||
# STEP 6: verify custom views on every model
|
||||
if update_module:
|
||||
|
|
@ -583,6 +597,16 @@ def load_modules(
|
|||
# STEP 10: check that we can trust nullable columns
|
||||
registry.check_null_constraints(cr)
|
||||
|
||||
if update_module:
|
||||
cr.execute(
|
||||
"""
|
||||
INSERT INTO ir_config_parameter(key, value)
|
||||
SELECT 'base.partially_updated_database', '1'
|
||||
WHERE EXISTS(SELECT FROM ir_module_module WHERE state IN ('to upgrade', 'to install', 'to remove'))
|
||||
ON CONFLICT DO NOTHING
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def reset_modules_state(db_name: str) -> None:
|
||||
"""
|
||||
|
|
@ -596,8 +620,7 @@ def reset_modules_state(db_name: str) -> None:
|
|||
# of time
|
||||
db = odoo.sql_db.db_connect(db_name)
|
||||
with db.cursor() as cr:
|
||||
cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name='ir_module_module'")
|
||||
if not cr.fetchall():
|
||||
if not odoo.tools.sql.table_exists(cr, 'ir_module_module'):
|
||||
_logger.info('skipping reset_modules_state, ir_module_module table does not exists')
|
||||
return
|
||||
cr.execute(
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class MigrationManager:
|
|||
|
||||
def _get_migration_versions(pkg, stage: str) -> list[str]:
|
||||
versions = sorted({
|
||||
ver
|
||||
ver: None
|
||||
for lv in self.migrations[pkg.name].values()
|
||||
for ver, lf in lv.items()
|
||||
if lf
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class Manifest(Mapping[str, typing.Any]):
|
|||
_, self.name = os.path.split(path)
|
||||
if not MODULE_NAME_RE.match(self.name):
|
||||
raise FileNotFoundError(f"Invalid module name: {self.name}")
|
||||
self._manifest_content = manifest_content
|
||||
self.__manifest_content = manifest_content
|
||||
|
||||
@property
|
||||
def addons_path(self) -> str:
|
||||
|
|
@ -191,14 +191,14 @@ class Manifest(Mapping[str, typing.Any]):
|
|||
return parent_path
|
||||
|
||||
@functools.cached_property
|
||||
def manifest_cached(self) -> dict:
|
||||
def __manifest_cached(self) -> dict:
|
||||
"""Parsed and validated manifest data from the file."""
|
||||
return _load_manifest(self.name, self._manifest_content)
|
||||
return _load_manifest(self.name, self.__manifest_content)
|
||||
|
||||
@functools.cached_property
|
||||
def description(self):
|
||||
"""The description of the module defaulting to the README file."""
|
||||
if (desc := self.manifest_cached.get('description')):
|
||||
if (desc := self.__manifest_cached.get('description')):
|
||||
return desc
|
||||
for file_name in README:
|
||||
try:
|
||||
|
|
@ -211,7 +211,7 @@ class Manifest(Mapping[str, typing.Any]):
|
|||
@functools.cached_property
|
||||
def version(self):
|
||||
try:
|
||||
return self.manifest_cached['version']
|
||||
return self.__manifest_cached['version']
|
||||
except Exception: # noqa: BLE001
|
||||
return adapt_version('1.0')
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ class Manifest(Mapping[str, typing.Any]):
|
|||
@functools.cached_property
|
||||
def static_path(self) -> str | None:
|
||||
static_path = opj(self.path, 'static')
|
||||
manifest = self.manifest_cached
|
||||
manifest = self.__manifest_cached
|
||||
if (manifest['installable'] or manifest['assets']) and os.path.isdir(static_path):
|
||||
return static_path
|
||||
return None
|
||||
|
|
@ -230,10 +230,13 @@ class Manifest(Mapping[str, typing.Any]):
|
|||
def __getitem__(self, key: str):
|
||||
if key in ('description', 'icon', 'addons_path', 'version', 'static_path'):
|
||||
return getattr(self, key)
|
||||
return copy.deepcopy(self.manifest_cached[key])
|
||||
return copy.deepcopy(self.__manifest_cached[key])
|
||||
|
||||
def raw_value(self, key):
|
||||
return copy.deepcopy(self.__manifest_cached.get(key))
|
||||
|
||||
def __iter__(self):
|
||||
manifest = self.manifest_cached
|
||||
manifest = self.__manifest_cached
|
||||
yield from manifest
|
||||
for key in ('description', 'icon', 'addons_path', 'version', 'static_path'):
|
||||
if key not in manifest:
|
||||
|
|
@ -377,9 +380,15 @@ def get_module_icon(module: str) -> str:
|
|||
""" Get the path to the module's icon. Invalid module names are accepted. """
|
||||
manifest = Manifest.for_addon(module, display_warning=False)
|
||||
if manifest and 'icon' in manifest.__dict__:
|
||||
# we have a value in the cached property
|
||||
return manifest.icon
|
||||
try:
|
||||
fpath = ''
|
||||
if manifest:
|
||||
fpath = manifest.raw_value('icon') or ''
|
||||
fpath = fpath.lstrip('/')
|
||||
if not fpath:
|
||||
fpath = f"{module}/static/description/icon.png"
|
||||
try:
|
||||
tools.file_path(fpath)
|
||||
return "/" + fpath
|
||||
except FileNotFoundError:
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class ModuleNode:
|
|||
# acceptable in this context since we don't modify it
|
||||
manifest = Manifest.for_addon(name, display_warning=False)
|
||||
if manifest is not None:
|
||||
manifest.manifest_cached # parse the manifest now
|
||||
manifest.raw_value('') # parse the manifest now
|
||||
self.manifest: Mapping = manifest or {}
|
||||
|
||||
# ir_module_module data # column_name
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue