diff --git a/openerp/modules/graph.py b/openerp/modules/graph.py index 74f4e0db9ce..76a9f046dc6 100644 --- a/openerp/modules/graph.py +++ b/openerp/modules/graph.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2014 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -149,7 +149,14 @@ class Graph(dict): level += 1 -class Singleton(object): +class Node(object): + """ One module in the modules dependency graph. + + Node acts as a per-module singleton. A node is constructed via + Graph.add_module() or Graph.add_modules(). Some of its fields are from + ir_module_module (setted by Graph.update_from_db()). + + """ def __new__(cls, name, graph, info): if name in graph: inst = graph[name] @@ -160,22 +167,13 @@ class Singleton(object): graph[name] = inst return inst - -class Node(Singleton): - """ One module in the modules dependency graph. - - Node acts as a per-module singleton. A node is constructed via - Graph.add_module() or Graph.add_modules(). Some of its fields are from - ir_module_module (setted by Graph.update_from_db()). - - """ - def __init__(self, name, graph, info): self.graph = graph if not hasattr(self, 'children'): self.children = [] if not hasattr(self, 'depth'): self.depth = 0 + self.info = info or {} def add_child(self, name, info): node = Node(name, self.graph, info) @@ -189,7 +187,7 @@ class Node(Singleton): return node def __setattr__(self, name, value): - super(Singleton, self).__setattr__(name, value) + super(Node, self).__setattr__(name, value) if name in ('init', 'update', 'demo'): tools.config[name][self.name] = 1 for child in self.children: diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 2b507acc0bb..2b9fca6fca9 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -148,6 +148,13 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'pre') load_openerp_module(package.name) + new_install = package.installed_version is None + if new_install: + py_module = sys.modules['openerp.addons.%s' % (module_name,)] + pre_init = package.info.get('pre_init_hook') + if pre_init: + getattr(py_module, pre_init)(cr) + models = registry.load(cr, package) loaded_modules.append(package.name) @@ -181,6 +188,11 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'post') + if new_install: + post_init = package.info.get('post_init_hook') + if post_init: + getattr(py_module, post_init)(cr, registry) + registry._init_modules.add(package.name) # validate all the views at a whole registry['ir.ui.view']._validate_module_views(cr, SUPERUSER_ID, module_name) @@ -401,10 +413,17 @@ def load_modules(db, force_demo=False, status=None, update_module=False): 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 FROM ir_module_module WHERE state=%s", ('to remove',)) - mod_ids_to_remove = [x[0] for x in cr.fetchall()] - if mod_ids_to_remove: - registry['ir.module.module'].module_uninstall(cr, SUPERUSER_ID, mod_ids_to_remove) + cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s", ('to remove',)) + modules_to_remove = dict(cr.fetchall()) + if modules_to_remove: + pkgs = reversed([p for p in graph if p.name in modules_to_remove]) + for pkg in pkgs: + uninstall_hook = pkg.info.get('uninstall_hook') + if uninstall_hook: + py_module = sys.modules['openerp.addons.%s' % (pkg.name,)] + getattr(py_module, uninstall_hook)(cr, registry) + + registry['ir.module.module'].module_uninstall(cr, SUPERUSER_ID, modules_to_remove.values()) # Recursive reload, should only happen once, because there should be no # modules to remove next time cr.commit()