[IMP] uninstall: started test module, added new ir_model_constraint table.
bzr revid: vmt@openerp.com-20120531160140-tutjw76tp0u5hipo
This commit is contained in:
parent
754cd3a7fe
commit
5df4aa8cca
|
@ -347,6 +347,25 @@ CREATE TABLE ir_model_data (
|
||||||
res_id integer, primary key(id)
|
res_id integer, primary key(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Records foreign keys and constraints
|
||||||
|
-- installed by a module (so they can be removed them when the module is
|
||||||
|
-- uninstalled).:
|
||||||
|
-- - for a foreign key: type 'f',
|
||||||
|
-- - for a constraint: type 'u'.
|
||||||
|
CREATE TABLE ir_model_constraint (
|
||||||
|
id serial NOT NULL,
|
||||||
|
create_uid integer,
|
||||||
|
create_date timestamp without time zone,
|
||||||
|
write_date timestamp without time zone,
|
||||||
|
write_uid integer,
|
||||||
|
date_init timestamp without time zone,
|
||||||
|
date_update timestamp without time zone,
|
||||||
|
module integer NOT NULL references ir_module_module on delete restrict,
|
||||||
|
model integer NOT NULL references ir_model on delete restrict,
|
||||||
|
type character varying(1) NOT NULL,
|
||||||
|
name character varying(128) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
---------------------------------
|
---------------------------------
|
||||||
-- Users
|
-- Users
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import ir_model
|
import ir_model
|
||||||
|
import ir_model_constraint
|
||||||
import ir_sequence
|
import ir_sequence
|
||||||
import ir_needaction
|
import ir_needaction
|
||||||
import ir_ui_menu
|
import ir_ui_menu
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
from openerp.osv import fields
|
||||||
|
from openerp.osv.orm import Model
|
||||||
|
|
||||||
|
class ir_model_constraint(Model):
|
||||||
|
"""
|
||||||
|
This model tracks PostgreSQL foreign keys and constraints used by OpenERP
|
||||||
|
models.
|
||||||
|
"""
|
||||||
|
_name = 'ir.model.constraint'
|
||||||
|
_columns = {
|
||||||
|
'name': fields.char('Constraint', required=True, size=128, select=1,
|
||||||
|
help="PostgreSQL constraint or foreign key name."),
|
||||||
|
'model': fields.many2one('ir.model', string='Model Name',
|
||||||
|
required=True, select=1),
|
||||||
|
'module': fields.many2one('ir.module.module', string='Module Name',
|
||||||
|
required=True, select=1),
|
||||||
|
'type': fields.char('Constraint Type', required=True, size=1, select=1,
|
||||||
|
help="Type of the constraint: `f` for a foreign key, "
|
||||||
|
"`u` for other constraints."),
|
||||||
|
'date_update': fields.datetime('Update Date'),
|
||||||
|
'date_init': fields.datetime('Initialization Date')
|
||||||
|
}
|
||||||
|
|
||||||
|
_sql_constraints = [
|
||||||
|
('module_name_uniq', 'unique(name, module)',
|
||||||
|
'Constraints with the same name are unique per module.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _module_data_uninstall(self, cr, uid, ids, context=None):
|
||||||
|
"""
|
||||||
|
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"):
|
||||||
|
raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module')))
|
||||||
|
|
||||||
|
context = dict(context or {})
|
||||||
|
|
||||||
|
ids_set = set(ids)
|
||||||
|
ids.sort()
|
||||||
|
ids.reverse()
|
||||||
|
for data in self.browse(cr, uid, ids, context):
|
||||||
|
model = data.model
|
||||||
|
model_obj = self.pool.get(model)
|
||||||
|
name = tools.ustr(data.name)
|
||||||
|
typ = data.type
|
||||||
|
|
||||||
|
# double-check we are really going to delete all the owners of this schema element
|
||||||
|
cr.execute("""SELECT id from ir_model_constraint where name=%s""", (data.name,))
|
||||||
|
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
|
||||||
|
|
||||||
|
elif 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():
|
||||||
|
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||||
|
_logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
|
||||||
|
|
||||||
|
elif 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():
|
||||||
|
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
|
||||||
|
_logger.info('Dropped CONSTRAINT %s@%s', name, model)
|
|
@ -2744,6 +2744,23 @@ class BaseModel(object):
|
||||||
_schema.debug("Table '%s': column '%s': dropped NOT NULL constraint",
|
_schema.debug("Table '%s': column '%s': dropped NOT NULL constraint",
|
||||||
self._table, column['attname'])
|
self._table, column['attname'])
|
||||||
|
|
||||||
|
def _save_constraint(self, cr, constraint_name, type):
|
||||||
|
assert type in ('f', 'u')
|
||||||
|
cr.execute("""
|
||||||
|
SELECT 1 FROM ir_model_constraint, ir_module_module
|
||||||
|
WHERE ir_model_constraint.module=ir_module_module.id
|
||||||
|
AND ir_model_constraint.name=%s
|
||||||
|
AND ir_module_module.name=%s
|
||||||
|
""", (constraint_name, self._module))
|
||||||
|
if not cr.rowcount:
|
||||||
|
cr.execute("""
|
||||||
|
INSERT INTO ir_model_constraint
|
||||||
|
(name, date_init, date_update, module, model, type)
|
||||||
|
VALUES (%s, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC',
|
||||||
|
(SELECT id FROM ir_module_module WHERE name=%s),
|
||||||
|
(SELECT id FROM ir_model WHERE model=%s), %s)""",
|
||||||
|
(constraint_name, self._module, self._name, type))
|
||||||
|
|
||||||
# quick creation of ir.model.data entry to make uninstall of schema elements easier
|
# quick creation of ir.model.data entry to make uninstall of schema elements easier
|
||||||
def _make_ext_id(self, cr, ext_id):
|
def _make_ext_id(self, cr, ext_id):
|
||||||
cr.execute('SELECT 1 FROM ir_model_data WHERE name=%s AND module=%s', (ext_id, self._module))
|
cr.execute('SELECT 1 FROM ir_model_data WHERE name=%s AND module=%s', (ext_id, self._module))
|
||||||
|
@ -3092,6 +3109,7 @@ class BaseModel(object):
|
||||||
for t, k, r, d in self._foreign_keys:
|
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))
|
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._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()
|
cr.commit()
|
||||||
del self._foreign_keys
|
del self._foreign_keys
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import models
|
||||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,15 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': 'test-uninstall',
|
||||||
|
'version': '0.1',
|
||||||
|
'category': 'Tests',
|
||||||
|
'description': """A module to test the uninstall feature.""",
|
||||||
|
'author': 'OpenERP SA',
|
||||||
|
'maintainer': 'OpenERP SA',
|
||||||
|
'website': 'http://www.openerp.com',
|
||||||
|
'depends': ['base'],
|
||||||
|
'data': [],
|
||||||
|
'installable': True,
|
||||||
|
'auto_install': False,
|
||||||
|
}
|
||||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,11 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import openerp
|
||||||
|
from openerp.osv.orm import Model
|
||||||
|
|
||||||
|
class test_uninstall_model(Model):
|
||||||
|
_name = 'test_uninstall.model'
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,66 @@
|
||||||
|
import openerp
|
||||||
|
from openerp.osv import fields
|
||||||
|
from openerp.osv.orm import Model
|
||||||
|
conf = openerp.tools.config
|
||||||
|
|
||||||
|
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)
|
||||||
|
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, {})
|
||||||
|
cr.close()
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
# Nice idea, but won't work without some more change to the framework (which
|
||||||
|
# expects everything on disk, maybe we can craft a zip file...).
|
||||||
|
|
||||||
|
MY_MODULE = {
|
||||||
|
'author': 'Jean Beauvoir',
|
||||||
|
'website': 'http://www.youtube.com/watch?v=FeO5DfdZi7Y',
|
||||||
|
'name': 'FEEL THE HEAT',
|
||||||
|
'description': "Cobra's theme",
|
||||||
|
'web': False,
|
||||||
|
'license': 'WTFPL',
|
||||||
|
'application': False,
|
||||||
|
'icon': False,
|
||||||
|
'sequence': 100,
|
||||||
|
'depends': ['base'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_virtual_module(db_name, module_name, info):
|
||||||
|
registry = openerp.modules.registry.RegistryManager.get(db_name)
|
||||||
|
cr = registry.db.cursor()
|
||||||
|
|
||||||
|
cr.execute("""SELECT 1 FROM ir_module_module WHERE name=%s""", (module_name,))
|
||||||
|
if cr.fetchone(): return
|
||||||
|
|
||||||
|
category_id = openerp.modules.db.create_categories(cr, ['Tests'])
|
||||||
|
cr.execute('INSERT INTO ir_module_module \
|
||||||
|
(author, website, name, shortdesc, description, \
|
||||||
|
category_id, auto_install, state, certificate, web, license, application, icon, sequence) \
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING id', (
|
||||||
|
info['author'],
|
||||||
|
info['website'], module_name, info['name'],
|
||||||
|
info['description'], category_id,
|
||||||
|
True, 'to install', False,
|
||||||
|
info['web'],
|
||||||
|
info['license'],
|
||||||
|
info['application'], info['icon'],
|
||||||
|
info['sequence']))
|
||||||
|
module_id = cr.fetchone()[0]
|
||||||
|
cr.execute('INSERT INTO ir_model_data \
|
||||||
|
(name,model,module, res_id, noupdate) VALUES (%s,%s,%s,%s,%s)', (
|
||||||
|
'module_' + module_name, 'ir.module.module', 'base', module_id, True))
|
||||||
|
dependencies = info['depends']
|
||||||
|
for d in dependencies:
|
||||||
|
cr.execute('INSERT INTO ir_module_module_dependency \
|
||||||
|
(module_id,name) VALUES (%s, %s)', (module_id, d))
|
||||||
|
|
||||||
|
cr.commit()
|
||||||
|
cr.close()
|
Loading…
Reference in New Issue