[IMP] uninstall: use dedicated table instead of overloading ir.model.data.
bzr revid: vmt@openerp.com-20120601131414-880vmpctmjfxl84f
This commit is contained in:
parent
5df4aa8cca
commit
d790650bfb
|
@ -29,8 +29,7 @@ from openerp import netsvc, pooler, tools
|
|||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.tools import config
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv.orm import except_orm, browse_record, EXT_ID_PREFIX_FK, \
|
||||
EXT_ID_PREFIX_M2M_TABLE, EXT_ID_PREFIX_CONSTRAINT
|
||||
from openerp.osv.orm import except_orm, browse_record, EXT_ID_PREFIX_M2M_TABLE
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -857,8 +856,7 @@ class ir_model_data(osv.osv):
|
|||
model_obj = self.pool.get(model)
|
||||
name = tools.ustr(data.name)
|
||||
|
||||
if name.startswith(EXT_ID_PREFIX_FK) or name.startswith(EXT_ID_PREFIX_M2M_TABLE)\
|
||||
or name.startswith(EXT_ID_PREFIX_CONSTRAINT):
|
||||
if name.startswith(EXT_ID_PREFIX_M2M_TABLE):
|
||||
# double-check we are really going to delete all the owners of this schema element
|
||||
cr.execute("""SELECT id from ir_model_data where name = %s and res_id IS NULL""", (data.name,))
|
||||
external_ids = [x[0] for x in cr.fetchall()]
|
||||
|
@ -866,16 +864,6 @@ class ir_model_data(osv.osv):
|
|||
# as installed modules have defined this element we must not delete it!
|
||||
continue
|
||||
|
||||
if name.startswith(EXT_ID_PREFIX_FK):
|
||||
name = name[len(EXT_ID_PREFIX_FK):]
|
||||
# test if FK exists on this table (it could be on a related m2m table, in which case we ignore it)
|
||||
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
|
||||
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table))
|
||||
if cr.fetchone():
|
||||
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||
_logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
|
||||
continue
|
||||
|
||||
if name.startswith(EXT_ID_PREFIX_M2M_TABLE):
|
||||
name = name[len(EXT_ID_PREFIX_M2M_TABLE):]
|
||||
cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name=%s", (name,))
|
||||
|
@ -883,16 +871,6 @@ class ir_model_data(osv.osv):
|
|||
to_drop_table.append(name)
|
||||
continue
|
||||
|
||||
if name.startswith(EXT_ID_PREFIX_CONSTRAINT):
|
||||
name = name[len(EXT_ID_PREFIX_CONSTRAINT):]
|
||||
# test if constraint exists
|
||||
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
|
||||
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table))
|
||||
if cr.fetchone():
|
||||
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||
_logger.info('Dropped CONSTRAINT %s@%s', name, model)
|
||||
continue
|
||||
|
||||
pair_to_unlink = (model, res_id)
|
||||
if pair_to_unlink not in to_unlink:
|
||||
to_unlink.append(pair_to_unlink)
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import logging
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import fields
|
||||
from openerp.osv.orm import Model
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class ir_model_constraint(Model):
|
||||
"""
|
||||
This model tracks PostgreSQL foreign keys and constraints used by OpenERP
|
||||
|
@ -33,7 +37,7 @@ class ir_model_constraint(Model):
|
|||
Delete PostgreSQL foreign keys and constraints tracked by this model.
|
||||
"""
|
||||
|
||||
if uid != 1 and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"):
|
||||
if uid != SUPERUSER_ID and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"):
|
||||
raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module')))
|
||||
|
||||
context = dict(context or {})
|
||||
|
@ -41,10 +45,11 @@ class ir_model_constraint(Model):
|
|||
ids_set = set(ids)
|
||||
ids.sort()
|
||||
ids.reverse()
|
||||
to_unlink = []
|
||||
for data in self.browse(cr, uid, ids, context):
|
||||
model = data.model
|
||||
model = data.model.name
|
||||
model_obj = self.pool.get(model)
|
||||
name = tools.ustr(data.name)
|
||||
name = openerp.tools.ustr(data.name)
|
||||
typ = data.type
|
||||
|
||||
# double-check we are really going to delete all the owners of this schema element
|
||||
|
@ -52,20 +57,25 @@ class ir_model_constraint(Model):
|
|||
external_ids = [x[0] for x in cr.fetchall()]
|
||||
if (set(external_ids)-ids_set):
|
||||
# as installed modules have defined this element we must not delete it!
|
||||
pass
|
||||
continue
|
||||
|
||||
elif typ == 'f':
|
||||
if typ == 'f':
|
||||
# test if FK exists on this table (it could be on a related m2m table, in which case we ignore it)
|
||||
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
|
||||
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table))
|
||||
if cr.fetchone():
|
||||
print '>>> ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name)
|
||||
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||
_logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
|
||||
|
||||
elif typ == 'u':
|
||||
if typ == 'u':
|
||||
# test if constraint exists
|
||||
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
|
||||
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table))
|
||||
if cr.fetchone():
|
||||
print '>>> ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name)
|
||||
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||
_logger.info('Dropped CONSTRAINT %s@%s', name, model)
|
||||
|
||||
to_unlink.append(data.id)
|
||||
self.unlink(cr, uid, to_unlink, context)
|
||||
|
|
|
@ -364,7 +364,10 @@ class module(osv.osv):
|
|||
including the deletion of all database structures created by the module:
|
||||
tables, columns, constraints, etc."""
|
||||
ir_model_data = self.pool.get('ir.model.data')
|
||||
ir_model_constraint = self.pool.get('ir.model.constraint')
|
||||
modules_to_remove = [m.name for m in self.browse(cr, uid, ids, context)]
|
||||
constraint_ids = ir_model_constraint.search(cr, uid, [('module', 'in', modules_to_remove)])
|
||||
ir_model_constraint._module_data_uninstall(cr, uid, constraint_ids, context)
|
||||
data_ids = ir_model_data.search(cr, uid, [('module', 'in', modules_to_remove)])
|
||||
ir_model_data._module_data_uninstall(cr, uid, data_ids, context)
|
||||
ir_model_data.unlink(cr, uid, data_ids, context)
|
||||
|
|
|
@ -71,9 +71,7 @@ _schema = logging.getLogger(__name__ + '.schema')
|
|||
from openerp.tools import SKIPPED_ELEMENT_TYPES
|
||||
|
||||
# Prefixes for external IDs of schema elements
|
||||
EXT_ID_PREFIX_FK = "_foreign_key_"
|
||||
EXT_ID_PREFIX_M2M_TABLE = "_m2m_rel_table_"
|
||||
EXT_ID_PREFIX_CONSTRAINT = "_constraint_"
|
||||
|
||||
regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I)
|
||||
regex_object_name = re.compile(r'^[a-z0-9_.]+$')
|
||||
|
@ -3108,7 +3106,6 @@ class BaseModel(object):
|
|||
""" Create the foreign keys recorded by _auto_init. """
|
||||
for t, k, r, d in self._foreign_keys:
|
||||
cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (t, k, r, d))
|
||||
self._make_ext_id(cr, "%s%s_%s_fkey" % (EXT_ID_PREFIX_FK, t, k))
|
||||
self._save_constraint(cr, "%s_%s_fkey" % (t, k), 'f')
|
||||
cr.commit()
|
||||
del self._foreign_keys
|
||||
|
@ -3234,7 +3231,7 @@ class BaseModel(object):
|
|||
for (key, con, _) in self._sql_constraints:
|
||||
conname = '%s_%s' % (self._table, key)
|
||||
|
||||
self._make_ext_id(cr, EXT_ID_PREFIX_CONSTRAINT + conname)
|
||||
self._save_constraint(cr, conname, 'u')
|
||||
cr.execute("SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef FROM pg_constraint where conname=%s", (conname,))
|
||||
existing_constraints = cr.dictfetchall()
|
||||
sql_actions = {
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import openerp
|
||||
from openerp.osv import fields
|
||||
from openerp.osv.orm import Model
|
||||
|
||||
class test_uninstall_model(Model):
|
||||
_name = 'test_uninstall.model'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64),
|
||||
'ref': fields.many2one('res.users', string='User'),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', 'Each name must be unique.')
|
||||
]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
78
t.py
78
t.py
|
@ -1,18 +1,80 @@
|
|||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import fields
|
||||
from openerp.osv.orm import Model
|
||||
conf = openerp.tools.config
|
||||
|
||||
# TODO Exception handling (especially on cursors).
|
||||
|
||||
def get_registry(database_name):
|
||||
registry = openerp.modules.registry.RegistryManager.get(database_name)
|
||||
return registry
|
||||
|
||||
def reload_registry(database_name):
|
||||
openerp.modules.registry.RegistryManager.new(
|
||||
database_name, update_module=True)
|
||||
|
||||
def search_registry(database_name, model_name, domain):
|
||||
registry = get_registry(database_name)
|
||||
cr = registry.db.cursor()
|
||||
model = registry.get(model_name)
|
||||
record_ids = model.search(cr, SUPERUSER_ID,
|
||||
domain, {})
|
||||
cr.close()
|
||||
return record_ids
|
||||
|
||||
def install_module(database_name, module_name):
|
||||
registry = get_registry(database_name)
|
||||
ir_module_module = registry.get('ir.module.module')
|
||||
cr = registry.db.cursor()
|
||||
module_ids = ir_module_module.search(cr, SUPERUSER_ID,
|
||||
[('name', '=', module_name)], {})
|
||||
assert len(module_ids) == 1
|
||||
ir_module_module.button_install(cr, SUPERUSER_ID, module_ids, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
reload_registry(database_name)
|
||||
|
||||
def uninstall_module(database_name, module_name):
|
||||
registry = get_registry(database_name)
|
||||
ir_module_module = registry.get('ir.module.module')
|
||||
cr = registry.db.cursor()
|
||||
module_ids = ir_module_module.search(cr, SUPERUSER_ID,
|
||||
[('name', '=', module_name)], {})
|
||||
assert len(module_ids) == 1
|
||||
ir_module_module.button_uninstall(cr, SUPERUSER_ID, module_ids, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
reload_registry(database_name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
openerp.netsvc.init_logger()
|
||||
conf['addons_path'] = './openerp/tests/addons'
|
||||
conf['init'] = {'test_uninstall': 1}
|
||||
registry = openerp.modules.registry.RegistryManager.new('xx', update_module=True)
|
||||
conf['addons_path'] = './openerp/tests/addons,../../addons/trunk,../../web/trunk/addons'
|
||||
|
||||
install_module('xx', 'test_uninstall')
|
||||
registry = get_registry('xx')
|
||||
assert registry.get('test_uninstall.model')
|
||||
|
||||
assert search_registry('xx', 'ir.model.data',
|
||||
[('module', '=', 'test_uninstall')])
|
||||
|
||||
assert search_registry('xx', 'ir.model.fields',
|
||||
[('model', '=', 'test_uninstall.model')])
|
||||
|
||||
uninstall_module('xx', 'test_uninstall')
|
||||
registry = get_registry('xx')
|
||||
assert not registry.get('test_uninstall.model')
|
||||
|
||||
assert not search_registry('xx', 'ir.model.data',
|
||||
[('module', '=', 'test_uninstall')])
|
||||
|
||||
assert not search_registry('xx', 'ir.model.fields',
|
||||
[('model', '=', 'test_uninstall.model')])
|
||||
|
||||
ir_model_constraint = registry.get('ir.model.constraint')
|
||||
print ir_model_constraint
|
||||
cr = registry.db.cursor()
|
||||
ids = ir_model_constraint.search(cr, openerp.SUPERUSER_ID, [], {})
|
||||
print ir_model_constraint.browse(cr, openerp.SUPERUSER_ID, ids, {})
|
||||
ids = ir_model_constraint.search(cr, SUPERUSER_ID, [], {})
|
||||
#print ir_model_constraint.browse(cr, SUPERUSER_ID, ids, {})
|
||||
cr.close()
|
||||
|
||||
#####################################################################
|
||||
|
@ -33,8 +95,8 @@ MY_MODULE = {
|
|||
'depends': ['base'],
|
||||
}
|
||||
|
||||
def create_virtual_module(db_name, module_name, info):
|
||||
registry = openerp.modules.registry.RegistryManager.get(db_name)
|
||||
def create_virtual_module(database_name, module_name, info):
|
||||
registry = get_registry(database_name)
|
||||
cr = registry.db.cursor()
|
||||
|
||||
cr.execute("""SELECT 1 FROM ir_module_module WHERE name=%s""", (module_name,))
|
||||
|
|
Loading…
Reference in New Issue