[FIX] module.loading: ensure installed modules are all loaded before installing new ones
After the recent change to make module install atomically (code *and* data), we ran into issues when installing a new module indirectly triggers code of a not-yet-loaded-but-installed module, via its data that is already in the database (e.g. worflows or reports modified by this module within another module, that now refer to its code). To avoid this, we now make sure that we only install new modules on top of a consistent system (code *and* data), by loading all installed or 'to upgrade' modules *before* starting to install new ones. lp bug: https://launchpad.net/bugs/809168 fixed bzr revid: odo@openerp.com-20110712133343-unf610k23fa6d3pk
This commit is contained in:
parent
65190b7f8c
commit
8874fb058f
|
@ -152,6 +152,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
|||
status = {}
|
||||
|
||||
processed_modules = []
|
||||
loaded_modules = []
|
||||
statusi = 0
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
migrations = openerp.modules.migration.MigrationManager(cr, graph)
|
||||
|
@ -169,6 +170,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
|||
migrations.migrate_module(package, 'pre')
|
||||
register_module_classes(package.name)
|
||||
models = pool.instanciate(package.name, cr)
|
||||
loaded_modules.append(package.name)
|
||||
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
|
||||
init_module_models(cr, package.name, models)
|
||||
|
||||
|
@ -226,7 +228,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
|||
|
||||
cr.commit()
|
||||
|
||||
return processed_modules
|
||||
return loaded_modules, processed_modules
|
||||
|
||||
def _check_module_names(cr, module_names):
|
||||
mod_names = set(module_names)
|
||||
|
@ -242,11 +244,26 @@ def _check_module_names(cr, module_names):
|
|||
incorrect_names = mod_names.difference([x['name'] for x in cr.dictfetchall()])
|
||||
logging.getLogger('init').warning('invalid module names, ignored: %s', ", ".join(incorrect_names))
|
||||
|
||||
def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_modules):
|
||||
"""Loads modules marked with ``states``, adding them to ``graph`` and
|
||||
``loaded_modules`` and returns a list of installed/upgraded modules."""
|
||||
processed_modules = []
|
||||
while True:
|
||||
cr.execute("SELECT name from ir_module_module WHERE state IN %s" ,(tuple(states),))
|
||||
module_list = [name for (name,) in cr.fetchall() if name not in graph]
|
||||
new_modules_in_graph = graph.add_modules(cr, module_list, force)
|
||||
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))
|
||||
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules)
|
||||
processed_modules.extend(processed)
|
||||
loaded_modules.extend(loaded)
|
||||
if not processed: break
|
||||
return processed_modules
|
||||
|
||||
|
||||
def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
# TODO status['progress'] reporting is broken: used twice (and reset each
|
||||
# time to zero) in load_module_graph, not fine-grained enough.
|
||||
# It should be a method exposed by the pool.
|
||||
|
||||
initialize_sys_path()
|
||||
|
||||
open_openerp_namespace()
|
||||
|
@ -268,10 +285,9 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
# This is a brand new pool, just created in pooler.get_db_and_pool()
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
||||
processed_modules = []
|
||||
processed_modules = [] # for cleanup step after install
|
||||
loaded_modules = [] # to avoid double loading
|
||||
report = tools.assertion_report()
|
||||
# NOTE: Try to also load the modules that have been marked as uninstallable previously...
|
||||
STATES_TO_LOAD = ['installed', 'to upgrade', 'uninstallable']
|
||||
if 'base' in tools.config['update'] or 'all' in tools.config['update']:
|
||||
cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed'))
|
||||
|
||||
|
@ -281,7 +297,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
if not graph:
|
||||
logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
|
||||
raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
|
||||
processed_modules.extend(load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report))
|
||||
loaded, processed = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report)
|
||||
processed_modules.extend(processed)
|
||||
|
||||
if tools.config['load_language']:
|
||||
for lang in tools.config['load_language'].split(','):
|
||||
|
@ -310,28 +327,19 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
|
||||
cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))
|
||||
|
||||
STATES_TO_LOAD += ['to install']
|
||||
|
||||
|
||||
# STEP 3: Load marked modules (skipping base which was done in STEP 1)
|
||||
loop_guardrail = 0
|
||||
while True:
|
||||
loop_guardrail += 1
|
||||
if loop_guardrail > 100:
|
||||
raise ValueError('Possible recursive module tree detected, aborting.')
|
||||
cr.execute("SELECT name from ir_module_module WHERE state IN %s" ,(tuple(STATES_TO_LOAD),))
|
||||
|
||||
module_list = [name for (name,) in cr.fetchall() if name not in graph]
|
||||
if not module_list:
|
||||
break
|
||||
|
||||
new_modules_in_graph = graph.add_modules(cr, module_list, force)
|
||||
if new_modules_in_graph == 0:
|
||||
# nothing to load
|
||||
break
|
||||
|
||||
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))
|
||||
processed_modules.extend(load_module_graph(cr, graph, status, report=report, skip_modules=processed_modules))
|
||||
# IMPORTANT: this is done in two parts, first loading all installed or
|
||||
# partially installed modules (i.e. installed/to upgrade), to
|
||||
# offer a consistent system to the second part: installing
|
||||
# newly selected modules.
|
||||
states_to_load = ['installed', 'to upgrade']
|
||||
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
|
||||
processed_modules.extend(processed)
|
||||
if update_module:
|
||||
states_to_load = ['to install']
|
||||
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
|
||||
processed_modules.extend(processed)
|
||||
|
||||
# load custom models
|
||||
cr.execute('select model from ir_model where state=%s', ('manual',))
|
||||
|
|
Loading…
Reference in New Issue