[ADD] module install/uninstall hooks.

Since 4ec71c74d1, migration scripts
are not executed at module install anymore.
As this behavior was missused as "init" scripts (see [1]), this
commit re-add this possiblity via hooks.

There are 3 hooks that can be declared in the manifest file:
 - pre_init_hook: called before module installation
 - post_init_hook: called after module installation
 - uninstall_hook: called before module uninstallation

Like the "post_load" manifest option, the values for these hooks
must be a string containing the name of a method available at the
module root.
The signatures of these functions are:
 - (cr) for pre_init_hook
 - (cr, registry) for post_init_hook and uninstall_hook

[1] https://bugs.launchpad.net/openobject-server/+bug/1314680
This commit is contained in:
Christophe Simonis 2014-06-07 00:01:52 +02:00
parent bd51bf1e35
commit 4105b5f028
2 changed files with 34 additions and 17 deletions

View File

@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
#
# 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:

View File

@ -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()