From 8b878de82d5d31fb1bcb862a2187a40ed1a24b18 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 11 May 2011 12:34:55 +0200 Subject: [PATCH] [REF] modules.__init__: - added some comments - the "updating modules list" log appears only when actually updating the list - similar code to read the module descriptor file is combined - default values for some descriptor entries are given only once - in particular, the default version is always 0, instead of 0 when reading a descriptor for migration and 1.0 when writing its value in database. bzr revid: vmt@openerp.com-20110511103455-lqezcrjf2996j7mc --- openerp/modules/__init__.py | 92 +++++++++++++++++++++---------------- openerp/tools/misc.py | 1 + tools/module_graph.py | 1 + 3 files changed, 54 insertions(+), 40 deletions(-) diff --git a/openerp/modules/__init__.py b/openerp/modules/__init__.py index aee0ceebf13..44d19e48342 100644 --- a/openerp/modules/__init__.py +++ b/openerp/modules/__init__.py @@ -352,21 +352,39 @@ def load_information_from_description_file(module): :param module: The name of the module (sale, purchase, ...) """ - for filename in ['__openerp__.py', '__terp__.py']: - description_file = get_module_resource(module, filename) - if description_file : - desc_f = tools.file_open(description_file) + terp_file = get_module_resource(module, '__openerp__.py') + if not terp_file: + terp_file = get_module_resource(module, '__terp__.py') + mod_path = get_module_path(module) + if terp_file: + info = {} + if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path+'.zip'): + terp_f = tools.file_open(terp_file) try: - return eval(desc_f.read()) + info = eval(terp_f.read()) + except Exception: + logger.notifyChannel('modules', netsvc.LOG_ERROR, + 'module %s: exception while evaluating file %s' % + (module, terp_file)) + raise finally: - desc_f.close() + terp_f.close() + # TODO the version should probably be mandatory + info.setdefault('version', '0') + info.setdefault('depends', []) + info.setdefault('installable', True) + for kind in ['data', 'demo', 'test', + 'init_xml', 'update_xml', 'demo_xml']: + info.setdefault(kind, []) + return info #TODO: refactor the logger in this file to follow the logging guidelines # for 6.0 - logging.getLogger('addons').debug('The module %s does not contain a description file:'\ - '__openerp__.py or __terp__.py (deprecated)', module) + logging.getLogger('modules').debug('module %s: no descriptor file' + ' found: __openerp__.py or __terp__.py (deprecated)', module) return {} + def get_modules_with_version(): modules = get_modules() res = {} @@ -389,33 +407,19 @@ def upgrade_graph(graph, cr, module_list, force=None): packages = [] len_graph = len(graph) for module in module_list: - mod_path = get_module_path(module) - terp_file = get_module_resource(module, '__openerp__.py') - if not terp_file: - terp_file = get_module_resource(module, '__terp__.py') - if not mod_path or not terp_file: - logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: not found, skipped' % (module)) - continue + # This will raise an exception if no/unreadable descriptor file. + info = load_information_from_description_file(module) + if info['installable']: + packages.append((module, info)) # TODO directly a dict, like in get_modules_with_version + else: + logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: not installable, skipped' % (module)) - if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path+'.zip'): - terp_f = tools.file_open(terp_file) - try: - info = eval(terp_f.read()) - except Exception: - logger.notifyChannel('init', netsvc.LOG_ERROR, 'module %s: eval file %s' % (module, terp_file)) - raise - finally: - terp_f.close() - if info.get('installable', True): - packages.append((module, info.get('depends', []), info)) - else: - logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: not installable, skipped' % (module)) - - dependencies = dict([(p, deps) for p, deps, data in packages]) - current, later = set([p for p, dep, data in packages]), set() + dependencies = dict([(p, info['depends']) for p, info in packages]) + current, later = set([p for p, info in packages]), set() while packages and current > later: - package, deps, data = packages[0] + package, info = packages[0] + deps = info['depends'] # if all dependencies of 'package' are already in the graph, add 'package' in the graph if reduce(lambda x, y: x and y in graph, deps, True): @@ -426,13 +430,13 @@ def upgrade_graph(graph, cr, module_list, force=None): current.remove(package) graph.addNode(package, deps) node = Node(package, graph) - node.data = data + node.data = info for kind in ('init', 'demo', 'update'): if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force: setattr(node, kind, True) else: later.add(package) - packages.append((package, deps, data)) + packages.append((package, info)) packages.pop(0) graph.update_from_db(cr) @@ -624,7 +628,7 @@ class MigrationManager(object): from openerp.tools.parse_version import parse_version parsed_installed_version = parse_version(pkg.installed_version or '') - current_version = parse_version(convert_version(pkg.data.get('version', '0'))) + current_version = parse_version(convert_version(pkg.data['version'])) versions = _get_migration_versions(pkg) @@ -722,7 +726,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= init mode. """ - for filename in package.data.get(kind, []): + for filename in package.data[kind]: log = logging.getLogger('init') log.info("module %s: loading %s", module_name, filename) _, ext = os.path.splitext(filename) @@ -754,6 +758,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations = MigrationManager(cr, graph) logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph)) + # register, instanciate and initialize models for each modules for package in graph: if skip_modules and package.name in skip_modules: continue @@ -765,6 +770,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= init_module_models(cr, package.name, models) cr.commit() + # load data for each modules modobj = pool.get('ir.module.module') for package in graph: status['progress'] = (float(statusi)+0.1) / len(graph) @@ -807,7 +813,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'post') - ver = release.major_version + '.' + package.data.get('version', '1.0') + ver = release.major_version + '.' + package.data['version'] # Set new modules and dependencies modobj.write(cr, 1, [mid], {'state': 'installed', 'latest_version': ver}) cr.commit() @@ -888,8 +894,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False): # STEP 2: Mark other modules to be loaded/updated if update_module: modobj = pool.get('ir.module.module') - logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list') if ('base' in tools.config['init']) or ('base' in tools.config['update']): + logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list') modobj.update_list(cr, 1) _check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys())) @@ -971,6 +977,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False): cr.commit() if update_module: + # Remove records referenced from ir_model_data for modules to be + # removed (and removed the references from ir_model_data). cr.execute("select id,name from ir_module_module where state=%s", ('to remove',)) for mod_id, mod_name in cr.fetchall(): cr.execute('select model,res_id from ir_model_data where noupdate=%s and module=%s order by id desc', (False, mod_name,)) @@ -978,14 +986,17 @@ def load_modules(db, force_demo=False, status=None, update_module=False): uid = 1 rmod_module= pool.get(rmod) if rmod_module: + # TODO group by module so that we can delete multiple ids in a call rmod_module.unlink(cr, uid, [rid]) else: logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not locate %s to remove res=%d' % (rmod,rid)) cr.execute('delete from ir_model_data where noupdate=%s and module=%s', (False, mod_name,)) cr.commit() - # + + # Remove menu items that are not referenced by any of other + # (child) menu item, ir_values, or ir_model_data. + # This code could be a method of ir_ui_menu. # TODO: remove menu without actions of children - # while True: cr.execute('''delete from ir_ui_menu @@ -1001,6 +1012,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): else: logger.notifyChannel('init', netsvc.LOG_INFO, 'removed %d unused menus' % (cr.rowcount,)) + # Pretend that modules to be removed are actually uninstalled. cr.execute("update ir_module_module set state=%s where state=%s", ('uninstalled', 'to remove',)) cr.commit() finally: diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 723a3a5f2ea..1c1fbe0f1fa 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -85,6 +85,7 @@ def init_db(cr): if not mod_path: continue + # This will raise an exception if no/unreadable descriptor file. info = addons.load_information_from_description_file(i) if not info: diff --git a/tools/module_graph.py b/tools/module_graph.py index 05bb058a447..b29bd316e2f 100755 --- a/tools/module_graph.py +++ b/tools/module_graph.py @@ -27,6 +27,7 @@ import optparse import sys import glob +# TODO use the same function provided in openerp.modules def load_information_from_description_file(module): """ :param module: The name of the module (sale, purchase, ...)