Merge lp:~therp-nl/openupgrade-server/5.0-use_orm into lp:openupgrade-server/5.0
- 5.0-use_orm
- Merge into 5.0
Proposed by
Stefan Rijnhart (Opener)
Status: | Merged |
---|---|
Merged at revision: | 2176 |
Proposed branch: | lp:~therp-nl/openupgrade-server/5.0-use_orm |
Merge into: | lp:openupgrade-server/5.0 |
Diff against target: |
1699 lines (+1461/-53) 23 files modified
bin/addons/__init__.py (+135/-52) bin/addons/base/ir/ir_model.py (+6/-0) bin/addons/openupgrade_records/__init__.py (+2/-0) bin/addons/openupgrade_records/__openerp__.py (+63/-0) bin/addons/openupgrade_records/__terp__.py (+63/-0) bin/addons/openupgrade_records/model/__init__.py (+6/-0) bin/addons/openupgrade_records/model/analysis_wizard.py (+178/-0) bin/addons/openupgrade_records/model/comparison_config.py (+98/-0) bin/addons/openupgrade_records/model/generate_records_wizard.py (+90/-0) bin/addons/openupgrade_records/model/install_all_wizard.py (+113/-0) bin/addons/openupgrade_records/model/openupgrade_record.py (+111/-0) bin/addons/openupgrade_records/security/ir.model.access.csv (+3/-0) bin/addons/openupgrade_records/view/analysis_wizard.xml (+30/-0) bin/addons/openupgrade_records/view/comparison_config.xml (+62/-0) bin/addons/openupgrade_records/view/generate_records_wizard.xml (+52/-0) bin/addons/openupgrade_records/view/install_all_wizard.xml (+54/-0) bin/addons/openupgrade_records/view/openupgrade_record.xml (+65/-0) bin/openupgrade/doc/readme.txt (+2/-0) bin/openupgrade/openupgrade.py (+259/-0) bin/openupgrade/openupgrade_log.py (+56/-0) bin/openupgrade/openupgrade_tools.py (+8/-0) bin/tools/convert.py (+3/-0) bin/tools/sql.py (+2/-1) |
To merge this branch: | bzr merge lp:~therp-nl/openupgrade-server/5.0-use_orm |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenUpgrade Committers | Pending | ||
Review via email: mp+105195@code.launchpad.net |
Commit message
Description of the change
This merge constitutes the refactoring of the database layout analysis and the inclusion of the analysis files for 5.0, as described here:
https:/
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
1 | === modified file 'bin/addons/__init__.py' |
2 | --- bin/addons/__init__.py 2011-11-30 22:57:11 +0000 |
3 | +++ bin/addons/__init__.py 2012-05-09 12:36:18 +0000 |
4 | @@ -41,6 +41,15 @@ |
5 | |
6 | logger = netsvc.Logger() |
7 | |
8 | +### OpenUpgrade |
9 | +def table_exists(cr, table): |
10 | + """ Check whether a certain table or view exists """ |
11 | + cr.execute( |
12 | + 'SELECT count(relname) FROM pg_class WHERE relname = %s', |
13 | + (table,)) |
14 | + return cr.fetchone()[0] == 1 |
15 | +### End of OpenUpgrade |
16 | + |
17 | _ad = os.path.abspath(opj(tools.config['root_path'], 'addons')) # default addons path (base) |
18 | ad = os.path.abspath(tools.config['addons_path']) # alternate addons path |
19 | |
20 | @@ -571,12 +580,133 @@ |
21 | modobj = None |
22 | |
23 | import string |
24 | + |
25 | + local_registry = {} |
26 | def get_repr(properties, type='val'): |
27 | + """ |
28 | + OpenUpgrade: Return the string representation of the model or field |
29 | + for logging purposes |
30 | + """ |
31 | if type == 'key': |
32 | props = ['model', 'field'] |
33 | elif type == 'val': |
34 | - props = ['type', 'isfunction', 'relation', 'required', 'selection_keys', 'req_default', 'inherits'] |
35 | - return ','.join(["\"" + string.replace(properties[prop], '\"', '\'') + "\"" for prop in props]) |
36 | + props = [ |
37 | + 'type', 'isfunction', 'relation', 'required', 'selection_keys', |
38 | + 'req_default', 'inherits' |
39 | + ] |
40 | + return ','.join([ |
41 | + '\"' + string.replace( |
42 | + string.replace( |
43 | + properties[prop], '\"', '\''), '\n','') |
44 | + + '\"' for prop in props |
45 | + ]) |
46 | + |
47 | + def log_model(model): |
48 | + """ |
49 | + OpenUpgrade: Store the characteristics of the BaseModel and its fields |
50 | + in the local registry, so that we can compare changes with the |
51 | + main registry |
52 | + """ |
53 | + |
54 | + # persistent models only |
55 | + if isinstance(model, osv.osv.osv_memory): |
56 | + return |
57 | + |
58 | + model_registry = local_registry.setdefault( |
59 | + model._name, {}) |
60 | + if model._inherits: |
61 | + model_registry['_inherits'] = {'_inherits': unicode(model._inherits)} |
62 | + for k, v in model._columns.items(): |
63 | + properties = { |
64 | + 'type': v._type, |
65 | + 'isfunction': ( |
66 | + isinstance(v, osv.fields.function) and 'function' or ''), |
67 | + 'relation': ( |
68 | + v._type in ('many2many', 'many2one','one2many') |
69 | + and v._obj or '' |
70 | + ), |
71 | + 'required': v.required and 'required' or '', |
72 | + 'selection_keys': '', |
73 | + 'req_default': '', |
74 | + 'inherits': '', |
75 | + } |
76 | + if v._type == 'selection': |
77 | + if hasattr(v.selection, "__iter__"): |
78 | + properties['selection_keys'] = unicode( |
79 | + sorted([x[0] for x in v.selection])) |
80 | + else: |
81 | + properties['selection_keys'] = 'function' |
82 | + if v.required and k in model._defaults: |
83 | + if isinstance(model._defaults[k], types.FunctionType): |
84 | + # todo: in OpenERP 5 (and in 6 as well), |
85 | + # literals are wrapped in a lambda function. |
86 | + properties['req_default'] = 'function' |
87 | + else: |
88 | + properties['req_default'] = unicode(model._defaults[k]) |
89 | + for key, value in properties.items(): |
90 | + if value: |
91 | + model_registry.setdefault(k, {})[key] = value |
92 | + |
93 | + def get_record_id(cr, module, model, field, mode): |
94 | + """ |
95 | + OpenUpgrade: get or create the id from the record table matching |
96 | + the key parameter values |
97 | + """ |
98 | + cr.execute( |
99 | + "SELECT id FROM openupgrade_record " |
100 | + "WHERE module = %s AND model = %s AND " |
101 | + "field = %s AND mode = %s AND type = %s", |
102 | + (module, model, field, mode, 'field') |
103 | + ) |
104 | + record = cr.fetchone() |
105 | + if record: |
106 | + return record[0] |
107 | + cr.execute( |
108 | + "INSERT INTO openupgrade_record " |
109 | + "(module, model, field, mode, type) " |
110 | + "VALUES (%s, %s, %s, %s, %s)", |
111 | + (module, model, field, mode, 'field') |
112 | + ) |
113 | + cr.execute( |
114 | + "SELECT id FROM openupgrade_record " |
115 | + "WHERE module = %s AND model = %s AND " |
116 | + "field = %s AND mode = %s AND type = %s", |
117 | + (module, model, field, mode, 'field') |
118 | + ) |
119 | + return cr.fetchone()[0] |
120 | + |
121 | + def compare_registries(cr, module): |
122 | + """ |
123 | + OpenUpgrade: Compare the local registry with the global registry, |
124 | + log any differences and merge the local registry with |
125 | + the global one. |
126 | + """ |
127 | + if not table_exists(cr, 'openupgrade_record'): |
128 | + return |
129 | + for model, fields in local_registry.items(): |
130 | + registry.setdefault(model, {}) |
131 | + for field, attributes in fields.items(): |
132 | + old_field = registry[model].setdefault(field, {}) |
133 | + mode = old_field and 'modify' or 'create' |
134 | + record_id = False |
135 | + for key, value in attributes.items(): |
136 | + if key not in old_field or old_field[key] != value: |
137 | + if not record_id: |
138 | + record_id = get_record_id( |
139 | + cr, module, model, field, mode) |
140 | + cr.execute( |
141 | + "SELECT id FROM openupgrade_attribute " |
142 | + "WHERE name = %s AND value = %s AND " |
143 | + "record_id = %s", |
144 | + (key, value, record_id) |
145 | + ) |
146 | + if not cr.fetchone(): |
147 | + cr.execute( |
148 | + "INSERT INTO openupgrade_attribute " |
149 | + "(name, value, record_id) VALUES (%s, %s, %s)", |
150 | + (key, value, record_id) |
151 | + ) |
152 | + old_field[key] = value |
153 | |
154 | for package in graph: |
155 | logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading objects' % package.name) |
156 | @@ -584,53 +714,10 @@ |
157 | register_class(package.name) |
158 | modules = pool.instanciate(package.name, cr) |
159 | |
160 | - logger.notifyChannel('OpenUpgrade_FIELD', netsvc.LOG_INFO, 'module %s' % (package.name)) |
161 | local_registry = {} |
162 | - for orm_object in osv.orm.orm: |
163 | - if orm_object._inherits: |
164 | - properties = { |
165 | - 'model': orm_object._name, |
166 | - 'field': '_inherits', |
167 | - 'type': '', |
168 | - 'isfunction': '', |
169 | - 'relation': '', |
170 | - 'required': '', |
171 | - 'selection_keys': '', |
172 | - 'req_default': '', |
173 | - 'inherits': unicode(orm_object._inherits), |
174 | - } |
175 | - local_registry[get_repr(properties, 'key')] = get_repr(properties) |
176 | - for k,v in orm_object._columns.items(): |
177 | - properties = { |
178 | - 'model': orm_object._name, |
179 | - 'field': k, |
180 | - 'type': v._type, |
181 | - 'isfunction': isinstance(v, osv.fields.function) and 'function' or '', |
182 | - 'relation': v._type in ('many2many', 'many2one','one2many') and v._obj or '', |
183 | - 'required': v.required and 'required' or '', |
184 | - 'selection_keys': '', |
185 | - 'req_default': '', |
186 | - 'inherits': '', |
187 | - } |
188 | - if v._type == 'selection': |
189 | - if hasattr(v.selection, "__iter__"): |
190 | - properties['selection_keys'] = unicode(sorted([x[0] for x in v.selection])) |
191 | - else: |
192 | - properties['selection_keys'] = 'function' |
193 | - if v.required and k in orm_object._defaults: |
194 | - if isinstance(orm_object._defaults[k], types.FunctionType): |
195 | - properties['req_default'] = 'function' |
196 | - else: |
197 | - properties['req_default'] = unicode(orm_object._defaults[k]) |
198 | - local_registry[get_repr(properties, 'key')] = get_repr(properties) |
199 | - for key in sorted(local_registry.keys()): |
200 | - if key in registry: |
201 | - if registry[key] != local_registry[key]: |
202 | - logger.notifyChannel('OpenUpgrade_FIELD', netsvc.LOG_INFO, '"%s","modify",%s,%s' % (package.name, key, local_registry[key])) |
203 | - else: |
204 | - logger.notifyChannel('OpenUpgrade_FIELD', netsvc.LOG_INFO, '"%s","create",%s,%s' % (package.name, key, local_registry[key])) |
205 | - registry[key] = local_registry[key] |
206 | - |
207 | + for model in modules: |
208 | + log_model(model) |
209 | + compare_registries(cr, package.name) |
210 | if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'): |
211 | init_module_objects(cr, package.name, modules) |
212 | cr.commit() |
213 | @@ -712,10 +799,6 @@ |
214 | delattr(package, kind) |
215 | |
216 | statusi += 1 |
217 | - cr.execute('select model, name from ir_model_data where module=%s order by model, name', (package.name,)) |
218 | - for res in cr.fetchall(): |
219 | - xmlid_repr = ','.join(["\"" + string.replace(property, '\"', '\'') + "\"" for property in (res[0], res[1], package.name)]) |
220 | - logger.notifyChannel('OpenUpgrade_XMLID', netsvc.LOG_INFO, xmlid_repr) |
221 | |
222 | cr.execute('select model from ir_model where state=%s', ('manual',)) |
223 | for model in cr.dictfetchall(): |
224 | |
225 | === modified file 'bin/addons/base/ir/ir_model.py' |
226 | --- bin/addons/base/ir/ir_model.py 2010-05-18 09:30:44 +0000 |
227 | +++ bin/addons/base/ir/ir_model.py 2012-05-09 12:36:18 +0000 |
228 | @@ -31,6 +31,8 @@ |
229 | from tools.translate import _ |
230 | import pooler |
231 | |
232 | +from openupgrade import openupgrade_log |
233 | + |
234 | def _get_fields_type(self, cr, uid, context=None): |
235 | cr.execute('select distinct ttype,ttype from ir_model_fields') |
236 | return cr.fetchall() |
237 | @@ -459,6 +461,10 @@ |
238 | return id |
239 | |
240 | def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): |
241 | + #OpenUpgrade: log entry (used in csv import) |
242 | + if xml_id: |
243 | + openupgrade_log.log_xml_id(cr, module, xml_id) |
244 | + |
245 | warning = True |
246 | model_obj = self.pool.get(model) |
247 | if not context: |
248 | |
249 | === added directory 'bin/addons/openupgrade_records' |
250 | === added file 'bin/addons/openupgrade_records/__init__.py' |
251 | --- bin/addons/openupgrade_records/__init__.py 1970-01-01 00:00:00 +0000 |
252 | +++ bin/addons/openupgrade_records/__init__.py 2012-05-09 12:36:18 +0000 |
253 | @@ -0,0 +1,2 @@ |
254 | +import model |
255 | +import lib |
256 | |
257 | === added file 'bin/addons/openupgrade_records/__openerp__.py' |
258 | --- bin/addons/openupgrade_records/__openerp__.py 1970-01-01 00:00:00 +0000 |
259 | +++ bin/addons/openupgrade_records/__openerp__.py 2012-05-09 12:36:18 +0000 |
260 | @@ -0,0 +1,63 @@ |
261 | +# -*- coding: utf-8 -*- |
262 | +############################################################################## |
263 | +# |
264 | +# OpenERP, Open Source Management Solution |
265 | +# This module Copyright (C) 2012 OpenUpgrade community |
266 | +# https://launchpad.net/~openupgrade-committers |
267 | +# |
268 | +# Contributors: |
269 | +# Therp BV <http://therp.nl> |
270 | +# |
271 | +# This program is free software: you can redistribute it and/or modify |
272 | +# it under the terms of the GNU Affero General Public License as |
273 | +# published by the Free Software Foundation, either version 3 of the |
274 | +# License, or (at your option) any later version. |
275 | +# |
276 | +# This program is distributed in the hope that it will be useful, |
277 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
278 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
279 | +# GNU Affero General Public License for more details. |
280 | +# |
281 | +# You should have received a copy of the GNU Affero General Public License |
282 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
283 | +# |
284 | +############################################################################## |
285 | + |
286 | + |
287 | +{ |
288 | + 'name': 'OpenUpgrade Records', |
289 | + 'version': '0.2', |
290 | + 'category': 'Normal', |
291 | + 'description': """Allow OpenUpgrade records to be |
292 | +stored in the database and compare with other servers. |
293 | + |
294 | +This module depends on OpenERP client lib: |
295 | + |
296 | + easy_install openerp-client-lib |
297 | + |
298 | +""", |
299 | + 'author': 'OpenUpgrade Community', |
300 | + 'maintainer': 'OpenUpgrade Community', |
301 | + 'contributors': ['Therp BV'], |
302 | + 'website': 'https://launchpad.net/~openupgrade-committers', |
303 | + 'depends': [], |
304 | + 'init_xml': [], |
305 | + 'update_xml': [ |
306 | + 'view/openupgrade_record.xml', |
307 | + 'view/comparison_config.xml', |
308 | + 'view/analysis_wizard.xml', |
309 | + 'view/generate_records_wizard.xml', |
310 | + 'view/install_all_wizard.xml', |
311 | + 'security/ir.model.access.csv', |
312 | + ], |
313 | + 'demo_xml': [ |
314 | + ], |
315 | + 'test': [ |
316 | + ], |
317 | + 'installable': True, |
318 | + 'auto_install': False, |
319 | + 'external_dependencies': { |
320 | + 'python' : ['openerplib'], |
321 | + }, |
322 | +} |
323 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
324 | |
325 | === added file 'bin/addons/openupgrade_records/__terp__.py' |
326 | --- bin/addons/openupgrade_records/__terp__.py 1970-01-01 00:00:00 +0000 |
327 | +++ bin/addons/openupgrade_records/__terp__.py 2012-05-09 12:36:18 +0000 |
328 | @@ -0,0 +1,63 @@ |
329 | +# -*- coding: utf-8 -*- |
330 | +############################################################################## |
331 | +# |
332 | +# OpenERP, Open Source Management Solution |
333 | +# This module Copyright (C) 2012 OpenUpgrade community |
334 | +# https://launchpad.net/~openupgrade-committers |
335 | +# |
336 | +# Contributors: |
337 | +# Therp BV <http://therp.nl> |
338 | +# |
339 | +# This program is free software: you can redistribute it and/or modify |
340 | +# it under the terms of the GNU Affero General Public License as |
341 | +# published by the Free Software Foundation, either version 3 of the |
342 | +# License, or (at your option) any later version. |
343 | +# |
344 | +# This program is distributed in the hope that it will be useful, |
345 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
346 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
347 | +# GNU Affero General Public License for more details. |
348 | +# |
349 | +# You should have received a copy of the GNU Affero General Public License |
350 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
351 | +# |
352 | +############################################################################## |
353 | + |
354 | + |
355 | +{ |
356 | + 'name': 'OpenUpgrade Records', |
357 | + 'version': '0.2', |
358 | + 'category': 'Normal', |
359 | + 'description': """Allow OpenUpgrade records to be |
360 | +stored in the database and compare with other servers. |
361 | + |
362 | +This module depends on OpenERP client lib: |
363 | + |
364 | + easy_install openerp-client-lib |
365 | + |
366 | +""", |
367 | + 'author': 'OpenUpgrade Community', |
368 | + 'maintainer': 'OpenUpgrade Community', |
369 | + 'contributors': ['Therp BV'], |
370 | + 'website': 'https://launchpad.net/~openupgrade-committers', |
371 | + 'depends': [], |
372 | + 'init_xml': [], |
373 | + 'update_xml': [ |
374 | + 'view/openupgrade_record.xml', |
375 | + 'view/comparison_config.xml', |
376 | + 'view/analysis_wizard.xml', |
377 | + 'view/generate_records_wizard.xml', |
378 | + 'view/install_all_wizard.xml', |
379 | + 'security/ir.model.access.csv', |
380 | + ], |
381 | + 'demo_xml': [ |
382 | + ], |
383 | + 'test': [ |
384 | + ], |
385 | + 'installable': True, |
386 | + 'auto_install': False, |
387 | + 'external_dependencies': { |
388 | + 'python' : ['openerplib'], |
389 | + }, |
390 | +} |
391 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
392 | |
393 | === added directory 'bin/addons/openupgrade_records/model' |
394 | === added file 'bin/addons/openupgrade_records/model/__init__.py' |
395 | --- bin/addons/openupgrade_records/model/__init__.py 1970-01-01 00:00:00 +0000 |
396 | +++ bin/addons/openupgrade_records/model/__init__.py 2012-05-09 12:36:18 +0000 |
397 | @@ -0,0 +1,6 @@ |
398 | +import openupgrade_record |
399 | +import comparison_config |
400 | +import analysis_wizard |
401 | +import generate_records_wizard |
402 | +import install_all_wizard |
403 | + |
404 | |
405 | === added file 'bin/addons/openupgrade_records/model/analysis_wizard.py' |
406 | --- bin/addons/openupgrade_records/model/analysis_wizard.py 1970-01-01 00:00:00 +0000 |
407 | +++ bin/addons/openupgrade_records/model/analysis_wizard.py 2012-05-09 12:36:18 +0000 |
408 | @@ -0,0 +1,178 @@ |
409 | +# -*- coding: utf-8 -*- |
410 | +############################################################################## |
411 | +# |
412 | +# OpenERP, Open Source Management Solution |
413 | +# This module Copyright (C) 2012 OpenUpgrade community |
414 | +# https://launchpad.net/~openupgrade-committers |
415 | +# |
416 | +# Contributors: |
417 | +# Therp BV <http://therp.nl> |
418 | +# |
419 | +# This program is free software: you can redistribute it and/or modify |
420 | +# it under the terms of the GNU Affero General Public License as |
421 | +# published by the Free Software Foundation, either version 3 of the |
422 | +# License, or (at your option) any later version. |
423 | +# |
424 | +# This program is distributed in the hope that it will be useful, |
425 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
426 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
427 | +# GNU Affero General Public License for more details. |
428 | +# |
429 | +# You should have received a copy of the GNU Affero General Public License |
430 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
431 | +# |
432 | +############################################################################## |
433 | + |
434 | +import os |
435 | +from osv import osv, fields |
436 | + |
437 | +try: |
438 | + from openerp.addons.openupgrade_records.lib import compare |
439 | + from openerp.openupgrade_records.lib import apriori |
440 | + from openerp.addons import get_module_path |
441 | +except ImportError: |
442 | + from openupgrade_records.lib import compare |
443 | + from openupgrade_records.lib import apriori |
444 | + from addons import get_module_path |
445 | + |
446 | +class openupgrade_analysis_wizard(osv.osv_memory): |
447 | + _name = 'openupgrade.analysis.wizard' |
448 | + _description = 'OpenUpgrade Analysis Wizard' |
449 | + _columns = { |
450 | + 'server_config': fields.many2one( |
451 | + 'openupgrade.comparison.config', |
452 | + 'Configuration', required=True), |
453 | + 'state': fields.selection( |
454 | + [('init', 'Init'), ('ready', 'Ready')], 'State', |
455 | + readonly=True), |
456 | + 'log': fields.text('Log'), |
457 | + 'write': fields.boolean( |
458 | + 'Write files', |
459 | + help='Write analysis files to the module directories' |
460 | + ), |
461 | + } |
462 | + _defaults = { |
463 | + 'state': lambda *a: 'init', |
464 | + 'write': lambda *a: True, |
465 | + } |
466 | + |
467 | + def get_communication(self, cr, uid, ids, context=None): |
468 | + """ |
469 | + Retrieve both sets of database representations, |
470 | + perform the comparison and register the resulting |
471 | + change set |
472 | + """ |
473 | + def write_file( |
474 | + module, version, contents, filename='openupgrade_analysis.txt'): |
475 | + module_path = get_module_path(module) |
476 | + if not module_path: |
477 | + return "ERROR: could not find module path:\n" |
478 | + full_path = os.path.join( |
479 | + module_path, 'migrations', version) |
480 | + if not os.path.exists(full_path): |
481 | + try: |
482 | + os.makedirs(full_path) |
483 | + except os.error: |
484 | + return "ERROR: could not create migrations directory:\n" |
485 | + logfile = os.path.join(full_path, filename) |
486 | + try: |
487 | + f = open(logfile, 'w') |
488 | + except Exception: |
489 | + return "ERROR: could not open file %s for writing:\n" % logfile |
490 | + f.write(contents) |
491 | + f.close() |
492 | + return None |
493 | + |
494 | + wizard = self.browse(cr, uid, ids[0], context=context) |
495 | + # Retrieve connection and access methods |
496 | + conf_obj = self.pool.get('openupgrade.comparison.config') |
497 | + connection = conf_obj.get_connection( |
498 | + cr, uid, [wizard.server_config.id], context=context) |
499 | + remote_record_obj = connection.get_model('openupgrade.record') |
500 | + local_record_obj = self.pool.get('openupgrade.record') |
501 | + |
502 | + # Retrieve field representations and compare |
503 | + remote_records = remote_record_obj.field_dump(context) |
504 | + local_records = local_record_obj.field_dump(cr, uid, context) |
505 | + res = compare.compare_sets(remote_records, local_records) |
506 | + |
507 | + # Retrieve xml id representations and compare |
508 | + fields = ['module', 'model', 'name'] |
509 | + local_xml_record_ids = local_record_obj.search( |
510 | + cr, uid, [('type', '=', 'xmlid')]) |
511 | + remote_xml_record_ids = remote_record_obj.search( |
512 | + [('type', '=', 'xmlid')]) |
513 | + local_xml_records = [ |
514 | + dict([(field, x[field]) for field in fields]) |
515 | + for x in local_record_obj.read( |
516 | + cr, uid, local_xml_record_ids, fields) |
517 | + ] |
518 | + remote_xml_records = [ |
519 | + dict([(field, x[field]) for field in fields]) |
520 | + for x in remote_record_obj.read( |
521 | + remote_xml_record_ids, fields) |
522 | + ] |
523 | + res_xml = compare.compare_xml_sets( |
524 | + remote_xml_records, local_xml_records) |
525 | + |
526 | + # reorder and output the result |
527 | + keys = list(set(res.keys() + res_xml.keys())) |
528 | + keys.remove('general') |
529 | + keys = ['general'] + keys |
530 | + module_obj = self.pool.get('ir.module.module') |
531 | + module_ids = module_obj.search( |
532 | + cr, uid, [('state', '=', 'installed')]) |
533 | + modules = dict([(x['name'], x) for x in module_obj.read(cr, uid, module_ids)]) |
534 | + general = '' |
535 | + for key in keys: |
536 | + contents = "---%s---\n" % key |
537 | + if key in res: |
538 | + contents += '\n'.join([unicode(line) for line in sorted(res[key])]) |
539 | + if res[key]: |
540 | + contents += '\n' |
541 | + if key in res_xml: |
542 | + contents += '\n'.join([unicode(line) for line in sorted(res_xml[key])]) |
543 | + if res_xml[key]: |
544 | + contents += '\n' |
545 | + if key == 'general': |
546 | + general += contents |
547 | + continue |
548 | + if key not in modules: |
549 | + general += ( |
550 | + "ERROR: module not in list of installed modules:\n" |
551 | + + contents) |
552 | + continue |
553 | + if wizard.write: |
554 | + error = write_file( |
555 | + key, modules[key]['installed_version'], contents) |
556 | + if error: |
557 | + general += error |
558 | + general += contents |
559 | + else: |
560 | + general += contents |
561 | + |
562 | + # Store the general log in as many places as possible ;-) |
563 | + if wizard.write and 'base' in modules: |
564 | + write_file( |
565 | + 'base', modules['base']['installed_version'], general, |
566 | + 'openupgrade_general_log.txt') |
567 | + self.pool.get('openupgrade.comparison.config').write( |
568 | + cr, uid, wizard.server_config.id, |
569 | + {'last_log': general}) |
570 | + self.write(cr, uid, ids, {'state': 'ready', 'log': general}) |
571 | + |
572 | + result = { |
573 | + 'name': self._description, |
574 | + 'view_type': 'form', |
575 | + 'view_mode': 'form', |
576 | + 'res_model': 'openupgrade.analysis.wizard', |
577 | + 'domain': [], |
578 | + 'context': context, |
579 | + 'type': 'ir.actions.act_window', |
580 | + #'target': 'new', |
581 | + 'res_id': ids[0], |
582 | + } |
583 | + return result |
584 | + |
585 | +openupgrade_analysis_wizard() |
586 | + |
587 | |
588 | === added file 'bin/addons/openupgrade_records/model/comparison_config.py' |
589 | --- bin/addons/openupgrade_records/model/comparison_config.py 1970-01-01 00:00:00 +0000 |
590 | +++ bin/addons/openupgrade_records/model/comparison_config.py 2012-05-09 12:36:18 +0000 |
591 | @@ -0,0 +1,98 @@ |
592 | +# -*- coding: utf-8 -*- |
593 | +############################################################################## |
594 | +# |
595 | +# OpenERP, Open Source Management Solution |
596 | +# This module Copyright (C) 2012 OpenUpgrade community |
597 | +# https://launchpad.net/~openupgrade-committers |
598 | +# |
599 | +# Contributors: |
600 | +# Therp BV <http://therp.nl> |
601 | +# |
602 | +# This program is free software: you can redistribute it and/or modify |
603 | +# it under the terms of the GNU Affero General Public License as |
604 | +# published by the Free Software Foundation, either version 3 of the |
605 | +# License, or (at your option) any later version. |
606 | +# |
607 | +# This program is distributed in the hope that it will be useful, |
608 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
609 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
610 | +# GNU Affero General Public License for more details. |
611 | +# |
612 | +# You should have received a copy of the GNU Affero General Public License |
613 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
614 | +# |
615 | +############################################################################## |
616 | + |
617 | +from osv import osv, fields |
618 | +import openerplib |
619 | +from tools.translate import _ |
620 | + |
621 | +class openupgrade_comparison_config(osv.osv): |
622 | + _name = 'openupgrade.comparison.config' |
623 | + _columns = { |
624 | + 'name': fields.char('Name', size=64), |
625 | + 'server': fields.char('Server', size=64, required=True), |
626 | + 'port': fields.integer('Port', required=True), |
627 | + 'protocol': fields.selection( |
628 | + [('http://', 'XML-RPC')], |
629 | + # ('https://', 'XML-RPC Secure')], not supported by libopenerp |
630 | + 'Protocol', required=True), |
631 | + 'database': fields.char('Database', size=64, required=True), |
632 | + 'username': fields.char('Username', size=24, required=True), |
633 | + 'password': fields.char('Password', size=24, required=True, password=True), |
634 | + 'last_log': fields.text('Last log'), |
635 | + } |
636 | + _defaults = { |
637 | + 'port': lambda *a: 8069, |
638 | + 'protocol': lambda *a: 'http://', |
639 | + } |
640 | + |
641 | + def get_connection(self, cr, uid, ids, context=None): |
642 | + if not ids: |
643 | + raise osv.except_osv( |
644 | + _("Cannot connect"), _("Invalid id passed.")) |
645 | + conf = self.read(cr, uid, ids[0], context=None) |
646 | + return openerplib.get_connection( |
647 | + hostname=conf['server'], |
648 | + database=conf['database'], |
649 | + login=conf['username'], |
650 | + password=conf['password'], |
651 | + port=conf['port'], |
652 | + ) |
653 | + |
654 | + def test_connection(self, cr, uid, ids, context=None): |
655 | + try: |
656 | + connection = self.get_connection(cr, uid, [ids[0]], context) |
657 | + user_model = connection.get_model("res.users") |
658 | + ids = user_model.search([("login", "=", "admin")]) |
659 | + user_info = user_model.read(ids[0], ["name"]) |
660 | + except Exception, e: |
661 | + raise osv.except_osv( |
662 | + _("Connection failed."), unicode(e)) |
663 | + raise osv.except_osv( |
664 | + _("Connection succesful."), |
665 | + _("%s is connected.") % user_info["name"] |
666 | + ) |
667 | + |
668 | + def analyze(self, cr, uid, ids, context=None): |
669 | + """ |
670 | + Run the analysis wizard |
671 | + """ |
672 | + wizard_obj = self.pool.get('openupgrade.analysis.wizard') |
673 | + wizard_id = wizard_obj.create( |
674 | + cr, uid, {'server_config': ids[0]}, context) |
675 | + result = { |
676 | + 'name': wizard_obj._description, |
677 | + 'view_type': 'form', |
678 | + 'view_mode': 'form', |
679 | + 'res_model': 'openupgrade.analysis.wizard', |
680 | + 'domain': [], |
681 | + 'context': context, |
682 | + 'type': 'ir.actions.act_window', |
683 | + 'target': 'new', |
684 | + 'res_id': wizard_id, |
685 | + 'nodestroy': True, |
686 | + } |
687 | + return result |
688 | + |
689 | +openupgrade_comparison_config() |
690 | |
691 | === added file 'bin/addons/openupgrade_records/model/generate_records_wizard.py' |
692 | --- bin/addons/openupgrade_records/model/generate_records_wizard.py 1970-01-01 00:00:00 +0000 |
693 | +++ bin/addons/openupgrade_records/model/generate_records_wizard.py 2012-05-09 12:36:18 +0000 |
694 | @@ -0,0 +1,90 @@ |
695 | +# -*- coding: utf-8 -*- |
696 | +############################################################################## |
697 | +# |
698 | +# OpenERP, Open Source Management Solution |
699 | +# This module Copyright (C) 2012 OpenUpgrade community |
700 | +# https://launchpad.net/~openupgrade-committers |
701 | +# |
702 | +# Contributors: |
703 | +# Therp BV <http://therp.nl> |
704 | +# |
705 | +# This program is free software: you can redistribute it and/or modify |
706 | +# it under the terms of the GNU Affero General Public License as |
707 | +# published by the Free Software Foundation, either version 3 of the |
708 | +# License, or (at your option) any later version. |
709 | +# |
710 | +# This program is distributed in the hope that it will be useful, |
711 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
712 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
713 | +# GNU Affero General Public License for more details. |
714 | +# |
715 | +# You should have received a copy of the GNU Affero General Public License |
716 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
717 | +# |
718 | +############################################################################## |
719 | + |
720 | +import os |
721 | +from osv import osv, fields |
722 | +import pooler |
723 | +try: |
724 | + from openerp.openupgrade import openupgrade_tools |
725 | +except ImportError: |
726 | + from openupgrade import openupgrade_tools |
727 | + |
728 | +class generate_records_wizard(osv.osv_memory): |
729 | + _name = 'openupgrade.generate.records.wizard' |
730 | + _description = 'OpenUpgrade Generate Records Wizard' |
731 | + _columns = { |
732 | + 'state': fields.selection([('init', 'init'), ('ready', 'ready')], 'State'), |
733 | + } |
734 | + _defaults = { |
735 | + 'state': lambda *a: 'init', |
736 | + } |
737 | + |
738 | + def generate(self, cr, uid, ids, context=None): |
739 | + """ |
740 | + Main wizard step. Make sure that all modules are up-to-date, |
741 | + then reinitialize all installed modules. |
742 | + Equivalent of running the server with '-d <database> --init all' |
743 | + |
744 | + The goal of this is to fill the records table. |
745 | + |
746 | + TODO: update module list and versions, then update all modules? |
747 | + """ |
748 | + # Truncate the records table |
749 | + if (openupgrade_tools.table_exists(cr, 'openupgrade_attribute') and |
750 | + openupgrade_tools.table_exists(cr, 'openupgrade_record')): |
751 | + cr.execute( |
752 | + 'TRUNCATE openupgrade_attribute, openupgrade_record;' |
753 | + ) |
754 | + |
755 | + # Need to get all modules in state 'installed' |
756 | + module_obj = self.pool.get('ir.module.module') |
757 | + module_ids = module_obj.search( |
758 | + cr, uid, [('state', 'in', ['to install', 'to upgrade'])]) |
759 | + if module_ids: |
760 | + cr.commit() |
761 | + _db, pool = pooler.restart_pool(cr.dbname, update_module=True) |
762 | + # Did we succeed above? |
763 | + module_ids = module_obj.search( |
764 | + cr, uid, [('state', 'in', ['to install', 'to upgrade'])]) |
765 | + if module_ids: |
766 | + modules = module_obj.read( |
767 | + cr, uid, module_ids, ['name'], context=context) |
768 | + raise except_osv( |
769 | + "Cannot reliably generate records", |
770 | + ("Cannot seem to install or upgrade modules " + |
771 | + ', '.join([x['name'] for x in modules]))) |
772 | + # Now reinitialize all installed modules |
773 | + module_ids = module_obj.search( |
774 | + cr, uid, [('state', '=', 'installed')]) |
775 | + module_obj.write( |
776 | + cr, uid, module_ids, {'state': 'to install'}) |
777 | + cr.commit() |
778 | + _db, pool = pooler.restart_pool(cr.dbname, update_module=True) |
779 | + self.write(cr, uid, ids, {'state': 'ready'}) |
780 | + # and we are done |
781 | + return True |
782 | + |
783 | +generate_records_wizard() |
784 | + |
785 | |
786 | === added file 'bin/addons/openupgrade_records/model/install_all_wizard.py' |
787 | --- bin/addons/openupgrade_records/model/install_all_wizard.py 1970-01-01 00:00:00 +0000 |
788 | +++ bin/addons/openupgrade_records/model/install_all_wizard.py 2012-05-09 12:36:18 +0000 |
789 | @@ -0,0 +1,113 @@ |
790 | +# -*- coding: utf-8 -*- |
791 | +############################################################################## |
792 | +# |
793 | +# OpenERP, Open Source Management Solution |
794 | +# This module Copyright (C) 2012 OpenUpgrade community |
795 | +# https://launchpad.net/~openupgrade-committers |
796 | +# |
797 | +# Contributors: |
798 | +# Therp BV <http://therp.nl> |
799 | +# |
800 | +# This program is free software: you can redistribute it and/or modify |
801 | +# it under the terms of the GNU Affero General Public License as |
802 | +# published by the Free Software Foundation, either version 3 of the |
803 | +# License, or (at your option) any later version. |
804 | +# |
805 | +# This program is distributed in the hope that it will be useful, |
806 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
807 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
808 | +# GNU Affero General Public License for more details. |
809 | +# |
810 | +# You should have received a copy of the GNU Affero General Public License |
811 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
812 | +# |
813 | +############################################################################## |
814 | + |
815 | +import time |
816 | +import os |
817 | +from osv import osv, fields |
818 | +import pooler |
819 | + |
820 | +class install_all_wizard(osv.osv_memory): |
821 | + _name = 'openupgrade.install.all.wizard' |
822 | + _description = 'OpenUpgrade Install All Wizard' |
823 | + _columns = { |
824 | + 'state': fields.selection([('init', 'init'), ('ready', 'ready')], 'State', readonly=True), |
825 | + 'to_install': fields.integer('Number of modules to install', readonly=True), |
826 | + } |
827 | + _defaults = { |
828 | + 'state': lambda *a: 'init', |
829 | + } |
830 | + |
831 | + |
832 | + def default_get(self, cr, uid, fields, context=None): |
833 | + """ |
834 | + Update module list and retrieve the number |
835 | + of installable modules |
836 | + """ |
837 | + res = super(install_all_wizard, self).default_get( |
838 | + cr, uid, fields, context=None) |
839 | + module_obj = self.pool.get('ir.module.module') |
840 | + update, add = module_obj.update_list(cr, uid,) |
841 | + print "%s modules added" % add |
842 | + module_ids = module_obj.search( |
843 | + cr, uid, [('state', 'not in', ['installed', 'uninstallable', 'unknown'])]) |
844 | + res.update( |
845 | + {'to_install': module_ids and len(module_ids) or False} |
846 | + ) |
847 | + return res |
848 | + |
849 | + def quirk_fiscalyear(self, cr, uid, ids, context=None): |
850 | + """ |
851 | + Install account module first and create a fiscal year, |
852 | + in order to prevent "No fiscal year defined" exception |
853 | + during an upgrade or reinstallation of the account module. |
854 | + |
855 | + Refer to account_fiscalyear.find(), which is called as |
856 | + a default function by the orm upon module upgrade. |
857 | + """ |
858 | + module_obj = self.pool.get('ir.module.module') |
859 | + pool = self.pool |
860 | + # Retrieve status of the account module |
861 | + account_module_id = module_obj.search( |
862 | + cr, uid, [('name', '=', 'account')], context=context)[0] |
863 | + state = module_obj.read( |
864 | + cr, uid, account_module_id, ['state'], context=context)['state'] |
865 | + if state != 'installed': |
866 | + # Cancel installation of other modules |
867 | + module_ids = module_obj.search( |
868 | + cr, uid, [('state', '=', 'to install')]) |
869 | + module_obj.write(cr, uid, module_ids, {'state': 'uninstalled'}) |
870 | + # Mark the module and its dependencies |
871 | + module_obj.button_install(cr, uid, [account_module_id]) |
872 | + # Install account module |
873 | + cr.commit() |
874 | + _db, pool = pooler.restart_pool(cr.dbname, update_module=True) |
875 | + # get or create today's fiscal year |
876 | + fy_obj = pool.get('account.fiscalyear') |
877 | + if not fy_obj.find(cr, uid, False, exception=False, context=context): |
878 | + fy_obj.create(cr, uid, { |
879 | + 'name': time.strftime('%Y'), |
880 | + 'code': time.strftime('%Y'), |
881 | + 'date_start': "%s-01-01" % time.strftime('%Y'), |
882 | + 'date_stop': "%s-12-31" % time.strftime('%Y'), |
883 | + }) |
884 | + |
885 | + def install_all(self, cr, uid, ids, context=None): |
886 | + """ |
887 | + Main wizard step. Set all installable modules to install |
888 | + and actually install them. |
889 | + """ |
890 | + module_obj = self.pool.get('ir.module.module') |
891 | + module_ids = module_obj.search( |
892 | + cr, uid, [('state', 'not in', ['installed', 'uninstallable', 'unknown'])]) |
893 | + if module_ids: |
894 | + module_obj.write( |
895 | + cr, uid, module_ids, {'state': 'to install'}) |
896 | + cr.commit() |
897 | + _db, pool = pooler.restart_pool(cr.dbname, update_module=True) |
898 | + self.write(cr, uid, ids, {'state': 'ready'}) |
899 | + return True |
900 | + |
901 | +install_all_wizard() |
902 | + |
903 | |
904 | === added file 'bin/addons/openupgrade_records/model/openupgrade_record.py' |
905 | --- bin/addons/openupgrade_records/model/openupgrade_record.py 1970-01-01 00:00:00 +0000 |
906 | +++ bin/addons/openupgrade_records/model/openupgrade_record.py 2012-05-09 12:36:18 +0000 |
907 | @@ -0,0 +1,111 @@ |
908 | +# -*- coding: utf-8 -*- |
909 | +############################################################################## |
910 | +# |
911 | +# OpenERP, Open Source Management Solution |
912 | +# This module Copyright (C) 2012 OpenUpgrade community |
913 | +# https://launchpad.net/~openupgrade-committers |
914 | +# |
915 | +# Contributors: |
916 | +# Therp BV <http://therp.nl> |
917 | +# |
918 | +# This program is free software: you can redistribute it and/or modify |
919 | +# it under the terms of the GNU Affero General Public License as |
920 | +# published by the Free Software Foundation, either version 3 of the |
921 | +# License, or (at your option) any later version. |
922 | +# |
923 | +# This program is distributed in the hope that it will be useful, |
924 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
925 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
926 | +# GNU Affero General Public License for more details. |
927 | +# |
928 | +# You should have received a copy of the GNU Affero General Public License |
929 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
930 | +# |
931 | +############################################################################## |
932 | + |
933 | +from osv import osv, fields |
934 | + |
935 | +# Cannot use forward references in 6.0 |
936 | +class openupgrade_record(osv.osv): |
937 | + _name = 'openupgrade.record' |
938 | +openupgrade_record() |
939 | + |
940 | +class openupgrade_attribute(osv.osv): |
941 | + _name = 'openupgrade.attribute' |
942 | + _rec_name = 'attribute_id' |
943 | + _columns = { |
944 | + 'name': fields.char( |
945 | + 'Name', size=24, |
946 | + readonly=True, |
947 | + ), |
948 | + 'value': fields.char( |
949 | + 'Value', |
950 | + size=4096, |
951 | + readonly=True, |
952 | + ), |
953 | + 'record_id': fields.many2one( |
954 | + 'openupgrade.record', ondelete='CASCADE', |
955 | + readonly=True, |
956 | + ), |
957 | + } |
958 | +openupgrade_attribute() |
959 | + |
960 | +class openupgrade_record(osv.osv): |
961 | + _inherit = 'openupgrade.record' |
962 | + |
963 | + _columns = { |
964 | + 'name': fields.char('Name', size=256, readonly=True), |
965 | + 'module': fields.char('Module', size=128, readonly=True), |
966 | + 'model': fields.char('Model', size=128, readonly=True), |
967 | + 'field': fields.char('Field', size=128, readonly=True), |
968 | + 'mode': fields.selection( |
969 | + [('create', 'Create'), ('modify', 'Modify')], |
970 | + 'Mode', |
971 | + help='Set to Create if a field is newly created ' |
972 | + 'in this module. If this module modifies an attribute of an ' |
973 | + 'exting field, set to Modify.', |
974 | + readonly=True, |
975 | + ), |
976 | + 'type': fields.selection( |
977 | + [('field', 'Field'), ('xmlid', 'XML ID')], |
978 | + 'Type', |
979 | + readonly=True, |
980 | + ), |
981 | + 'attribute_ids': fields.one2many( |
982 | + 'openupgrade.attribute', 'record_id', 'Attributes', |
983 | + readonly=True, |
984 | + ), |
985 | + } |
986 | + def field_dump(self, cr, uid, context=None): |
987 | + keys = [ |
988 | + 'module', |
989 | + 'mode', |
990 | + 'model', |
991 | + 'field', |
992 | + 'type', |
993 | + 'isfunction', |
994 | + 'relation', |
995 | + 'required', |
996 | + 'selection_keys', |
997 | + 'req_default', |
998 | + 'inherits', |
999 | + ] |
1000 | + |
1001 | + template = dict([(x, False) for x in keys]) |
1002 | + ids = self.search(cr, uid, [('type', '=', 'field')], context=context) |
1003 | + records = self.browse(cr, uid, ids, context=context) |
1004 | + data = [] |
1005 | + for record in records: |
1006 | + repr = template.copy() |
1007 | + repr.update({ |
1008 | + 'module': record.module, |
1009 | + 'model': record.model, |
1010 | + 'field': record.field, |
1011 | + 'mode': record.mode, |
1012 | + }) |
1013 | + repr.update( |
1014 | + dict([(x.name, x.value) for x in record.attribute_ids])) |
1015 | + data.append(repr) |
1016 | + return data |
1017 | + |
1018 | +openupgrade_record() |
1019 | |
1020 | === added directory 'bin/addons/openupgrade_records/security' |
1021 | === added file 'bin/addons/openupgrade_records/security/ir.model.access.csv' |
1022 | --- bin/addons/openupgrade_records/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
1023 | +++ bin/addons/openupgrade_records/security/ir.model.access.csv 2012-05-09 12:36:18 +0000 |
1024 | @@ -0,0 +1,3 @@ |
1025 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
1026 | +"access_openupgrade_record","openupgrade.record all","model_openupgrade_record",,1,0,0,0 |
1027 | +"access_openupgrade_attribute","openupgrade.attribute all","model_openupgrade_attribute",,1,0,0,0 |
1028 | |
1029 | === added directory 'bin/addons/openupgrade_records/view' |
1030 | === added file 'bin/addons/openupgrade_records/view/analysis_wizard.xml' |
1031 | --- bin/addons/openupgrade_records/view/analysis_wizard.xml 1970-01-01 00:00:00 +0000 |
1032 | +++ bin/addons/openupgrade_records/view/analysis_wizard.xml 2012-05-09 12:36:18 +0000 |
1033 | @@ -0,0 +1,30 @@ |
1034 | +<?xml version="1.0" encoding="utf-8"?> |
1035 | +<openerp> |
1036 | + <data> |
1037 | + <record id="view_openupgrade_analysis_wizard_form" model="ir.ui.view"> |
1038 | + <field name="name">view.openupgrade.analysis_wizard.form</field> |
1039 | + <field name="model">openupgrade.analysis.wizard</field> |
1040 | + <field name="type">form</field> |
1041 | + <field name="arch" type="xml"> |
1042 | + <form string="OpenUpgrade Analysis Wizard"> |
1043 | + <field name="server_config" readonly="1"/> |
1044 | + <field name="state"/> |
1045 | + <field name="log" colspan="4" |
1046 | + attrs="{'invisible': [('state', '!=', 'ready')]}"/> |
1047 | + <field name="write" |
1048 | + attrs="{'readonly': [('state', '!=', 'init')]}"/> |
1049 | + <button icon="gtk-close" |
1050 | + special="cancel" |
1051 | + string="Close" |
1052 | + /> |
1053 | + <button icon="gtk-ok" |
1054 | + string="Create" |
1055 | + name="get_communication" |
1056 | + type="object" |
1057 | + states="init" |
1058 | + /> |
1059 | + </form> |
1060 | + </field> |
1061 | + </record> |
1062 | + </data> |
1063 | +</openerp> |
1064 | |
1065 | === added file 'bin/addons/openupgrade_records/view/comparison_config.xml' |
1066 | --- bin/addons/openupgrade_records/view/comparison_config.xml 1970-01-01 00:00:00 +0000 |
1067 | +++ bin/addons/openupgrade_records/view/comparison_config.xml 2012-05-09 12:36:18 +0000 |
1068 | @@ -0,0 +1,62 @@ |
1069 | +<?xml version="1.0" encoding="utf-8"?> |
1070 | +<openerp> |
1071 | + <data> |
1072 | + <record id="view_openupgrade_comparison_config_tree" model="ir.ui.view"> |
1073 | + <field name="name">view.openupgrade.comparison_config.tree</field> |
1074 | + <field name="model">openupgrade.comparison.config</field> |
1075 | + <field name="type">tree</field> |
1076 | + <field name="arch" type="xml"> |
1077 | + <tree string="OpenUpgrade Comparison Config"> |
1078 | + <field name="name" select="1"/> |
1079 | + <field name="protocol"/> |
1080 | + <field name="server" select="1"/> |
1081 | + <field name="port" select="1"/> |
1082 | + <field name="database" select="1"/> |
1083 | + </tree> |
1084 | + </field> |
1085 | + </record> |
1086 | + <record id="view_openupgrade_comparison_config_form" model="ir.ui.view"> |
1087 | + <field name="name">view.openupgrade.comparison_config.form</field> |
1088 | + <field name="model">openupgrade.comparison.config</field> |
1089 | + <field name="type">form</field> |
1090 | + <field name="arch" type="xml"> |
1091 | + <form string="OpenUpgrade Comparison Config"> |
1092 | + <field name="name"/> |
1093 | + <field name="protocol"/> |
1094 | + <field name="server"/> |
1095 | + <field name="port"/> |
1096 | + <field name="database"/> |
1097 | + <field name="username"/> |
1098 | + <field name="password" password="1"/> |
1099 | + <button |
1100 | + name="test_connection" |
1101 | + string="Test Connection" |
1102 | + type="object" icon="gtk-network" |
1103 | + colspan="2" |
1104 | + /> |
1105 | + <newline/> |
1106 | + <button |
1107 | + name="analyze" |
1108 | + string="Perform Analysis" |
1109 | + type="object" icon="gtk-execute" |
1110 | + colspan="2" |
1111 | + /> |
1112 | + <separator string="Last log" colspan="4"/> |
1113 | + <field name="last_log" nolabel="1" colspan="4"/> |
1114 | + </form> |
1115 | + </field> |
1116 | + </record> |
1117 | + <record id="action_openupgrade_comparison_config_tree" model="ir.actions.act_window"> |
1118 | + <field name="name">OpenUpgrade Comparison Configs</field> |
1119 | + <field name="type">ir.actions.act_window</field> |
1120 | + <field name="res_model">openupgrade.comparison.config</field> |
1121 | + <field name="view_type">form</field> |
1122 | + </record> |
1123 | + <menuitem |
1124 | + action="action_openupgrade_comparison_config_tree" |
1125 | + id="menu_openupgrade_comparison_config" |
1126 | + name="Comparison Configurations" |
1127 | + parent="menu_openupgrade" |
1128 | + /> |
1129 | + </data> |
1130 | +</openerp> |
1131 | |
1132 | === added file 'bin/addons/openupgrade_records/view/generate_records_wizard.xml' |
1133 | --- bin/addons/openupgrade_records/view/generate_records_wizard.xml 1970-01-01 00:00:00 +0000 |
1134 | +++ bin/addons/openupgrade_records/view/generate_records_wizard.xml 2012-05-09 12:36:18 +0000 |
1135 | @@ -0,0 +1,52 @@ |
1136 | +<?xml version="1.0" encoding="utf-8"?> |
1137 | +<openerp> |
1138 | + <data> |
1139 | + <record id="view_openupgrade_generate_records_wizard_form" model="ir.ui.view"> |
1140 | + <field name="name">view.openupgrade.generate_records_wizard.form</field> |
1141 | + <field name="model">openupgrade.generate.records.wizard</field> |
1142 | + <field name="type">form</field> |
1143 | + <field name="arch" type="xml"> |
1144 | + <form string="OpenUpgrade Generate Records Wizard"> |
1145 | + <group states="init" colspan="4"> |
1146 | + <label string="This will reinitialize all the modules installed on this database. Do not continue if you use this database in production." |
1147 | + /> |
1148 | + <button icon="gtk-close" |
1149 | + special="cancel" |
1150 | + string="Cancel" |
1151 | + /> |
1152 | + <button icon="gtk-ok" |
1153 | + string="Continue" |
1154 | + name="generate" |
1155 | + type="object" |
1156 | + /> |
1157 | + </group> |
1158 | + <group states="ready" colspan="4"> |
1159 | + <label string="Modules initialized and records created" |
1160 | + /> |
1161 | + <field name="state" invisible="1"/> |
1162 | + <button icon="gtk-close" |
1163 | + special="cancel" |
1164 | + string="Close" |
1165 | + /> |
1166 | + </group> |
1167 | + </form> |
1168 | + </field> |
1169 | + </record> |
1170 | + |
1171 | + <record id="action_generate_records" model="ir.actions.act_window"> |
1172 | + <field name="name">Generate Records</field> |
1173 | + <field name="type">ir.actions.act_window</field> |
1174 | + <field name="res_model">openupgrade.generate.records.wizard</field> |
1175 | + <field name="view_type">form</field> |
1176 | + <field name="view_mode">form,tree</field> |
1177 | + <field name="target">new</field> |
1178 | + </record> |
1179 | + |
1180 | + <menuitem name="Generate Records" |
1181 | + id="menu_openupgrade_generate_records" |
1182 | + parent="menu_openupgrade" |
1183 | + action="action_generate_records" |
1184 | + sequence="15"/> |
1185 | + |
1186 | + </data> |
1187 | +</openerp> |
1188 | |
1189 | === added file 'bin/addons/openupgrade_records/view/install_all_wizard.xml' |
1190 | --- bin/addons/openupgrade_records/view/install_all_wizard.xml 1970-01-01 00:00:00 +0000 |
1191 | +++ bin/addons/openupgrade_records/view/install_all_wizard.xml 2012-05-09 12:36:18 +0000 |
1192 | @@ -0,0 +1,54 @@ |
1193 | +<?xml version="1.0" encoding="utf-8"?> |
1194 | +<openerp> |
1195 | + <data> |
1196 | + <record id="view_openupgrade_install_all_wizard_form" model="ir.ui.view"> |
1197 | + <field name="name">view.openupgrade.install_all_wizard.form</field> |
1198 | + <field name="model">openupgrade.install.all.wizard</field> |
1199 | + <field name="type">form</field> |
1200 | + <field name="arch" type="xml"> |
1201 | + <form string="OpenUpgrade Install All Modules Wizard"> |
1202 | + <group states="init" colspan="4"> |
1203 | + <label string="This will install all modules on the database. Do not continue if you use this database in production." colspan="4" |
1204 | + /> |
1205 | + <field name="to_install"/> |
1206 | + <newline/> |
1207 | + <button icon="gtk-close" |
1208 | + special="cancel" |
1209 | + string="Cancel" |
1210 | + /> |
1211 | + <button icon="gtk-ok" |
1212 | + string="Continue" |
1213 | + name="install_all" |
1214 | + type="object" |
1215 | + /> |
1216 | + </group> |
1217 | + <group states="ready" colspan="4"> |
1218 | + <label string="Modules installed" |
1219 | + /> |
1220 | + <field name="state" invisible="1"/> |
1221 | + <button icon="gtk-close" |
1222 | + special="cancel" |
1223 | + string="Close" |
1224 | + /> |
1225 | + </group> |
1226 | + </form> |
1227 | + </field> |
1228 | + </record> |
1229 | + |
1230 | + <record id="action_install_all" model="ir.actions.act_window"> |
1231 | + <field name="name">Install All Modules</field> |
1232 | + <field name="type">ir.actions.act_window</field> |
1233 | + <field name="res_model">openupgrade.install.all.wizard</field> |
1234 | + <field name="view_type">form</field> |
1235 | + <field name="view_mode">form,tree</field> |
1236 | + <field name="target">new</field> |
1237 | + </record> |
1238 | + |
1239 | + <menuitem name="Install All Modules" |
1240 | + id="menu_openupgrade_install_all" |
1241 | + parent="menu_openupgrade" |
1242 | + action="action_install_all" |
1243 | + sequence="14"/> |
1244 | + |
1245 | + </data> |
1246 | +</openerp> |
1247 | |
1248 | === added file 'bin/addons/openupgrade_records/view/openupgrade_record.xml' |
1249 | --- bin/addons/openupgrade_records/view/openupgrade_record.xml 1970-01-01 00:00:00 +0000 |
1250 | +++ bin/addons/openupgrade_records/view/openupgrade_record.xml 2012-05-09 12:36:18 +0000 |
1251 | @@ -0,0 +1,65 @@ |
1252 | +<?xml version="1.0" encoding="utf-8"?> |
1253 | +<openerp> |
1254 | + <data> |
1255 | + <!-- Top level menu under 'Database structure' --> |
1256 | + <menuitem |
1257 | + id="menu_openupgrade" |
1258 | + name="OpenUpgrade Development" |
1259 | + parent="base.menu_administration" |
1260 | + sequence="99" |
1261 | + /> |
1262 | + <record id="view_openupgrade_record_tree" model="ir.ui.view"> |
1263 | + <field name="name">view.openupgrade.record.tree</field> |
1264 | + <field name="model">openupgrade.record</field> |
1265 | + <field name="type">tree</field> |
1266 | + <field name="arch" type="xml"> |
1267 | + <tree string="OpenUpgrade Records"> |
1268 | + <field name="module" select="1"/> |
1269 | + <field name="model" select="1"/> |
1270 | + <field name="field" select="1"/> |
1271 | + <field name="name" select="1"/> |
1272 | + <field name="type" select="1"/> |
1273 | + <field name="mode" select="1"/> |
1274 | + </tree> |
1275 | + </field> |
1276 | + </record> |
1277 | + <record id="view_openupgrade_record_form" model="ir.ui.view"> |
1278 | + <field name="name">view.openupgrade.record.form</field> |
1279 | + <field name="model">openupgrade.record</field> |
1280 | + <field name="type">form</field> |
1281 | + <field name="arch" type="xml"> |
1282 | + <form string="OpenUpgrade Record"> |
1283 | + <field name="module" select="1"/> |
1284 | + <field name="model" select="1"/> |
1285 | + <field name="field" select="1"/> |
1286 | + <field name="name" select="1"/> |
1287 | + <field name="type" select="1"/> |
1288 | + <field name="mode" select="1"/> |
1289 | + <separator string="Attributes" colspan="4"/> |
1290 | + <field name="attribute_ids" mode="tree,form" nolabel="1" colspan="4"> |
1291 | + <tree string="Attributes"> |
1292 | + <field name="name"/> |
1293 | + <field name="value"/> |
1294 | + </tree> |
1295 | + <form string="Attribute"> |
1296 | + <field name="name"/> |
1297 | + <field name="value"/> |
1298 | + </form> |
1299 | + </field> |
1300 | + </form> |
1301 | + </field> |
1302 | + </record> |
1303 | + <record id="action_openupgrade_record_tree" model="ir.actions.act_window"> |
1304 | + <field name="name">OpenUpgrade Records</field> |
1305 | + <field name="type">ir.actions.act_window</field> |
1306 | + <field name="res_model">openupgrade.record</field> |
1307 | + <field name="view_type">form</field> |
1308 | + </record> |
1309 | + <menuitem |
1310 | + action="action_openupgrade_record_tree" |
1311 | + id="menu_openupgrade_records" |
1312 | + name="Records" |
1313 | + parent="menu_openupgrade" |
1314 | + /> |
1315 | + </data> |
1316 | +</openerp> |
1317 | |
1318 | === added directory 'bin/openupgrade' |
1319 | === added file 'bin/openupgrade/__init__.py' |
1320 | === added directory 'bin/openupgrade/doc' |
1321 | === added file 'bin/openupgrade/doc/readme.txt' |
1322 | --- bin/openupgrade/doc/readme.txt 1970-01-01 00:00:00 +0000 |
1323 | +++ bin/openupgrade/doc/readme.txt 2012-05-09 12:36:18 +0000 |
1324 | @@ -0,0 +1,2 @@ |
1325 | +The documentation of this project is currently maintained in the |
1326 | +6.1 branch. You can also consult it at http://readthedocs.org/docs/openupgrade-server |
1327 | |
1328 | === added file 'bin/openupgrade/openupgrade.py' |
1329 | --- bin/openupgrade/openupgrade.py 1970-01-01 00:00:00 +0000 |
1330 | +++ bin/openupgrade/openupgrade.py 2012-05-09 12:36:18 +0000 |
1331 | @@ -0,0 +1,259 @@ |
1332 | +# -*- coding: utf-8 -*- |
1333 | +import os |
1334 | +from osv import osv |
1335 | +import pooler |
1336 | +import logging |
1337 | +import tools |
1338 | +import openupgrade_tools |
1339 | + |
1340 | +logger = logging.getLogger('OpenUpgrade') |
1341 | + |
1342 | +__all__ = [ |
1343 | + 'load_data', |
1344 | + 'rename_columns', |
1345 | + 'rename_tables', |
1346 | + 'drop_columns', |
1347 | + 'table_exists', |
1348 | + 'column_exists', |
1349 | + 'delete_model_workflow', |
1350 | + 'set_defaults', |
1351 | + 'update_module_names', |
1352 | + 'add_ir_model_fields', |
1353 | +] |
1354 | + |
1355 | +def load_data(cr, module_name, filename, idref=None, mode='init'): |
1356 | + """ |
1357 | + Load an xml or csv data file from your post script. The usual case for this is the |
1358 | + occurrence of newly added essential or useful data in the module that is |
1359 | + marked with "noupdate='1'" and without "forcecreate='1'" so that it will |
1360 | + not be loaded by the usual upgrade mechanism. Leaving the 'mode' argument to |
1361 | + its default 'init' will load the data from your migration script. |
1362 | + |
1363 | + Theoretically, you could simply load a stock file from the module, but be |
1364 | + careful not to reinitialize any data that could have been customized. |
1365 | + Preferably, select only the newly added items. Copy these to a file |
1366 | + in your migrations directory and load that file. |
1367 | + Leave it to the user to actually delete existing resources that are |
1368 | + marked with 'noupdate' (other named items will be deleted |
1369 | + automatically). |
1370 | + |
1371 | + |
1372 | + :param module_name: the name of the module |
1373 | + :param filename: the path to the filename, relative to the module \ |
1374 | + directory. |
1375 | + :param idref: optional hash with ?id mapping cache? |
1376 | + :param mode: one of 'init', 'update', 'demo'. Always use 'init' for adding new items \ |
1377 | + from files that are marked with 'noupdate'. Defaults to 'init'. |
1378 | + |
1379 | + """ |
1380 | + |
1381 | + if idref is None: |
1382 | + idref = {} |
1383 | + logger.info('%s: loading %s' % (module_name, filename)) |
1384 | + _, ext = os.path.splitext(filename) |
1385 | + pathname = os.path.join(module_name, filename) |
1386 | + fp = tools.file_open(pathname) |
1387 | + try: |
1388 | + if ext == '.csv': |
1389 | + noupdate = True |
1390 | + tools.convert_csv_import(cr, module_name, pathname, fp.read(), idref, mode, noupdate) |
1391 | + else: |
1392 | + tools.convert_xml_import(cr, module_name, fp, idref, mode=mode) |
1393 | + finally: |
1394 | + fp.close() |
1395 | + |
1396 | +# for backwards compatibility |
1397 | +load_xml = load_data |
1398 | +table_exists = openupgrade_tools.table_exists |
1399 | + |
1400 | +def rename_columns(cr, column_spec): |
1401 | + """ |
1402 | + Rename table columns. Typically called in the pre script. |
1403 | + |
1404 | + :param column_spec: a hash with table keys, with lists of tuples as values. \ |
1405 | + Tuples consist of (old_name, new_name). |
1406 | + |
1407 | + """ |
1408 | + for table in column_spec.keys(): |
1409 | + for (old, new) in column_spec[table]: |
1410 | + logger.info("table %s, column %s: renaming to %s", |
1411 | + table, old, new) |
1412 | + cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % (table, old, new,)) |
1413 | + |
1414 | +def rename_tables(cr, table_spec): |
1415 | + """ |
1416 | + Rename tables. Typically called in the pre script. |
1417 | + :param column_spec: a list of tuples (old table name, new table name). |
1418 | + |
1419 | + """ |
1420 | + for (old, new) in table_spec: |
1421 | + logger.info("table %s: renaming to %s", |
1422 | + old, new) |
1423 | + cr.execute('ALTER TABLE "%s" RENAME TO "%s"' % (old, new,)) |
1424 | + |
1425 | +def rename_models(cr, model_spec): |
1426 | + """ |
1427 | + Rename models. Typically called in the pre script. |
1428 | + :param column_spec: a list of tuples (old table name, new table name). |
1429 | + |
1430 | + Use case: if a model changes name, but still implements equivalent |
1431 | + functionality you will want to update references in for instance |
1432 | + relation fields. |
1433 | + |
1434 | + """ |
1435 | + for (old, new) in model_spec: |
1436 | + logger.info("model %s: renaming to %s", |
1437 | + old, new) |
1438 | + cr.execute('UPDATE ir_model_fields SET relation = %s ' |
1439 | + 'WHERE relation = %s', (new, old,)) |
1440 | + |
1441 | +def drop_columns(cr, column_spec): |
1442 | + """ |
1443 | + Drop columns but perform an additional check if a column exists. |
1444 | + This covers the case of function fields that may or may not be stored. |
1445 | + Consider that this may not be obvious: an additional module can govern |
1446 | + a function fields' store properties. |
1447 | + |
1448 | + :param column_spec: a list of (table, column) tuples |
1449 | + """ |
1450 | + for (table, column) in column_spec: |
1451 | + logger.info("table %s: drop column %s", |
1452 | + table, column) |
1453 | + if column_exists(cr, table, column): |
1454 | + cr.execute('ALTER TABLE "%s" DROP COLUMN "%s"' % |
1455 | + (table, column)) |
1456 | + else: |
1457 | + logger.warn("table %s: column %s did not exist", |
1458 | + table, column) |
1459 | + |
1460 | +def delete_model_workflow(cr, model): |
1461 | + """ |
1462 | + Forcefully remove active workflows for obsolete models, |
1463 | + to prevent foreign key issues when the orm deletes the model. |
1464 | + """ |
1465 | + logged_query( |
1466 | + cr, |
1467 | + "DELETE FROM wkf_workitem WHERE act_id in " |
1468 | + "( SELECT wkf_activity.id " |
1469 | + " FROM wkf_activity, wkf " |
1470 | + " WHERE wkf_id = wkf.id AND " |
1471 | + " wkf.osv = %s" |
1472 | + ")", (model,)) |
1473 | + logged_query( |
1474 | + cr, |
1475 | + "DELETE FROM wkf WHERE osv = %s", (model,)) |
1476 | + |
1477 | +def set_defaults(cr, pool, default_spec, force=False): |
1478 | + """ |
1479 | + Set default value. Useful for fields that are newly required. Uses orm, so |
1480 | + call from the post script. |
1481 | + |
1482 | + :param default_spec: a hash with model names as keys. Values are lists of \ |
1483 | + tuples (field, value). None as a value has a special meaning: it assigns \ |
1484 | + the default value. If this value is provided by a function, the function is \ |
1485 | + called as the user that created the resource. |
1486 | + :param force: overwrite existing values. To be used for assigning a non- \ |
1487 | + default value (presumably in the case of a new column). The ORM assigns \ |
1488 | + the default value as declared in the model in an earlier stage of the \ |
1489 | + process. Beware of issues with resources loaded from new data that \ |
1490 | + actually do require the model's default, in combination with the post \ |
1491 | + script possible being run multiple times. |
1492 | + """ |
1493 | + |
1494 | + def write_value(ids, field, value): |
1495 | + logger.info("model %s, field %s: setting default value of %d resources to %s", |
1496 | + model, field, len(ids), unicode(value)) |
1497 | + obj.write(cr, 1, ids, {field: value}) |
1498 | + |
1499 | + for model in default_spec.keys(): |
1500 | + obj = pool.get(model) |
1501 | + if not obj: |
1502 | + raise osv.except_osv("Migration: error setting default, no such model: %s" % model, "") |
1503 | + |
1504 | + for field, value in default_spec[model]: |
1505 | + domain = not force and [(field, '=', False)] or [] |
1506 | + ids = obj.search(cr, 1, domain) |
1507 | + if not ids: |
1508 | + continue |
1509 | + if value is None: |
1510 | + # Set the value by calling the _defaults of the object. |
1511 | + # Typically used for company_id on various models, and in that |
1512 | + # case the result depends on the user associated with the object. |
1513 | + # We retrieve create_uid for this purpose and need to call the _defaults |
1514 | + # function per resource. Otherwise, write all resources at once. |
1515 | + if field in obj._defaults: |
1516 | + if not callable(obj._defaults[field]): |
1517 | + write_value(ids, field, obj._defaults[field]) |
1518 | + else: |
1519 | + # existence users is covered by foreign keys, so this is not needed |
1520 | + # 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" % |
1521 | + # (obj._table, obj._table, obj._table, obj._table, tuple(ids),)) |
1522 | + cr.execute("SELECT id, COALESCE(create_uid, 1) FROM %s " % obj._table + "WHERE id in %s", (tuple(ids),)) |
1523 | + fetchdict = dict(cr.fetchall()) |
1524 | + for id in ids: |
1525 | + write_value([id], field, obj._defaults[field](obj, cr, fetchdict.get(id, 1), None)) |
1526 | + if id not in fetchdict: |
1527 | + logger.info("model %s, field %s, id %d: no create_uid defined or user does not exist anymore", |
1528 | + model, field, id) |
1529 | + else: |
1530 | + error = ("OpenUpgrade: error setting default, field %s with " |
1531 | + "None default value not in %s' _defaults" % ( |
1532 | + field, model)) |
1533 | + logger.error(error) |
1534 | + # this exeption seems to get lost in a higher up try block |
1535 | + osv.except_osv("OpenUpgrade", error) |
1536 | + else: |
1537 | + write_value(ids, field, value) |
1538 | + |
1539 | +def logged_query(cr, query, args=None): |
1540 | + if args is None: |
1541 | + args = [] |
1542 | + res = cr.execute(query, args) |
1543 | + logger.debug('Running %s', query) |
1544 | + if not res: |
1545 | + query = query % args |
1546 | + logger.warn('No rows affected for query "%s"', query) |
1547 | + return res |
1548 | + |
1549 | +def column_exists(cr, table, column): |
1550 | + """ Check whether a certain column exists """ |
1551 | + cr.execute( |
1552 | + 'SELECT count(attname) FROM pg_attribute ' |
1553 | + 'WHERE attrelid = ' |
1554 | + '( SELECT oid FROM pg_class WHERE relname = %s ) ' |
1555 | + 'AND attname = %s', |
1556 | + (table, column)); |
1557 | + return cr.fetchone()[0] == 1 |
1558 | + |
1559 | +def update_module_names(cr, namespec): |
1560 | + """ |
1561 | + Deal with changed module names of certified modules |
1562 | + in order to prevent 'certificate not unique' error, |
1563 | + as well as updating the module reference in the |
1564 | + XML id. |
1565 | + |
1566 | + :param namespec: tuple of (old name, new name) |
1567 | + """ |
1568 | + for (old_name, new_name) in namespec: |
1569 | + query = ("UPDATE ir_module_module SET name = %s " |
1570 | + "WHERE name = %s") |
1571 | + logged_query(cr, query, (new_name, old_name)) |
1572 | + query = ("UPDATE ir_model_data SET module = %s " |
1573 | + "WHERE module = %s ") |
1574 | + logged_query(cr, query, (new_name, old_name)) |
1575 | + |
1576 | +def add_ir_model_fields(cr, columnspec): |
1577 | + """ |
1578 | + Typically, new columns on ir_model_fields need to be added in a very |
1579 | + early stage in the upgrade process of the base module, in raw sql |
1580 | + as they need to be in place before any model gets initialized. |
1581 | + Do not use for fields with additional SQL constraints, such as a |
1582 | + reference to another table or the cascade constraint, but craft your |
1583 | + own statement taking them into account. |
1584 | + |
1585 | + :param columnspec: tuple of (column name, column type) |
1586 | + """ |
1587 | + for column in columnspec: |
1588 | + query = 'ALTER TABLE ir_model_fields ADD COLUMN %s %s' % ( |
1589 | + column) |
1590 | + logged_query(cr, query, []) |
1591 | |
1592 | === added file 'bin/openupgrade/openupgrade_log.py' |
1593 | --- bin/openupgrade/openupgrade_log.py 1970-01-01 00:00:00 +0000 |
1594 | +++ bin/openupgrade/openupgrade_log.py 2012-05-09 12:36:18 +0000 |
1595 | @@ -0,0 +1,56 @@ |
1596 | +# -*- coding: utf-8 -*- |
1597 | +from openupgrade_tools import table_exists |
1598 | + |
1599 | +def log_xml_id(cr, module, xml_id): |
1600 | + """ |
1601 | + Log xml_ids at load time in the records table. |
1602 | + Called from openerp/tools/convert.py:xml_import._test_xml_id() |
1603 | + |
1604 | + # Catcha's |
1605 | + - The module needs to be loaded with 'init', or the calling method |
1606 | + won't be called. This can be brought about by installing the |
1607 | + module or updating the 'state' field of the module to 'to install' |
1608 | + or call the server with '--init <module>' and the database argument. |
1609 | + |
1610 | + - Do you get the right results immediately when installing the module? |
1611 | + No, sorry. This method retrieves the model from the ir_model_table, but when |
1612 | + the xml id is encountered for the first time, this method is called |
1613 | + before the item is present in this table. Therefore, you will not |
1614 | + get any meaningful results until the *second* time that you 'init' |
1615 | + the module. |
1616 | + |
1617 | + - The good news is that the openupgrade_records module that comes |
1618 | + with this distribution allows you to deal with all of this with |
1619 | + one click on the menu item Settings -> Customizations -> |
1620 | + Database Structure -> OpenUpgrade -> Generate Records |
1621 | + |
1622 | + - You cannot reinitialize the modules in your production database |
1623 | + and expect to keep working on it happily ever after. Do not perform |
1624 | + this routine on your production database. |
1625 | + |
1626 | + :param module: The module that contains the xml_id |
1627 | + :param xml_id: the xml_id, with or without 'module.' prefix |
1628 | + """ |
1629 | + if not table_exists(cr, 'openupgrade_record'): |
1630 | + return |
1631 | + if not '.' in xml_id: |
1632 | + xml_id = '%s.%s' % (module, xml_id) |
1633 | + cr.execute( |
1634 | + "SELECT model FROM ir_model_data " |
1635 | + "WHERE module = %s AND name = %s", |
1636 | + xml_id.split('.')) |
1637 | + record = cr.fetchone() |
1638 | + if not record: |
1639 | + #print "Cannot find xml_id %s" % xml_id |
1640 | + return |
1641 | + else: |
1642 | + cr.execute( |
1643 | + "SELECT id FROM openupgrade_record " |
1644 | + "WHERE module=%s AND model=%s AND name=%s AND type=%s", |
1645 | + (module, record[0], xml_id, 'xmlid')) |
1646 | + if not cr.fetchone(): |
1647 | + cr.execute( |
1648 | + "INSERT INTO openupgrade_record " |
1649 | + "(module, model, name, type) values(%s, %s, %s, %s)", |
1650 | + (module, record[0], xml_id, 'xmlid')) |
1651 | + |
1652 | |
1653 | === added file 'bin/openupgrade/openupgrade_tools.py' |
1654 | --- bin/openupgrade/openupgrade_tools.py 1970-01-01 00:00:00 +0000 |
1655 | +++ bin/openupgrade/openupgrade_tools.py 2012-05-09 12:36:18 +0000 |
1656 | @@ -0,0 +1,8 @@ |
1657 | +# -*- coding: utf-8 -*- |
1658 | +def table_exists(cr, table): |
1659 | + """ Check whether a certain table or view exists """ |
1660 | + cr.execute( |
1661 | + 'SELECT count(relname) FROM pg_class WHERE relname = %s', |
1662 | + (table,)) |
1663 | + return cr.fetchone()[0] == 1 |
1664 | + |
1665 | |
1666 | === modified file 'bin/tools/convert.py' |
1667 | --- bin/tools/convert.py 2010-12-17 12:06:16 +0000 |
1668 | +++ bin/tools/convert.py 2012-05-09 12:36:18 +0000 |
1669 | @@ -42,6 +42,8 @@ |
1670 | |
1671 | from tools.safe_eval import safe_eval as eval |
1672 | |
1673 | +from openupgrade import openupgrade_log |
1674 | + |
1675 | class ConvertError(Exception): |
1676 | def __init__(self, doc, orig_excpt): |
1677 | self.d = doc |
1678 | @@ -244,6 +246,7 @@ |
1679 | |
1680 | if len(id) > 64: |
1681 | self.logger.notifyChannel('init', netsvc.LOG_ERROR, 'id: %s is to long (max: 64)'% (id,)) |
1682 | + openupgrade_log.log_xml_id(self.cr, self.module, xml_id) |
1683 | |
1684 | def _tag_delete(self, cr, rec, data_node=None): |
1685 | d_model = rec.get("model",'') |
1686 | |
1687 | === modified file 'bin/tools/sql.py' |
1688 | --- bin/tools/sql.py 2009-01-04 22:13:29 +0000 |
1689 | +++ bin/tools/sql.py 2012-05-09 12:36:18 +0000 |
1690 | @@ -23,7 +23,8 @@ |
1691 | def drop_view_if_exists(cr, viewname): |
1692 | cr.execute("select count(1) from pg_class where relkind=%s and relname=%s", ('v', viewname,)) |
1693 | if cr.fetchone()[0]: |
1694 | - cr.execute("DROP view %s" % (viewname,)) |
1695 | + # OpenUpgrade: add CASCADE |
1696 | + cr.execute("DROP view %s CASCADE" % (viewname,)) |
1697 | cr.commit() |
1698 | |
1699 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |