Merge lp:~therp-nl/openupgrade-server/6.0-API_and_loading_improvements into lp:openupgrade-server/6.0

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 3489
Proposed branch: lp:~therp-nl/openupgrade-server/6.0-API_and_loading_improvements
Merge into: lp:openupgrade-server/6.0
Diff against target: 580 lines (+268/-102)
5 files modified
bin/addons/__init__.py (+12/-15)
bin/addons/base/migrations/6.0.1.3/post-migration.py (+88/-37)
bin/addons/base/migrations/6.0.1.3/pre-migration.py (+25/-15)
bin/addons/openupgrade_records/lib/apriori.py (+3/-0)
bin/openupgrade/openupgrade.py (+140/-35)
To merge this branch: bzr merge lp:~therp-nl/openupgrade-server/6.0-API_and_loading_improvements
Reviewer Review Type Date Requested Status
OpenUpgrade Committers Pending
Review via email: mp+109162@code.launchpad.net

Description of the change

This branch ensures that pre and post scripts are only called once. This means that developers do not have to bother checking whether they are being rerun in the scripts themselves. It is now also ensured that new dependencies are installed automatically. Modules that are known to be obsolete will now be removed automatically.

The API is augmented with a decorator that can be used in migration scripts to log any errors that may occur. A new function for renaming XML IDs is provided, and setting defaults provided by a function is faster.

Some bugs in the base module migration scripts are solved.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/addons/__init__.py'
--- bin/addons/__init__.py 2012-05-27 12:34:50 +0000
+++ bin/addons/__init__.py 2012-06-07 14:50:24 +0000
@@ -50,14 +50,7 @@
5050
51logger = netsvc.Logger()51logger = netsvc.Logger()
5252
53### OpenUpgrade53from openupgrade import openupgrade
54def table_exists(cr, table):
55 """ Check whether a certain table or view exists """
56 cr.execute(
57 'SELECT count(relname) FROM pg_class WHERE relname = %s',
58 (table,))
59 return cr.fetchone()[0] == 1
60### End of OpenUpgrade
6154
62_ad = os.path.abspath(opj(tools.ustr(tools.config['root_path']), u'addons')) # default addons path (base)55_ad = os.path.abspath(opj(tools.ustr(tools.config['root_path']), u'addons')) # default addons path (base)
63ad_paths= map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))56ad_paths= map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))
@@ -808,7 +801,7 @@
808 log any differences and merge the local registry with801 log any differences and merge the local registry with
809 the global one.802 the global one.
810 """803 """
811 if not table_exists(cr, 'openupgrade_record'):804 if not openupgrade.table_exists(cr, 'openupgrade_record'):
812 return805 return
813 for model, fields in local_registry.items():806 for model, fields in local_registry.items():
814 registry.setdefault(model, {})807 registry.setdefault(model, {})
@@ -848,10 +841,9 @@
848 logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph))841 logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph))
849842
850 for package in graph:843 for package in graph:
851 if skip_modules and package.name in skip_modules:
852 continue
853 logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading objects' % package.name)844 logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading objects' % package.name)
854 migrations.migrate_module(package, 'pre')845 if package.name not in skip_modules['pre']:
846 migrations.migrate_module(package, 'pre')
855 register_class(package.name)847 register_class(package.name)
856 modules = pool.instanciate(package.name, cr)848 modules = pool.instanciate(package.name, cr)
857849
@@ -864,13 +856,14 @@
864856
865 init_module_objects(cr, package.name, modules)857 init_module_objects(cr, package.name, modules)
866 cr.commit()858 cr.commit()
859 skip_modules['pre'].append(package.name)
867860
868 for package in graph:861 for package in graph:
869 status['progress'] = (float(statusi)+0.1) / len(graph)862 status['progress'] = (float(statusi)+0.1) / len(graph)
870 m = package.name863 m = package.name
871 mid = package.id864 mid = package.id
872865
873 if skip_modules and m in skip_modules:866 if package.name in skip_modules['post']:
874 continue867 continue
875868
876 if modobj is None:869 if modobj is None:
@@ -923,6 +916,7 @@
923 if hasattr(package, kind):916 if hasattr(package, kind):
924 delattr(package, kind)917 delattr(package, kind)
925918
919 skip_modules['post'].append(package.name)
926 statusi += 1920 statusi += 1
927 cr.commit()921 cr.commit()
928922
@@ -964,6 +958,7 @@
964958
965 registry = {}959 registry = {}
966960
961 skip_modules = {'pre': [], 'post': []}
967 try:962 try:
968 processed_modules = []963 processed_modules = []
969 report = tools.assertion_report()964 report = tools.assertion_report()
@@ -977,7 +972,7 @@
977 if not graph:972 if not graph:
978 logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')973 logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
979 raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))974 raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
980 processed_modules.extend(load_module_graph(cr, graph, status, perform_checks=(not update_module), registry=registry, report=report))975 processed_modules.extend(load_module_graph(cr, graph, status, perform_checks=(not update_module), registry=registry, report=report, skip_modules=skip_modules))
981976
982 if tools.config['load_language']:977 if tools.config['load_language']:
983 for lang in tools.config['load_language'].split(','):978 for lang in tools.config['load_language'].split(','):
@@ -1021,13 +1016,15 @@
1021 if not module_list:1016 if not module_list:
1022 break1017 break
10231018
1019 # OpenUpgrade: forcefeeding module dependencies into the graph
1020 module_list = openupgrade.add_module_dependencies(cr, module_list)
1024 new_modules_in_graph = upgrade_graph(graph, cr, module_list, force)1021 new_modules_in_graph = upgrade_graph(graph, cr, module_list, force)
1025 if new_modules_in_graph == 0:1022 if new_modules_in_graph == 0:
1026 # nothing to load1023 # nothing to load
1027 break1024 break
10281025
1029 logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))1026 logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))
1030 processed_modules.extend(load_module_graph(cr, graph, status, registry=registry, report=report, skip_modules=processed_modules))1027 processed_modules.extend(load_module_graph(cr, graph, status, registry=registry, report=report, skip_modules=skip_modules))
10311028
1032 # load custom models1029 # load custom models
1033 cr.execute('select model from ir_model where state=%s', ('manual',))1030 cr.execute('select model from ir_model where state=%s', ('manual',))
10341031
=== modified file 'bin/addons/base/migrations/6.0.1.3/post-migration.py'
--- bin/addons/base/migrations/6.0.1.3/post-migration.py 2011-11-30 22:51:16 +0000
+++ bin/addons/base/migrations/6.0.1.3/post-migration.py 2012-06-07 14:50:24 +0000
@@ -1,18 +1,58 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
22
3from osv import osv
4import pooler, logging3import pooler, logging
5from openupgrade import openupgrade4from openupgrade import openupgrade
6log = logging.getLogger('migrate')5logger = logging.getLogger('migrate')
6MODULE="base"
7
8obsolete_modules = [
9 'account_report',
10 'account_reporting',
11 'account_tax_include',
12 'board_account',
13 'board_sale',
14 'report_account',
15 'report_analytic',
16 'report_analytic_line',
17 'report_crm',
18 'report_purchase',
19 'report_sale',
20 'pxgo_bank_statement_analytic',
21]
22
23def set_defaults_on_act_window(cr):
24 """ The act window model has a constraint
25 that checks the validity of the model on it.
26 At migration time, this is inconvenient.
27 Therefore, we set the defaults through SQL
28
29 Replaces setting the following defaults
30 #'ir.actions.act_window': [
31 # ('auto_search', True),
32 # ('context', '{}'),
33 # ('multi', False),
34 # ],
35
36 """
37 cr.execute("""
38 UPDATE ir_act_window
39 SET auto_search = true,
40 multi = false
41 """)
42 cr.execute("""
43 UPDATE ir_act_window
44 SET context = '{}'
45 WHERE context is NULL
46 """)
47 cr.execute("""
48 UPDATE ir_act_window
49 SET context = '{}'
50 WHERE context is NULL
51 """)
752
8defaults = {53defaults = {
9 # False results in column value NULL54 # False results in column value NULL
10 # None value triggers a call to the model's default function 55 # None value triggers a call to the model's default function
11 'ir.actions.act_window': [
12 ('auto_search', True),
13 ('context', '{}'),
14 ('multi', False),
15 ],
16 'ir.actions.todo': [56 'ir.actions.todo': [
17 ('restart', 'onskip'),57 ('restart', 'onskip'),
18 ],58 ],
@@ -96,13 +136,14 @@
96 # In the pre script, we renamed the old function column, a many2one136 # In the pre script, we renamed the old function column, a many2one
97 # to res.partner.function137 # to res.partner.function
98 cr.execute(138 cr.execute(
99 "UPDATE res_partner_address SET function = res_partner_function.name " +139 "UPDATE res_partner_address "
100 "FROM res_partner_function " +140 "SET function = openupgrade_legacy_res_partner_function.name "
101 "WHERE res_partner_function.id = res_partner_address.tmp_mgr_function"141 "FROM openupgrade_legacy_res_partner_function "
102 )142 "WHERE openupgrade_legacy_res_partner_function.id "
103 cr.execute("ALTER TABLE res_partner_address DROP COLUMN tmp_mgr_function CASCADE")143 "= res_partner_address.tmp_mgr_function")
104 cr.execute("DROP TABLE res_partner_function")144 cr.execute(
105145 "ALTER TABLE res_partner_address "
146 "DROP COLUMN tmp_mgr_function CASCADE")
106 # and the reverse: 'title' is now a many2one on res_partner_title147 # and the reverse: 'title' is now a many2one on res_partner_title
107 cr.execute(148 cr.execute(
108 "SELECT id, tmp_mgr_title FROM res_partner_address WHERE title IS NULL " +149 "SELECT id, tmp_mgr_title FROM res_partner_address WHERE title IS NULL " +
@@ -139,10 +180,9 @@
139 if bank_ids:180 if bank_ids:
140 bank_id = bank_ids[0]181 bank_id = bank_ids[0]
141 else:182 else:
142 bank_id = bank_obj.create(cursor, uid, dict(183 bank_id = bank_obj.create(cr, 1, dict(
143 code = info.code or 'UNKNOW',184 code = 'UNKNOW',
144 name = info.name or _('Unknown Bank'),185 name = 'Unknown Bank')),
145 ))
146 partner_bank_obj.write(cr, 1, partner_bank_ids, {'bank': bank_id})186 partner_bank_obj.write(cr, 1, partner_bank_ids, {'bank': bank_id})
147 187
148def mgr_roles_to_groups(cr, pool):188def mgr_roles_to_groups(cr, pool):
@@ -208,24 +248,35 @@
208 "AND ir_actions.usage = 'menu'"248 "AND ir_actions.usage = 'menu'"
209 )249 )
210250
251def mark_obsolete_modules(cr):
252 """
253 Remove modules that are known to be obsolete
254 in this version of the OpenERP server.
255 """
256 openupgrade.logged_query(
257 cr, """
258 UPDATE
259 ir_module_module
260 SET
261 state='to remove'
262 WHERE
263 state='installed'
264 AND name in %s
265 """,
266 (tuple(obsolete_modules),))
267
268@openupgrade.migrate()
211def migrate(cr, version):269def migrate(cr, version):
212 try:270 pool = pooler.get_pool(cr.dbname)
213 271 set_defaults_on_act_window(cr)
214 log.info("post-set-defaults.py now called")272 openupgrade.set_defaults(cr, pool, defaults)
215 # this method called in a try block too273 mgr_ir_rule(cr, pool)
216 pool = pooler.get_pool(cr.dbname)274 mgr_res_partner_address(cr, pool)
217275 mgr_res_partner(cr, pool)
218 openupgrade.set_defaults(cr, pool, defaults)276 mgr_default_bank(cr, pool)
219277 mgr_roles_to_groups(cr, pool)
220 mgr_ir_rule(cr, pool)278 mgr_res_currency(cr, pool)
221 mgr_res_partner_address(cr, pool)279 mgr_ir_module_module(cr)
222 mgr_res_partner(cr, pool)280 mgr_res_users(cr)
223 mgr_default_bank(cr, pool)281 mark_obsolete_modules(cr)
224 mgr_roles_to_groups(cr, pool)
225 mgr_res_currency(cr, pool)
226 mgr_ir_module_module(cr)
227 mgr_res_users(cr)
228 except Exception, e:
229 log.info("Migration: error in post-set-defaults.py: %s" % e)
230 raise
231282
232283
=== modified file 'bin/addons/base/migrations/6.0.1.3/pre-migration.py'
--- bin/addons/base/migrations/6.0.1.3/pre-migration.py 2012-01-15 11:33:42 +0000
+++ bin/addons/base/migrations/6.0.1.3/pre-migration.py 2012-06-07 14:50:24 +0000
@@ -3,11 +3,18 @@
3# Removal of modules that are deprecated3# Removal of modules that are deprecated
4# e.g. report_analytic_line (incorporated in hr_timesheet_invoice)4# e.g. report_analytic_line (incorporated in hr_timesheet_invoice)
55
6from osv import osv
7import pooler6import pooler
8import logging7import logging
9from openupgrade import openupgrade8from openupgrade import openupgrade
9
10log = logging.getLogger('migrate')10log = logging.getLogger('migrate')
11MODULE = 'base'
12
13module_namespec = [
14 # This is a list of tuples (old module name, new module name)
15 ('profile_association', 'association'),
16 ('report_analytic_planning', 'project_planning'),
17]
1118
12renames = {19renames = {
13 # this is a mapping per table from old column name20 # this is a mapping per table from old column name
@@ -27,6 +34,11 @@
27 ],34 ],
28 }35 }
2936
37renamed_xmlids = [
38 ('sale.group_sale_manager', 'base.group_sale_manager'),
39 ('sale.group_sale_user', 'base.group_sale_salesman'),
40]
41
30def mgr_ir_model_fields(cr):42def mgr_ir_model_fields(cr):
31 cr.execute('ALTER TABLE ir_model_fields ADD COLUMN selectable BOOLEAN')43 cr.execute('ALTER TABLE ir_model_fields ADD COLUMN selectable BOOLEAN')
32 cr.execute('UPDATE ir_model_fields SET selectable = FALSE')44 cr.execute('UPDATE ir_model_fields SET selectable = FALSE')
@@ -54,20 +66,18 @@
54 "AND ir_model_data.model = 'res.currency.rate' " +66 "AND ir_model_data.model = 'res.currency.rate' " +
55 "AND ir_model_data.name = 'rateINR'")67 "AND ir_model_data.name = 'rateINR'")
56 if not cr.rowcount:68 if not cr.rowcount:
57 import pdb
58 pdb.set_trace()
59 raise osv.except_osv("Migration: error setting INR rate in demo data, no row found", "")69 raise osv.except_osv("Migration: error setting INR rate in demo data, no row found", "")
6070
71@openupgrade.migrate()
61def migrate(cr, version):72def migrate(cr, version):
62 try:73 openupgrade.update_module_names(
63 # this method called in a try block too74 cr, module_namespec
64 log.info("base:pre.py now called")75 )
65 pool = pooler.get_pool(cr.dbname)76 openupgrade.rename_columns(cr, renames)
66 openupgrade.rename_columns(cr, renames)77 openupgrade.rename_xmlids(cr, renamed_xmlids)
67 mgr_ir_model_fields(cr)78 mgr_ir_model_fields(cr)
68 mgr_company_id(cr)79 mgr_company_id(cr)
69 mgr_fix_test_results(cr)80 mgr_fix_test_results(cr)
70 except Exception, e:81 openupgrade.rename_tables(
71 log.info("Migration: error in pre-convert-fields.py: %s", e)82 cr, [('res_partner_function',
72 osv.except_osv("Migration: error in pre-convert-fields.py: %s" % e, "")83 'openupgrade_legacy_res_partner_function')])
73 raise
7484
=== modified file 'bin/addons/openupgrade_records/lib/apriori.py'
--- bin/addons/openupgrade_records/lib/apriori.py 2012-04-18 20:20:03 +0000
+++ bin/addons/openupgrade_records/lib/apriori.py 2012-06-07 14:50:24 +0000
@@ -3,7 +3,10 @@
3"""3"""
44
5renamed_modules = {5renamed_modules = {
6 'association_profile': 'association',
7 'report_analytic_planning': 'project_planning',
6 }8 }
79
8renamed_models = {10renamed_models = {
11 'mrp.procurement': 'procurement.order',
9 }12 }
1013
=== modified file 'bin/openupgrade/openupgrade.py'
--- bin/openupgrade/openupgrade.py 2012-05-06 18:56:17 +0000
+++ bin/openupgrade/openupgrade.py 2012-06-07 14:50:24 +0000
@@ -1,5 +1,26 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# This module copyright (C) 2011-2012 Therp BV (<http://therp.nl>)
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
2import os22import os
23import inspect
3from osv import osv24from osv import osv
4import pooler25import pooler
5import logging26import logging
@@ -9,16 +30,20 @@
9logger = logging.getLogger('OpenUpgrade')30logger = logging.getLogger('OpenUpgrade')
1031
11__all__ = [32__all__ = [
33 'migrate',
12 'load_data',34 'load_data',
13 'rename_columns',35 'rename_columns',
14 'rename_tables',36 'rename_tables',
15 'drop_columns',37 'drop_columns',
16 'table_exists',38 'table_exists',
17 'column_exists',39 'column_exists',
40 'logged_query',
18 'delete_model_workflow',41 'delete_model_workflow',
19 'set_defaults',42 'set_defaults',
20 'update_module_names',43 'update_module_names',
21 'add_ir_model_fields',44 'add_ir_model_fields',
45 'rename_models',
46 'rename_xmlids',
22] 47]
2348
24def load_data(cr, module_name, filename, idref=None, mode='init'):49def load_data(cr, module_name, filename, idref=None, mode='init'):
@@ -94,7 +119,7 @@
94def rename_models(cr, model_spec):119def rename_models(cr, model_spec):
95 """120 """
96 Rename models. Typically called in the pre script.121 Rename models. Typically called in the pre script.
97 :param column_spec: a list of tuples (old table name, new table name).122 :param column_spec: a list of tuples (old model name, new model name).
98 123
99 Use case: if a model changes name, but still implements equivalent124 Use case: if a model changes name, but still implements equivalent
100 functionality you will want to update references in for instance125 functionality you will want to update references in for instance
@@ -106,6 +131,24 @@
106 old, new)131 old, new)
107 cr.execute('UPDATE ir_model_fields SET relation = %s '132 cr.execute('UPDATE ir_model_fields SET relation = %s '
108 'WHERE relation = %s', (new, old,))133 'WHERE relation = %s', (new, old,))
134 # TODO: signal where the model occurs in references to ir_model
135
136def rename_xmlids(cr, xmlids_spec):
137 """
138 Rename XML IDs. Typically called in the pre script.
139 One usage example is when an ID changes module. In OpenERP 6 for example,
140 a number of res_groups IDs moved to module base from other modules (
141 although they were still being defined in their respective module).
142 """
143 for (old, new) in xmlids_spec:
144 if not old.split('.') or not new.split('.'):
145 logger.error(
146 'Cannot rename XMLID %s to %s: need the module '
147 'reference to be specified in the IDs' % (old, new))
148 else:
149 query = ("UPDATE ir_model_data SET module = %s, name = %s "
150 "WHERE module = %s and name = %s")
151 logged_query(cr, query, tuple(new.split('.') + old.split('.')))
109152
110def drop_columns(cr, column_spec):153def drop_columns(cr, column_spec):
111 """154 """
@@ -161,8 +204,8 @@
161 """204 """
162205
163 def write_value(ids, field, value):206 def write_value(ids, field, value):
164 logger.info("model %s, field %s: setting default value of %d resources to %s",207 logger.debug("model %s, field %s: setting default value of resources %s to %s",
165 model, field, len(ids), unicode(value))208 model, field, ids, unicode(value))
166 obj.write(cr, 1, ids, {field: value})209 obj.write(cr, 1, ids, {field: value})
167210
168 for model in default_spec.keys():211 for model in default_spec.keys():
@@ -170,40 +213,42 @@
170 if not obj:213 if not obj:
171 raise osv.except_osv("Migration: error setting default, no such model: %s" % model, "")214 raise osv.except_osv("Migration: error setting default, no such model: %s" % model, "")
172215
173 for field, value in default_spec[model]:216 for field, value in default_spec[model]:
174 domain = not force and [(field, '=', False)] or []217 domain = not force and [(field, '=', False)] or []
175 ids = obj.search(cr, 1, domain)218 ids = obj.search(cr, 1, domain)
176 if not ids:219 if not ids:
177 continue220 continue
178 if value is None:221 if value is None:
179 # Set the value by calling the _defaults of the object.222 # Set the value by calling the _defaults of the object.
180 # Typically used for company_id on various models, and in that223 # Typically used for company_id on various models, and in that
181 # case the result depends on the user associated with the object.224 # case the result depends on the user associated with the object.
182 # We retrieve create_uid for this purpose and need to call the _defaults225 # We retrieve create_uid for this purpose and need to call the _defaults
183 # function per resource. Otherwise, write all resources at once.226 # function per resource. Otherwise, write all resources at once.
184 if field in obj._defaults:227 if field in obj._defaults:
185 if not callable(obj._defaults[field]):228 if not callable(obj._defaults[field]):
186 write_value(ids, field, obj._defaults[field])229 write_value(ids, field, obj._defaults[field])
230 else:
231 # existence users is covered by foreign keys, so this is not needed
232 # cr.execute("SELECT %s.id, res_users.id FROM %s LEFT OUTER JOIN res_users ON (%s.create_uid = res_users.id) WHERE %s.id IN %s" %
233 # (obj._table, obj._table, obj._table, obj._table, tuple(ids),))
234 cr.execute("SELECT id, COALESCE(create_uid, 1) FROM %s " % obj._table + "WHERE id in %s", (tuple(ids),))
235 # Execute the function once per user_id
236 user_id_map = {}
237 for row in cr.fetchall():
238 user_id_map.setdefault(row[1], []).append(row[0])
239 for user_id in user_id_map:
240 write_value(
241 user_id_map[user_id], field,
242 obj._defaults[field](obj, cr, user_id, None))
187 else:243 else:
188 # existence users is covered by foreign keys, so this is not needed244 error = ("OpenUpgrade: error setting default, field %s with "
189 # cr.execute("SELECT %s.id, res_users.id FROM %s LEFT OUTER JOIN res_users ON (%s.create_uid = res_users.id) WHERE %s.id IN %s" %245 "None default value not in %s' _defaults" % (
190 # (obj._table, obj._table, obj._table, obj._table, tuple(ids),))246 field, model))
191 cr.execute("SELECT id, COALESCE(create_uid, 1) FROM %s " % obj._table + "WHERE id in %s", (tuple(ids),))247 logger.error(error)
192 fetchdict = dict(cr.fetchall())248 # this exeption seems to get lost in a higher up try block
193 for id in ids:249 osv.except_osv("OpenUpgrade", error)
194 write_value([id], field, obj._defaults[field](obj, cr, fetchdict.get(id, 1), None))
195 if id not in fetchdict:
196 logger.info("model %s, field %s, id %d: no create_uid defined or user does not exist anymore",
197 model, field, id)
198 else:250 else:
199 error = ("OpenUpgrade: error setting default, field %s with "251 write_value(ids, field, value)
200 "None default value not in %s' _defaults" % (
201 field, model))
202 logger.error(error)
203 # this exeption seems to get lost in a higher up try block
204 osv.except_osv("OpenUpgrade", error)
205 else:
206 write_value(ids, field, value)
207 252
208def logged_query(cr, query, args=None):253def logged_query(cr, query, args=None):
209 if args is None:254 if args is None:
@@ -257,3 +302,63 @@
257 query = 'ALTER TABLE ir_model_fields ADD COLUMN %s %s' % (302 query = 'ALTER TABLE ir_model_fields ADD COLUMN %s %s' % (
258 column)303 column)
259 logged_query(cr, query, [])304 logged_query(cr, query, [])
305
306def add_module_dependencies(cr, module_list):
307 """
308 Select (new) dependencies from the modules in the list
309 so that we can inject them into the graph at upgrade
310 time. Used in the modified OpenUpgrade Server,
311 not to be used in migration scripts
312 """
313 if not module_list:
314 return module_list
315 cr.execute("""
316 SELECT ir_module_module_dependency.name
317 FROM
318 ir_module_module,
319 ir_module_module_dependency
320 WHERE
321 module_id = ir_module_module.id
322 AND ir_module_module.name in %s
323 """, (tuple(module_list),))
324 dependencies = [x[0] for x in cr.fetchall()]
325 return list(set(module_list + dependencies))
326
327def migrate():
328 """
329 This is the decorator for the migrate() function
330 in migration scripts.
331 Return when the 'version' argument is not defined,
332 and log execeptions.
333 Retrieve debug context data from the frame above for
334 logging purposes.
335 """
336 def wrap(func):
337 def wrapped_function(cr, version):
338 stage = 'unknown'
339 module = 'unknown'
340 filename = 'unknown'
341 try:
342 frame = inspect.getargvalues(inspect.stack()[1][0])
343 stage = frame.locals['stage']
344 module = frame.locals['pkg'].name
345 filename = frame.locals['fp'].name
346 except Exception, e:
347 logger.error(
348 "'migrate' decorator: failed to inspect "
349 "the frame above: %s" % e)
350 pass
351 if not version:
352 return
353 logger.info(
354 "%s: %s-migration script called with version %s" %
355 (module, stage, version))
356 try:
357 # The actual function is called here
358 func(cr, version)
359 except Exception, e:
360 logger.error(
361 "%s: error in migration script %s: %s" %
362 (module, filename, e))
363 return wrapped_function
364 return wrap

Subscribers

People subscribed via source and target branches