← Back to team overview

credativ team mailing list archive

[Merge] lp:~therp-nl/openupgrade-server/6.1-use_orm into lp:openupgrade-server

 

Stefan Rijnhart (Therp) has proposed merging lp:~therp-nl/openupgrade-server/6.1-use_orm into lp:openupgrade-server.

Requested reviews:
  OpenUpgrade Committers (openupgrade-committers)

For more details, see:
https://code.launchpad.net/~therp-nl/openupgrade-server/6.1-use_orm/+merge/105196

This merge constitutes the refactoring of the database layout analysis and the inclusion of the analysis files for 6.1, as described here:

https://lists.launchpad.net/openupgrade-drivers/msg00001.html

-- 
https://code.launchpad.net/~therp-nl/openupgrade-server/6.1-use_orm/+merge/105196
Your team OpenUpgrade Committers is requested to review the proposed merge of lp:~therp-nl/openupgrade-server/6.1-use_orm into lp:openupgrade-server.
=== modified file 'openerp/addons/base/ir/ir_model.py'
--- openerp/addons/base/ir/ir_model.py	2012-02-09 08:38:28 +0000
+++ openerp/addons/base/ir/ir_model.py	2012-05-09 12:37:19 +0000
@@ -32,6 +32,8 @@
 from tools.translate import _
 import pooler
 
+from openerp.openupgrade import openupgrade_log
+
 _logger = logging.getLogger(__name__)
 
 def _get_fields_type(self, cr, uid, context=None):
@@ -675,6 +677,10 @@
         return super(ir_model_data,self).unlink(cr, uid, ids, context=context)
 
     def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None):
+        #OpenUpgrade: log entry (used in csv import)
+        if xml_id:
+            openupgrade_log.log_xml_id(cr, module, xml_id)
+
         model_obj = self.pool.get(model)
         if not context:
             context = {}

=== added file 'openerp/addons/base/migrations/6.1.1.3/openupgrade_analysis.txt'
--- openerp/addons/base/migrations/6.1.1.3/openupgrade_analysis.txt	1970-01-01 00:00:00 +0000
+++ openerp/addons/base/migrations/6.1.1.3/openupgrade_analysis.txt	2012-05-09 12:37:19 +0000
@@ -0,0 +1,178 @@
+---base---
+base         / ir.actions.act_window    / menus (char)                  : DEL 
+base         / ir.actions.act_window    / target (selection)            : selection_keys is now '['current', 'inline', 'new']' ('['current', 'new']')
+base         / ir.actions.act_window.view / view_mode (selection)         : selection_keys is now '['calendar', 'form', 'gantt', 'graph', 'kanban', 'tree']' ('['calendar', 'form', 'gantt', 'graph', 'tree']')
+base         / ir.actions.client        / name (char)                   : NEW required: required
+base         / ir.actions.client        / params_store (binary)         : NEW 
+base         / ir.actions.client        / tag (char)                    : NEW required: required
+base         / ir.actions.client        / type (char)                   : NEW required: required, req_default: ir.actions.client
+base         / ir.actions.client        / usage (char)                  : NEW 
+base         / ir.actions.todo          / category_id (many2one)        : NEW relation: ir.actions.todo.category
+base         / ir.actions.todo          / restart (selection)           : DEL required: required, selection_keys: ['always', 'never', 'onskip'], req_default: onskip
+base         / ir.actions.todo          / state (selection)             : selection_keys is now '['done', 'open']' ('['cancel', 'done', 'open', 'skip']')
+base         / ir.actions.todo          / type (selection)              : NEW required: required, selection_keys: ['automatic', 'manual', 'once'], req_default: manual
+base         / ir.actions.todo.category / name (char)                   : NEW required: required
+base         / ir.actions.todo.category / sequence (integer)            : NEW 
+base         / ir.actions.todo.category / wizards_ids (one2many)        : NEW relation: ir.actions.todo
+base         / ir.mail_server           / name (char)                   : NEW required: required
+base         / ir.mail_server           / sequence (integer)            : NEW 
+base         / ir.mail_server           / smtp_debug (boolean)          : NEW 
+base         / ir.mail_server           / smtp_encryption (selection)   : NEW required: required, selection_keys: ['none', 'ssl', 'starttls'], req_default: none
+base         / ir.mail_server           / smtp_host (char)              : NEW required: required
+base         / ir.mail_server           / smtp_pass (char)              : NEW 
+base         / ir.mail_server           / smtp_port (integer)           : NEW required: required, req_default: 25
+base         / ir.mail_server           / smtp_user (char)              : NEW 
+base         / ir.model.fields          / serialization_field_id (many2one): NEW relation: ir.model.fields
+base         / ir.module.category       / description (text)            : NEW 
+base         / ir.module.category       / module_ids (one2many)         : NEW relation: ir.module.module
+base         / ir.module.category       / sequence (integer)            : NEW 
+base         / ir.module.category       / visible (boolean)             : NEW 
+base         / ir.module.module         / application (boolean)         : NEW 
+base         / ir.module.module         / auto_install (boolean)        : NEW 
+base         / ir.module.module         / complexity (selection)        : NEW selection_keys: ['easy', 'expert', 'normal']
+base         / ir.module.module         / icon (char)                   : NEW 
+base         / ir.module.module         / sequence (integer)            : NEW 
+base         / ir.module.module         / web (boolean)                 : DEL 
+base         / ir.sequence              / implementation (selection)    : NEW required: required, selection_keys: ['no_gap', 'standard'], req_default: standard
+base         / ir.translation           / module (char)                 : DEL 
+base         / ir.translation           / xml_id (char)                 : DEL 
+base         / ir.ui.view               / type (selection)              : selection_keys is now '['calendar', 'diagram', 'form', 'gantt', 'graph', 'kanban', 'mdx', 'search', 'tree']' ('['calendar', 'diagram', 'form', 'gantt', 'graph', 'mdx', 'search', 'tree']')
+base         / ir.ui.view.custom        / ref_id (many2one)             : now required
+base         / ir.ui.view.custom        / user_id (many2one)            : now required
+base         / ir.values                / key (selection)               : now required, default = action
+base         / ir.values                / meta (text)                   : DEL 
+base         / ir.values                / model (char)                  : now required
+base         / ir.values                / name (char)                   : now required
+base         / ir.values                / object (boolean)              : DEL 
+base         / res.bank                 / code (char)                   : module is now 'l10n_ch' ('base')
+base         / res.company              / bank_ids (one2many)           : NEW relation: res.partner.bank
+base         / res.company              / company_registry (char)       : NEW 
+base         / res.company              / name (char)                   : now a function
+base         / res.company              / paper_format (selection)      : NEW required: required, selection_keys: ['a4', 'us_letter'], req_default: a4
+base         / res.company              / rml_footer2 (char)            : now a function
+base         / res.country              / address_format (text)         : NEW 
+base         / res.currency             / position (selection)          : NEW selection_keys: ['after', 'before']
+base         / res.currency.rate        / currency_rate_type_id (many2one): NEW relation: res.currency.rate.type
+base         / res.currency.rate.type   / name (char)                   : NEW required: required
+base         / res.groups               / category_id (many2one)        : NEW relation: ir.module.category
+base         / res.groups               / implied_ids (many2many)       : NEW relation: res.groups
+base         / res.partner              / color (integer)               : NEW 
+base         / res.partner.address      / color (integer)               : NEW 
+base         / res.partner.bank         / acc_number (char)             : now required
+base         / res.partner.bank         / bank_bic (char)               : NEW 
+base         / res.partner.bank         / bank_name (char)              : NEW 
+base         / res.partner.bank         / company_id (many2one)         : NEW relation: res.company
+base         / res.partner.bank         / footer (boolean)              : NEW 
+base         / res.partner.bank.type    / format_layout (text)          : NEW 
+base         / res.users                / address_id (many2one)         : DEL relation: res.partner.address
+base         / res.users                / email (char)                  : DEL 
+base         / res.users                / id (integer)                  : NEW 
+base         / res.users                / user_email (char)             : not a function anymore
+deleted xml-id of model ir.actions.act_window: base.act_values_form
+deleted xml-id of model ir.actions.act_window: base.action_config_simple_view_form
+deleted xml-id of model ir.actions.act_window: base.action_config_user_form
+deleted xml-id of model ir.actions.act_window: base.action_view_base_module_upgrade_window
+deleted xml-id of model ir.actions.act_window: base.res_partner_canal-act
+deleted xml-id of model ir.actions.server: base.action_start_configurator
+deleted xml-id of model ir.actions.todo: base.config_wizard_simple_view
+deleted xml-id of model ir.actions.todo: base.config_wizard_step_user
+deleted xml-id of model ir.actions.wizard: base.wizard_server_action_create
+deleted xml-id of model ir.model.access: base.access_ir_ui_view_custom_group_system
+deleted xml-id of model ir.model.access: base.access_ir_values_group_erp_manager
+deleted xml-id of model ir.model.access: base.access_res_partner_canal_group_partner_manager
+deleted xml-id of model ir.model.access: base.access_res_partner_canal_group_user
+deleted xml-id of model ir.ui.menu: base.menu_crm_config_lead
+deleted xml-id of model ir.ui.menu: base.menu_res_partner_canal-act
+deleted xml-id of model ir.ui.menu: base.menu_view_base_module_configuration
+deleted xml-id of model ir.ui.menu: base.menu_view_base_module_import
+deleted xml-id of model ir.ui.view: base.res_partner_canal-view
+deleted xml-id of model ir.ui.view: base.res_partner_canal-view-tree
+deleted xml-id of model ir.ui.view: base.values_view_form
+deleted xml-id of model ir.ui.view: base.values_view_tree
+deleted xml-id of model ir.ui.view: base.view_confirm_simple_view_form
+deleted xml-id of model ir.ui.view: base.view_users_configuration_form
+deleted xml-id of model ir.ui.view_sc: base.ir_ui_view_sc_configuration
+deleted xml-id of model ir.values: base.action_todo_config
+deleted xml-id of model res.currency.rate: base.rateVEB
+deleted xml-id of model res.currency: base.VEB
+deleted xml-id of model res.partner.bank.type.field: base.bank_normal_field
+deleted xml-id of model res.partner.bank.type.field: base.bank_normal_field_contry
+new xml-id of model ir.actions.act_window.view: base.action_values_defaults_form_view
+new xml-id of model ir.actions.act_window.view: base.action_values_defaults_tree_view
+new xml-id of model ir.actions.act_window: base.act_values_form_defaults
+new xml-id of model ir.actions.act_window: base.action_currency_rate_type_form
+new xml-id of model ir.actions.act_window: base.action_ir_mail_server_list
+new xml-id of model ir.actions.act_window: base.action_res_partner_bank_account_form
+new xml-id of model ir.actions.act_window: base.action_res_partner_bank_type_form
+new xml-id of model ir.actions.act_window: base.bank_account_update
+new xml-id of model ir.actions.act_window: base.ir_config_list_action
+new xml-id of model ir.actions.report.xml: base.preview_report
+new xml-id of model ir.actions.todo.category: base.category_administration_config
+new xml-id of model ir.actions.todo.category: base.category_sales_management_config
+new xml-id of model ir.actions.todo.category: base.category_tools_customization_config
+new xml-id of model ir.mail_server: base.ir_mail_server_localhost0
+new xml-id of model ir.model.access: base.access_ir_actions_client
+new xml-id of model ir.model.access: base.access_ir_actions_todo_category
+new xml-id of model ir.model.access: base.access_ir_mail_server_all
+new xml-id of model ir.model.access: base.access_res_currency_rate_type_group_all
+new xml-id of model ir.module.category: base.module_category_account_voucher
+new xml-id of model ir.module.category: base.module_category_accounting_and_finance
+new xml-id of model ir.module.category: base.module_category_administration
+new xml-id of model ir.module.category: base.module_category_customer_relationship_management
+new xml-id of model ir.module.category: base.module_category_hidden
+new xml-id of model ir.module.category: base.module_category_human_resources
+new xml-id of model ir.module.category: base.module_category_knowledge_management
+new xml-id of model ir.module.category: base.module_category_localization
+new xml-id of model ir.module.category: base.module_category_localization_account_charts
+new xml-id of model ir.module.category: base.module_category_manufacturing
+new xml-id of model ir.module.category: base.module_category_marketing
+new xml-id of model ir.module.category: base.module_category_point_of_sale
+new xml-id of model ir.module.category: base.module_category_project_management
+new xml-id of model ir.module.category: base.module_category_purchase_management
+new xml-id of model ir.module.category: base.module_category_report_designer
+new xml-id of model ir.module.category: base.module_category_sales_management
+new xml-id of model ir.module.category: base.module_category_specific_industry_applications
+new xml-id of model ir.module.category: base.module_category_tools
+new xml-id of model ir.module.category: base.module_category_usability
+new xml-id of model ir.module.category: base.module_category_warehouse_management
+new xml-id of model ir.rule: base.ir_ui_view_custom_personal
+new xml-id of model ir.rule: base.ir_values_default_rule
+new xml-id of model ir.ui.menu: base.ir_config_menu
+new xml-id of model ir.ui.menu: base.menu_action_res_partner_bank_form
+new xml-id of model ir.ui.menu: base.menu_action_res_partner_bank_typeform
+new xml-id of model ir.ui.menu: base.menu_email
+new xml-id of model ir.ui.menu: base.menu_mail_servers
+new xml-id of model ir.ui.menu: base.menu_values_form_defaults
+new xml-id of model ir.ui.view: base.contacts_kanban_view
+new xml-id of model ir.ui.view: base.ir_actions_todo_category_form
+new xml-id of model ir.ui.view: base.ir_actions_todo_category_tree
+new xml-id of model ir.ui.view: base.ir_mail_server_form
+new xml-id of model ir.ui.view: base.ir_mail_server_list
+new xml-id of model ir.ui.view: base.module_view_kanban
+new xml-id of model ir.ui.view: base.res_partner_kanban_view
+new xml-id of model ir.ui.view: base.user_groups_view
+new xml-id of model ir.ui.view: base.values_view_form_defaults
+new xml-id of model ir.ui.view: base.view_currency_rate_type_form
+new xml-id of model ir.ui.view: base.view_currency_rate_type_search
+new xml-id of model ir.ui.view: base.view_currency_search
+new xml-id of model ir.ui.view: base.view_ir_config_form
+new xml-id of model ir.ui.view: base.view_ir_config_list
+new xml-id of model ir.ui.view: base.view_ir_config_search
+new xml-id of model ir.ui.view: base.view_ir_mail_server_search
+new xml-id of model ir.ui.view: base.view_partner_bank_search
+new xml-id of model res.country: base.ax
+new xml-id of model res.country: base.bl
+new xml-id of model res.country: base.bq
+new xml-id of model res.country: base.cw
+new xml-id of model res.country: base.gg
+new xml-id of model res.country: base.im
+new xml-id of model res.country: base.je
+new xml-id of model res.country: base.mf
+new xml-id of model res.country: base.ps
+new xml-id of model res.country: base.ss
+new xml-id of model res.country: base.sx
+new xml-id of model res.currency.rate: base.rateUYU
+new xml-id of model res.currency.rate: base.rateVEF
+new xml-id of model res.currency: base.UYU
+new xml-id of model res.currency: base.VEF
+new xml-id of model res.partner.bank.type.field: base.bank_normal_field_bic

=== added file 'openerp/addons/base/migrations/6.1.1.3/openupgrade_general_log.txt'
--- openerp/addons/base/migrations/6.1.1.3/openupgrade_general_log.txt	1970-01-01 00:00:00 +0000
+++ openerp/addons/base/migrations/6.1.1.3/openupgrade_general_log.txt	2012-05-09 12:37:19 +0000
@@ -0,0 +1,248 @@
+---general---
+# 5021 fields matched,
+# Direct match: 4708
+# Found in other module: 6
+# Found with different name: 0
+# Found with different type: 1
+# In obsolete models: 306
+# New columns: 646
+# Not matched: 187
+new model account.asset.asset
+new model account.asset.category
+new model account.asset.depreciation.line
+new model account.asset.history
+new model account.bank.statement.line.global
+new model account.coda.comm.type
+new model account.coda.trans.category
+new model account.coda.trans.code
+new model account.coda.trans.type
+new model account.financial.report
+new model account.treasury.report
+new model analytic.user.funct.grid
+new model asset.asset.report
+new model coda.bank.account
+new model coda.bank.statement
+new model coda.bank.statement.line
+new model crm.case.channel
+new model crm.partner.report.assign
+new model edi.document
+new model fetchmail.server
+new model google.import.message
+new model hr.contribution.register
+new model hr.payslip.input
+new model hr.payslip.run
+new model hr.payslip.worked_days
+new model hr.recruitment.source
+new model hr.rule.input
+new model hr.salary.rule
+new model hr.salary.rule.category
+new model import.sugarcrm
+new model ir.actions.client
+new model ir.actions.todo.category
+new model ir.mail_server
+new model l10n_br_account.cst
+new model l10n_br_account.cst.template
+new model mail.thread
+new model pos.category
+new model project.task.history
+new model project.task.history.cumulative
+new model project.user.allocation
+new model res.currency.rate.type
+new model res.partner.activation
+new model res.partner.location
+new model res.portal
+new model res.portal.widget
+obsolete model account.report_libroiva
+obsolete model analytic_user_funct_grid
+obsolete model base_report_creator.report
+obsolete model base_report_creator.report.fields
+obsolete model base_report_creator.report.filter
+obsolete model board.note
+obsolete model board.note.type
+obsolete model company.contribution
+obsolete model company.contribution.line
+obsolete model document.directory.ics.fields
+obsolete model email.server
+obsolete model email.template
+obsolete model email_template.account
+obsolete model email_template.mailbox
+obsolete model hr.allounce.deduction.categoty
+obsolete model hr.contibution.register
+obsolete model hr.contibution.register.line
+obsolete model hr.contract.wage.type
+obsolete model hr.contract.wage.type.period
+obsolete model hr.employee.marital.status
+obsolete model hr.passport
+obsolete model hr.payroll.advice
+obsolete model hr.payroll.advice.line
+obsolete model hr.payroll.register
+obsolete model hr.payslip.account.move
+obsolete model hr.payslip.line.line
+obsolete model mailgate.message
+obsolete model mailgate.thread
+obsolete model mrp.production.order
+obsolete model project.resource.allocation
+obsolete model report.account.invoice.product
+obsolete model res.partner.canal
+obsolete model res.partner.job
+ERROR: module not in list of installed modules:
+---project_caldav---
+project_caldav / project.task             / alarm_id (many2one)           : DEL relation: res.alarm
+project_caldav / project.task             / allday (boolean)              : DEL 
+project_caldav / project.task             / attendee_ids (many2many)      : DEL relation: calendar.attendee
+project_caldav / project.task             / base_calendar_alarm_id (many2one): DEL relation: calendar.alarm
+project_caldav / project.task             / base_calendar_url (char)      : DEL 
+project_caldav / project.task             / byday (selection)             : DEL selection_keys: ['-1', '1', '2', '3', '4', '5']
+project_caldav / project.task             / class (selection)             : DEL selection_keys: ['confidential', 'private', 'public']
+project_caldav / project.task             / count (integer)               : DEL 
+project_caldav / project.task             / day (integer)                 : DEL 
+project_caldav / project.task             / duration (integer)            : DEL 
+project_caldav / project.task             / edit_all (boolean)            : DEL 
+project_caldav / project.task             / end_date (date)               : DEL 
+project_caldav / project.task             / end_type (selection)          : DEL selection_keys: ['count', 'end_date', 'forever']
+project_caldav / project.task             / exdate (text)                 : DEL 
+project_caldav / project.task             / exrule (char)                 : DEL 
+project_caldav / project.task             / fr (boolean)                  : DEL 
+project_caldav / project.task             / freq (selection)              : DEL selection_keys: ['None', 'daily', 'hourly', 'monthly', 'weekly', 'yearly']
+project_caldav / project.task             / interval (integer)            : DEL 
+project_caldav / project.task             / location (char)               : DEL 
+project_caldav / project.task             / mo (boolean)                  : DEL 
+project_caldav / project.task             / month_list (selection)        : DEL selection_keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+project_caldav / project.task             / organizer (char)              : DEL 
+project_caldav / project.task             / organizer_id (many2one)       : DEL relation: res.users
+project_caldav / project.task             / recurrency (boolean)          : DEL 
+project_caldav / project.task             / recurrent_id (datetime)       : DEL 
+project_caldav / project.task             / recurrent_uid (integer)       : DEL 
+project_caldav / project.task             / rrule_type (selection)        : DEL selection_keys: ['daily', 'monthly', 'none', 'weekly', 'yearly']
+project_caldav / project.task             / sa (boolean)                  : DEL 
+project_caldav / project.task             / select1 (selection)           : DEL selection_keys: ['date', 'day']
+project_caldav / project.task             / show_as (selection)           : DEL selection_keys: ['busy', 'free']
+project_caldav / project.task             / su (boolean)                  : DEL 
+project_caldav / project.task             / th (boolean)                  : DEL 
+project_caldav / project.task             / tu (boolean)                  : DEL 
+project_caldav / project.task             / vtimezone (selection)         : DEL selection_keys: function
+project_caldav / project.task             / we (boolean)                  : DEL 
+project_caldav / project.task             / week_list (selection)         : DEL selection_keys: ['FR', 'MO', 'SA', 'SU', 'TH', 'TU', 'WE']
+project_caldav / project.task             / write_date (datetime)         : DEL 
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_0
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_1
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_10
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_11
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_12
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_13
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_14
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_15
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_16
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_17
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_18
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_19
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_2
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_20
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_21
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_22
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_226
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_23
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_24
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_25
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_27
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_28
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_29
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_3
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_30
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_31
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_32
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_33
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_34
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_35
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_36
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_37
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_38
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_4
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_5
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_6
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_7
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_8
+deleted xml-id of model basic.calendar.fields: project_caldav.basic_calendar_fields_9
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_1
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_10
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_11
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_2
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_3
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_4
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_5
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_6
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_7
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_8
+deleted xml-id of model basic.calendar.fields: project_caldav.map_alarm_9
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_1
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_10
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_11
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_2
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_3
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_4
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_5
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_6
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_7
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_8
+deleted xml-id of model basic.calendar.fields: project_caldav.map_attendee_9
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_1
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_10
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_11
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_12
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_13
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_14
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_15
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_16
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_17
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_18
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_19
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_2
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_3
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_4
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_5
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_7
+deleted xml-id of model basic.calendar.fields: project_caldav.map_todo_9
+deleted xml-id of model basic.calendar.lines: caldav.calendar_lines_alarm2
+deleted xml-id of model basic.calendar.lines: caldav.calendar_lines_attendee2
+deleted xml-id of model basic.calendar.lines: caldav.calendar_lines_todo
+deleted xml-id of model basic.calendar.lines: project_caldav.basic_calendar_lines_attendee0
+deleted xml-id of model basic.calendar.lines: project_caldav.basic_calendar_lines_valarm0
+deleted xml-id of model basic.calendar.lines: project_caldav.basic_calendar_lines_vtodo0
+deleted xml-id of model basic.calendar: caldav.basic_calendar2
+deleted xml-id of model basic.calendar: project_caldav.basic_calendar_tasks0
+deleted xml-id of model ir.ui.view: project_caldav.view_project_caldav_task_form
+deleted xml-id of model ir.ui.view: project_caldav.view_project_caldav_task_form1
+deleted xml-id of model ir.ui.view: project_caldav.view_project_caldav_task_form2
+deleted xml-id of model ir.ui.view: project_caldav.view_project_caldav_task_form3
+deleted xml-id of model ir.ui.view: project_caldav.view_project_caldav_task_form4
+ERROR: module not in list of installed modules:
+---base_report_creator---
+deleted xml-id of model ir.actions.act_window: base_report_creator.action_report_menu_create
+deleted xml-id of model ir.actions.act_window: base_report_creator.base_report_creator_action
+deleted xml-id of model ir.actions.wizard: base_report_creator.wizard_set_filter_fields
+deleted xml-id of model ir.model.access: base_report_creator.access_base_report_creator_report
+deleted xml-id of model ir.model.access: base_report_creator.access_base_report_creator_report_fields
+deleted xml-id of model ir.model.access: base_report_creator.access_base_report_creator_report_filter
+deleted xml-id of model ir.ui.menu: base.menu_custom_reports
+deleted xml-id of model ir.ui.view: base.view_model_fields_tree
+deleted xml-id of model ir.ui.view: base_report_creator.base_report_creator_form
+deleted xml-id of model ir.ui.view: base_report_creator.base_report_creator_tree
+deleted xml-id of model ir.ui.view: base_report_creator.view_report_filter
+deleted xml-id of model ir.ui.view: base_report_creator.view_report_menu_create
+ERROR: module not in list of installed modules:
+---document_ics---
+document_ics / crm.meeting              / code (char)                   : DEL 
+document_ics / document.directory.content / fname_field (char)            : DEL 
+document_ics / document.directory.content / ics_domain (char)             : DEL 
+document_ics / document.directory.content / ics_field_ids (one2many)      : DEL relation: document.directory.ics.fields
+document_ics / document.directory.content / obj_iterate (boolean)         : DEL 
+document_ics / document.directory.content / object_id (many2one)          : DEL relation: ir.model
+deleted xml-id of model document.directory.content.type: document_ics.ics
+deleted xml-id of model ir.actions.act_window: document_ics.action_view_document_ics_config_directories
+deleted xml-id of model ir.actions.todo: document_ics.config_wizard_step_case_section_menu
+deleted xml-id of model ir.model.access: document_ics.access_document_directory_ics_fields_all
+deleted xml-id of model ir.model.access: document_ics.access_document_directory_ics_fields_manager
+deleted xml-id of model ir.ui.view: document_ics.view_document_directory_form
+deleted xml-id of model ir.ui.view: document_ics.view_document_directory_form_1
+deleted xml-id of model ir.ui.view: document_ics.view_document_ics_config_directories
+deleted xml-id of model ir.ui.view: document_ics.view_meeting_inherit_form

=== added directory 'openerp/addons/openupgrade_records'
=== added file 'openerp/addons/openupgrade_records/__init__.py'
--- openerp/addons/openupgrade_records/__init__.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/__init__.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,2 @@
+import model
+import lib

=== added file 'openerp/addons/openupgrade_records/__openerp__.py'
--- openerp/addons/openupgrade_records/__openerp__.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/__openerp__.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+    'name': 'OpenUpgrade Records',
+    'version': '0.2',
+    'category': 'Normal',
+    'description': """Allow OpenUpgrade records to be 
+stored in the database and compare with other servers.
+
+This module depends on OpenERP client lib:
+
+    easy_install openerp-client-lib
+
+""",
+    'author': 'OpenUpgrade Community',
+    'maintainer': 'OpenUpgrade Community',
+    'contributors': ['Therp BV'],
+    'website': 'https://launchpad.net/~openupgrade-committers',
+    'depends': [],
+    'init_xml': [],
+    'update_xml': [
+        'view/openupgrade_record.xml',
+        'view/comparison_config.xml',
+        'view/analysis_wizard.xml',
+        'view/generate_records_wizard.xml',
+        'view/install_all_wizard.xml',
+        'security/ir.model.access.csv',
+        ],
+    'demo_xml': [
+    ],
+    'test': [
+    ],
+    'installable': True,
+    'auto_install': False,
+    'external_dependencies': {
+        'python' : ['openerplib'],
+        },
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'openerp/addons/openupgrade_records/__terp__.py'
--- openerp/addons/openupgrade_records/__terp__.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/__terp__.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+    'name': 'OpenUpgrade Records',
+    'version': '0.2',
+    'category': 'Normal',
+    'description': """Allow OpenUpgrade records to be 
+stored in the database and compare with other servers.
+
+This module depends on OpenERP client lib:
+
+    easy_install openerp-client-lib
+
+""",
+    'author': 'OpenUpgrade Community',
+    'maintainer': 'OpenUpgrade Community',
+    'contributors': ['Therp BV'],
+    'website': 'https://launchpad.net/~openupgrade-committers',
+    'depends': [],
+    'init_xml': [],
+    'update_xml': [
+        'view/openupgrade_record.xml',
+        'view/comparison_config.xml',
+        'view/analysis_wizard.xml',
+        'view/generate_records_wizard.xml',
+        'view/install_all_wizard.xml',
+        'security/ir.model.access.csv',
+        ],
+    'demo_xml': [
+    ],
+    'test': [
+    ],
+    'installable': True,
+    'auto_install': False,
+    'external_dependencies': {
+        'python' : ['openerplib'],
+        },
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added directory 'openerp/addons/openupgrade_records/lib'
=== added file 'openerp/addons/openupgrade_records/lib/__init__.py'
--- openerp/addons/openupgrade_records/lib/__init__.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/lib/__init__.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,2 @@
+import apriori
+import compare

=== renamed file 'openerp/openupgrade/changes.py' => 'openerp/addons/openupgrade_records/lib/apriori.py'
=== renamed file 'openerp/openupgrade/process-csv.py' => 'openerp/addons/openupgrade_records/lib/compare.py'
--- openerp/openupgrade/process-csv.py	2012-02-15 22:19:54 +0000
+++ openerp/addons/openupgrade_records/lib/compare.py	2012-05-09 12:37:19 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 ##############################################################################
 #
@@ -20,21 +19,21 @@
 #
 ##############################################################################
 
-USAGE = """ 
-
-    Standalone runnable to analyse two progressive datase layouts from the
-    OpenUpgrade server.
-
-        Usage: %(name)s <old.csv> <new.csv>
-
-"""
-
-import sys, copy, csv, re
-import changes
+#####################################################################
+#   library providing a function to analyse two progressive database
+#   layouts from the OpenUpgrade server.
+#####################################################################
+
+import copy
+
+try:
+    from openerp.addons.openupgrade_records.lib import apriori
+except ImportError:
+    from openupgrade_records.lib import apriori
 
 keys = [
     'module',
-    'operation',
+    'mode',
     'model',
     'field',
     'type',
@@ -46,168 +45,196 @@
     'inherits',
     ]
 
-def readfile(file):
-    fields = []
-    readfile = csv.reader(open(file, 'rb'), delimiter=',', quotechar='"')
-    for row in readfile:
-        if len(row) != len(keys):
-            print "Skip line %s (%s)" % (row, len(row))
-            continue
-        col = 0
-        field = {}
-        for key in keys:
-            field[key] = row[col]
-            col += 1
-        field['matched'] = False
-        fields.append(field)
-    return fields
-
-def equal(dicta, dictb, ignore):
-    ka = dicta.keys()
-    kb = dictb.keys()
-    kbstatic = dictb.keys()
-    for keyset in [ ka, kb, kbstatic ]:
-        for k in ignore:
-            keyset.remove(k)
-    for k in ka:
-        if k not in kbstatic:
-            return False
-        if dicta[k] != dictb[k]:
-            return False
-        kb.remove(k)
-    if kb:
-        return False
-    return True
-
-def compare(dict_old, dict_new, fields):
+def module_map(module):
+    return apriori.renamed_modules.get(
+        module, module)
+
+def compare_records(dict_old, dict_new, fields):
+    """
+    Check equivalence of two OpenUpgrade field representations
+    with respect to the keys in the 'fields' arguments.
+    Take apriori knowledge into account for mapped modules or
+    model names.
+    Return True of False.
+    """
     for field in fields:
         if field == 'module':
-            if (changes.renamed_modules.get(dict_old[field], dict_old[field]) != dict_new[field]):
+            if (module_map(dict_old[field]) != dict_new[field]):
                 return False
         elif field == 'model':
-            if (changes.renamed_models.get(dict_old[field], dict_old[field]) != dict_new[field]):
+            if (apriori.renamed_models.get(
+                    dict_old[field], dict_old[field]) != dict_new[field]):
                 return False
         else:
             if dict_old[field] != dict_new[field]:
                 return False
     return True
 
-def search(item, dict, fields):
-    for i in dict:
-        if not compare(item, i, fields):
+def search(item, item_list, fields):
+    """
+    Find a match of a dictionary in a list of similar dictionaries
+    with respect to the keys in the 'fields' arguments.
+    Return the item if found or None.
+    """
+    for i in item_list:
+        if not compare_records(item, i, fields):
             continue
         return i
     return None
 
-def fieldprint(old, new, field='NOT SPECIFIED', text=None):
-#    repr = 'module %s, model %s, field %s (%s)' % (old['module'], old['model'], old['field'], old['type'])
+def fieldprint(old, new, field, text, reprs):
     fieldrepr = "%s (%s)" % (old['field'], old['type'])
-    repr = '%s / %s / %s' % (old['module'].ljust(12), old['model'].ljust(24), fieldrepr.ljust(30))
+    repr = '%s / %s / %s' % (
+        old['module'].ljust(12), old['model'].ljust(24), fieldrepr.ljust(30))
     if text:
-        print "%s: %s" % (repr, text)
+        reprs.setdefault(module_map(old['module']), []).append(
+            "%s: %s" % (repr, text))
     else:
-        print "%s: %s is now \'%s\' ('%s')" % (repr, field, new[field], old[field])
+        reprs.setdefault(module_map(old['module']), []).append(
+            "%s: %s is now \'%s\' ('%s')" % (
+                repr, field, new[field], old[field]))
 
-def report_generic(new, old, attrs):
+def report_generic(new, old, attrs, reprs):
     for attr in attrs:
         if attr == 'required':
             if old[attr] != new['required'] and new['required']:
                 text = "now required"
-                if column['req_default']:
-                    text += ', default = %s' % column['req_default']
-                fieldprint(old, new, text=text)
+                if new['req_default']:
+                    text += ', default = %s' % new['req_default']
+                fieldprint(old, new, None, text, reprs)
         elif attr == 'isfunction':
             if old['isfunction'] != new['isfunction']:
                 if new['isfunction']:
                     text = "now a function"
                 else:
                     text = "not a function anymore"
-                fieldprint(old, new, text=text)
+                fieldprint(old, new, None, text, reprs)
         else:
             if old[attr] != new[attr]:
-                fieldprint(old, new, attr)
-
-if len(sys.argv) != 3:
-    print USAGE % {'name': sys.argv[0]}
-    exit(1)
-
-k5 = readfile(sys.argv[1])
-k6 = readfile(sys.argv[2])
-
-origlen = len(k5)
-
-models6 = set([ column['model'] for column in k6 ])
-models5 = set([ column['model'] for column in k5 ])
-
-matched_direct = 0
-matched_other_module = 0
-matched_other_type = 0
-matched_other_name = 0
-in_obsolete_models = 0
-
-obsolete_models = []
-for model in models5:
-    if model not in models6:
-        obsolete_models.append(model)
-        print '# obsolete model %s' % model
-
-for column in copy.copy(k5):
-    if column['model'] in obsolete_models:
-        k5.remove(column)
-        in_obsolete_models += 1
-
-for model in models6:
-    if model not in models5:
-        print '# new model %s' % model
-    
-def match(match_fields, report_fields, warn=False):
-    count = 0
-    for column in copy.copy(k5):
-        found = search(column, k6, match_fields)
+                fieldprint(old, new, attr, None, reprs)
+
+def compare_sets(old_records, new_records):
+    """
+    Compare a set of OpenUpgrade field representations.
+    Try to match the equivalent fields in both sets.
+    Return a textual representation of changes in a dictionary with
+    module names as keys. Special case is the 'general' key
+    which contains overall remarks and matching statistics.
+    """
+    reprs = {'general': []}
+
+    for record in old_records + new_records:
+        record['matched'] = False
+    origlen = len(old_records)
+    new_models = set([ column['model'] for column in new_records ])
+    old_models = set([ column['model'] for column in old_records ])
+
+    matched_direct = 0
+    matched_other_module = 0
+    matched_other_type = 0
+    matched_other_name = 0
+    in_obsolete_models = 0
+    
+    obsolete_models = []
+    for model in old_models:
+        if model not in new_models:
+            obsolete_models.append(model)
+            reprs['general'].append('obsolete model %s' % model)
+
+    for column in copy.copy(old_records):
+        if column['model'] in obsolete_models:
+            old_records.remove(column)
+            in_obsolete_models += 1
+
+    for model in new_models:
+        if model not in old_models:
+            reprs['general'].append('new model %s' % model)
+    
+    def match(match_fields, report_fields, warn=False):
+        count = 0
+        for column in copy.copy(old_records):
+            found = search(column, new_records, match_fields)
+            if found:
+                if warn:
+                    pass
+                    #print "Tentatively"
+                report_generic(found, column, report_fields, reprs)
+                old_records.remove(column)
+                new_records.remove(found)
+                count += 1
+        return count
+
+    matched_direct = match(
+        ['module', 'mode', 'model', 'field'],
+        ['relation', 'type', 'selection_keys', 'inherits', 'isfunction', 'required'])
+
+    # other module, same type and operation
+    matched_other_module = match(
+        ['mode', 'model', 'field', 'type'],
+        ['module', 'relation', 'selection_keys', 'inherits', 'isfunction', 'required'])
+
+    # other module, same operation, other type
+    matched_other_type = match(
+        ['mode', 'model', 'field'],
+        ['relation', 'type', 'selection_keys', 'inherits', 'isfunction', 'required'])
+
+    # fields with other names
+    #matched_other_name = match(
+    # ['module', 'type', 'relation'],
+    # ['field', 'relation', 'type', 'selection_keys',
+    #   'inherits', 'isfunction', 'required'], warn=True)
+
+    printkeys = [
+        'relation', 'required', 'selection_keys',
+        'req_default', 'inherits', 'mode'
+        ]
+    for column in old_records:
+        # we do not care about removed function fields
+        if not column['isfunction']:
+            if column['mode'] == 'create':
+                column['mode'] = ''
+            fieldprint(
+                column, None, None, "DEL " + ", ".join(
+                    [k + ': ' + str(column[k]) for k in printkeys if column[k]]
+                    ), reprs)
+
+    for column in new_records:
+        # we do not care about newly added function fields
+        if not column['isfunction']:
+            if column['mode'] == 'create':
+                column['mode'] = ''
+            fieldprint(
+                column, None, None, "NEW " + ", ".join(
+                    [k + ': ' + str(column[k]) for k in printkeys if column[k]]
+                    ), reprs)
+
+    for line in [
+        "# %d fields matched," % (origlen - len(old_records)),
+        "# Direct match: %d" % matched_direct,
+        "# Found in other module: %d" % matched_other_module,
+        "# Found with different type: %d" % matched_other_type,
+        "# Found with different name: %d" % matched_other_name,
+        "# In obsolete models: %d" % in_obsolete_models,
+        "# Not matched: %d" % len(old_records),
+        "# New columns: %d" % len(new_records),
+        ]:
+        reprs['general'].append(line)
+    return reprs
+
+def compare_xml_sets(old_records, new_records):
+    reprs = {}
+    match_fields = ['module', 'model', 'name']
+    for column in copy.copy(old_records):
+        found = search(column, new_records, match_fields)
         if found:
-            if warn:
-                print "Tentatively"
-            report_generic(found, column, report_fields)
-            k5.remove(column)
-            k6.remove(found)
-            count += 1
-    return count
-
-matched_direct = match(['module', 'operation', 'model', 'field'],
-                       ['relation', 'type', 'selection_keys', 'inherits', 'isfunction', 'required'])
-
-# other module, same type and operation
-matched_other_module = match(['operation', 'model', 'field', 'type'],
-                             ['module', 'relation', 'selection_keys', 'inherits', 'isfunction', 'required'])
-
-# other module, same operation, other type
-matched_other_type = match(['operation', 'model', 'field'],
-                           ['relation', 'type', 'selection_keys', 'inherits', 'isfunction', 'required'])
-
-# fields with other names
-#matched_other_name = match(['module', 'type', 'relation'],
-#                           ['field', 'relation', 'type', 'selection_keys', 'inherits', 'isfunction', 'required'], warn=True)
-
-printkeys = ['relation', 'required', 'selection_keys', 'req_default', 'inherits', 'operation']
-for column in k5:
-    # we do not care about removed function fields
-    if not column['isfunction']:
-        if column['operation'] == 'create':
-            column['operation'] = ''
-        fieldprint(column, None, text="DEL " + ", ".join([k + ': ' + str(column[k]) for k in printkeys if column[k]]))
-
-for column in k6:
-    # we do not care about newly added function fields
-    if not column['isfunction']:
-        if column['operation'] == 'create':
-            column['operation'] = ''
-        fieldprint(column, None, text="NEW " + ", ".join([k + ': ' + str(column[k]) for k in printkeys if column[k]]))
-
-print "# %d fields matched," % (origlen - len(k5))
-print "# Direct match: %d" % matched_direct
-print "# Found in other module: %d" % matched_other_module
-print "# Found with different type: %d" % matched_other_type
-print "# Found with different name: %d" % matched_other_name
-print "# In obsolete models: %d" % in_obsolete_models
-print "# Not matched: %d" % len(k5)
-print "# New columns: %d" % len(k6)
+            old_records.remove(column)
+            new_records.remove(found)
+    for entry in sorted(
+        old_records, key=lambda k: '%s%s' % (k['model'].ljust(128), k['name'])):
+        reprs.setdefault(module_map(entry['module']), []).append(
+            'deleted xml-id of model %s: %s' % (entry['model'], entry['name']))
+    for entry in sorted(
+        new_records, key=lambda k: '%s%s' % (k['model'].ljust(128), k['name'])):
+        reprs.setdefault(module_map(entry['module']), []).append(
+            'new xml-id of model %s: %s' % (entry['model'], entry['name']))
+    return reprs

=== added directory 'openerp/addons/openupgrade_records/model'
=== added file 'openerp/addons/openupgrade_records/model/__init__.py'
--- openerp/addons/openupgrade_records/model/__init__.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/__init__.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,6 @@
+import openupgrade_record
+import comparison_config
+import analysis_wizard
+import generate_records_wizard
+import install_all_wizard
+

=== added file 'openerp/addons/openupgrade_records/model/analysis_wizard.py'
--- openerp/addons/openupgrade_records/model/analysis_wizard.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/analysis_wizard.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import os
+from osv import osv, fields
+
+try:
+    from openerp.addons.openupgrade_records.lib import compare
+    from openerp.openupgrade_records.lib import apriori
+    from openerp.addons import get_module_path
+except ImportError:
+    from openupgrade_records.lib import compare
+    from openupgrade_records.lib import apriori
+    from addons import get_module_path
+
+class openupgrade_analysis_wizard(osv.osv_memory):
+    _name = 'openupgrade.analysis.wizard'
+    _description = 'OpenUpgrade Analysis Wizard'
+    _columns = {
+        'server_config': fields.many2one(
+            'openupgrade.comparison.config',
+            'Configuration', required=True),
+        'state': fields.selection(
+            [('init', 'Init'), ('ready', 'Ready')], 'State',
+            readonly=True),
+        'log': fields.text('Log'),
+        'write': fields.boolean(
+            'Write files',
+            help='Write analysis files to the module directories'
+            ),
+        }
+    _defaults = {
+        'state': lambda *a: 'init',
+        'write': lambda *a: True,
+        }
+
+    def get_communication(self, cr, uid, ids, context=None):
+        """ 
+        Retrieve both sets of database representations,
+        perform the comparison and register the resulting
+        change set
+        """
+        def write_file(
+            module, version, contents, filename='openupgrade_analysis.txt'):
+            module_path = get_module_path(module)
+            if not module_path:
+                return "ERROR: could not find module path:\n"
+            full_path = os.path.join(
+                module_path, 'migrations', version)
+            if not os.path.exists(full_path):
+                try:
+                    os.makedirs(full_path)
+                except os.error:
+                    return "ERROR: could not create migrations directory:\n"
+            logfile = os.path.join(full_path, filename)
+            try:
+                f = open(logfile, 'w')
+            except Exception:
+                return "ERROR: could not open file %s for writing:\n" % logfile
+            f.write(contents)
+            f.close()
+            return None
+
+        wizard = self.browse(cr, uid, ids[0], context=context)
+        # Retrieve connection and access methods
+        conf_obj = self.pool.get('openupgrade.comparison.config')
+        connection = conf_obj.get_connection(
+            cr, uid, [wizard.server_config.id], context=context)
+        remote_record_obj = connection.get_model('openupgrade.record')
+        local_record_obj = self.pool.get('openupgrade.record')
+        
+        # Retrieve field representations and compare
+        remote_records = remote_record_obj.field_dump(context)
+        local_records = local_record_obj.field_dump(cr, uid, context)
+        res = compare.compare_sets(remote_records, local_records)
+
+        # Retrieve xml id representations and compare
+        fields = ['module', 'model', 'name']
+        local_xml_record_ids = local_record_obj.search(
+            cr, uid, [('type', '=', 'xmlid')])
+        remote_xml_record_ids = remote_record_obj.search(
+            [('type', '=', 'xmlid')])
+        local_xml_records = [
+            dict([(field, x[field]) for field in fields])
+            for x in local_record_obj.read(
+                cr, uid, local_xml_record_ids, fields)
+            ]
+        remote_xml_records = [
+            dict([(field, x[field]) for field in fields])
+            for x in remote_record_obj.read(
+                remote_xml_record_ids, fields)
+            ]
+        res_xml = compare.compare_xml_sets(
+            remote_xml_records, local_xml_records)
+
+        # reorder and output the result
+        keys = list(set(res.keys() + res_xml.keys()))
+        keys.remove('general')
+        keys = ['general'] + keys
+        module_obj = self.pool.get('ir.module.module')
+        module_ids = module_obj.search(
+            cr, uid, [('state', '=', 'installed')])
+        modules = dict([(x['name'], x) for x in module_obj.read(cr, uid, module_ids)])
+        general = ''
+        for key in keys:
+            contents = "---%s---\n" % key
+            if key in res:
+                contents += '\n'.join([unicode(line) for line in sorted(res[key])])
+                if res[key]:
+                    contents += '\n'
+            if key in res_xml:
+                contents += '\n'.join([unicode(line) for line in sorted(res_xml[key])])
+                if res_xml[key]:
+                    contents += '\n'
+            if key == 'general':
+                general += contents
+                continue
+            if key not in modules:
+                general += (
+                    "ERROR: module not in list of installed modules:\n"
+                    + contents)
+                continue
+            if wizard.write:
+                error = write_file(
+                    key, modules[key]['installed_version'], contents)
+                if error:
+                    general += error
+                    general += contents
+            else:
+                general += contents
+        
+        # Store the general log in as many places as possible ;-)
+        if wizard.write and 'base' in modules:
+            write_file(
+                'base', modules['base']['installed_version'], general,
+                'openupgrade_general_log.txt')
+        self.pool.get('openupgrade.comparison.config').write(
+            cr, uid, wizard.server_config.id,
+            {'last_log': general})
+        self.write(cr, uid, ids, {'state': 'ready', 'log': general})
+
+        result = {
+            'name': self._description,
+            'view_type': 'form',
+            'view_mode': 'form',
+            'res_model': 'openupgrade.analysis.wizard',
+            'domain': [],
+            'context': context,
+            'type': 'ir.actions.act_window',
+            #'target': 'new',
+            'res_id': ids[0],
+            }
+        return result
+
+openupgrade_analysis_wizard()
+

=== added file 'openerp/addons/openupgrade_records/model/comparison_config.py'
--- openerp/addons/openupgrade_records/model/comparison_config.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/comparison_config.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import osv, fields
+import openerplib
+from tools.translate import _
+
+class openupgrade_comparison_config(osv.osv):
+    _name = 'openupgrade.comparison.config'
+    _columns = {
+        'name': fields.char('Name', size=64),
+        'server': fields.char('Server', size=64, required=True),
+        'port': fields.integer('Port', required=True),
+        'protocol': fields.selection(
+            [('http://', 'XML-RPC')],
+            # ('https://', 'XML-RPC Secure')], not supported by libopenerp
+            'Protocol', required=True),
+        'database': fields.char('Database', size=64, required=True),
+        'username': fields.char('Username', size=24, required=True),
+        'password': fields.char('Password', size=24, required=True, password=True),
+        'last_log': fields.text('Last log'),
+        }
+    _defaults = {
+        'port': lambda *a: 8069,
+        'protocol': lambda *a: 'http://',
+        }
+
+    def get_connection(self, cr, uid, ids, context=None):
+        if not ids:
+            raise osv.except_osv(
+                _("Cannot connect"), _("Invalid id passed."))
+        conf = self.read(cr, uid, ids[0], context=None)
+        return openerplib.get_connection(
+           hostname=conf['server'],
+           database=conf['database'],
+           login=conf['username'],
+           password=conf['password'],
+           port=conf['port'],
+           )
+
+    def test_connection(self, cr, uid, ids, context=None):
+        try:
+            connection = self.get_connection(cr, uid, [ids[0]], context)
+            user_model = connection.get_model("res.users")
+            ids = user_model.search([("login", "=", "admin")])
+            user_info = user_model.read(ids[0], ["name"])
+        except Exception, e:
+            raise osv.except_osv(
+                _("Connection failed."), unicode(e))
+        raise osv.except_osv(
+            _("Connection succesful."),
+            _("%s is connected.") % user_info["name"]
+            )
+    
+    def analyze(self, cr, uid, ids, context=None):
+        """
+        Run the analysis wizard
+        """
+        wizard_obj = self.pool.get('openupgrade.analysis.wizard')
+        wizard_id = wizard_obj.create(
+            cr, uid, {'server_config': ids[0]}, context)
+        result = {
+            'name': wizard_obj._description,
+            'view_type': 'form',
+            'view_mode': 'form',
+            'res_model': 'openupgrade.analysis.wizard',
+            'domain': [],
+            'context': context,
+            'type': 'ir.actions.act_window',
+            'target': 'new',
+            'res_id': wizard_id,
+            'nodestroy': True,
+            }
+        return result
+
+openupgrade_comparison_config()

=== added file 'openerp/addons/openupgrade_records/model/generate_records_wizard.py'
--- openerp/addons/openupgrade_records/model/generate_records_wizard.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/generate_records_wizard.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import os
+from osv import osv, fields
+import pooler
+try:
+    from openerp.openupgrade import openupgrade_tools
+except ImportError:
+    from openupgrade import openupgrade_tools
+
+class generate_records_wizard(osv.osv_memory):
+    _name = 'openupgrade.generate.records.wizard'
+    _description = 'OpenUpgrade Generate Records Wizard'
+    _columns = {
+        'state': fields.selection([('init', 'init'), ('ready', 'ready')], 'State'),
+        }
+    _defaults = {
+        'state': lambda *a: 'init',
+        }
+
+    def generate(self, cr, uid, ids, context=None):
+        """
+        Main wizard step. Make sure that all modules are up-to-date,
+        then reinitialize all installed modules.
+        Equivalent of running the server with '-d <database> --init all'
+
+        The goal of this is to fill the records table.
+
+        TODO: update module list and versions, then update all modules?
+        """
+        # Truncate the records table
+        if (openupgrade_tools.table_exists(cr, 'openupgrade_attribute') and
+            openupgrade_tools.table_exists(cr, 'openupgrade_record')):
+            cr.execute(
+                'TRUNCATE openupgrade_attribute, openupgrade_record;'
+                )
+
+        # Need to get all modules in state 'installed'
+        module_obj = self.pool.get('ir.module.module')
+        module_ids = module_obj.search(
+            cr, uid, [('state', 'in', ['to install', 'to upgrade'])])
+        if module_ids:
+            cr.commit()
+            _db, pool = pooler.restart_pool(cr.dbname, update_module=True)
+        # Did we succeed above?
+        module_ids = module_obj.search(
+            cr, uid, [('state', 'in', ['to install', 'to upgrade'])])
+        if module_ids:
+            modules = module_obj.read(
+                cr, uid, module_ids, ['name'], context=context)
+            raise except_osv(
+                "Cannot reliably generate records", 
+                ("Cannot seem to install or upgrade modules " +
+                 ', '.join([x['name'] for x in modules])))
+        # Now reinitialize all installed modules
+        module_ids = module_obj.search(
+            cr, uid, [('state', '=', 'installed')])
+        module_obj.write(
+            cr, uid, module_ids, {'state': 'to install'})
+        cr.commit()
+        _db, pool = pooler.restart_pool(cr.dbname, update_module=True)
+        self.write(cr, uid, ids, {'state': 'ready'})
+        # and we are done
+        return True
+
+generate_records_wizard()
+

=== added file 'openerp/addons/openupgrade_records/model/install_all_wizard.py'
--- openerp/addons/openupgrade_records/model/install_all_wizard.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/install_all_wizard.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import time
+import os
+from osv import osv, fields
+import pooler
+
+class install_all_wizard(osv.osv_memory):
+    _name = 'openupgrade.install.all.wizard'
+    _description = 'OpenUpgrade Install All Wizard'
+    _columns = {
+        'state': fields.selection([('init', 'init'), ('ready', 'ready')], 'State', readonly=True),
+        'to_install': fields.integer('Number of modules to install', readonly=True),
+        }
+    _defaults = {
+        'state': lambda *a: 'init',
+        }
+
+
+    def default_get(self, cr, uid, fields, context=None):
+        """
+        Update module list and retrieve the number
+        of installable modules
+        """
+        res = super(install_all_wizard, self).default_get(
+            cr, uid, fields, context=None)
+        module_obj = self.pool.get('ir.module.module')
+        update, add = module_obj.update_list(cr, uid,)
+        print "%s modules added" % add
+        module_ids = module_obj.search(
+            cr, uid, [('state', 'not in', ['installed', 'uninstallable', 'unknown'])])
+        res.update(
+            {'to_install': module_ids and len(module_ids) or False}
+            )
+        return res
+
+    def quirk_fiscalyear(self, cr, uid, ids, context=None):
+        """ 
+        Install account module first and create a fiscal year,
+        in order to prevent "No fiscal year defined" exception
+        during an upgrade or reinstallation of the account module.
+        
+        Refer to account_fiscalyear.find(), which is called as
+        a default function by the orm upon module upgrade.
+        """
+        module_obj = self.pool.get('ir.module.module')
+        pool = self.pool
+        # Retrieve status of the account module
+        account_module_id = module_obj.search(
+            cr, uid, [('name', '=', 'account')], context=context)[0]
+        state = module_obj.read(
+            cr, uid, account_module_id, ['state'], context=context)['state']
+        if state != 'installed':
+            # Cancel installation of other modules
+            module_ids = module_obj.search(
+                cr, uid, [('state', '=', 'to install')])
+            module_obj.write(cr, uid, module_ids, {'state': 'uninstalled'})
+            # Mark the module and its dependencies
+            module_obj.button_install(cr, uid, [account_module_id])
+            # Install account module
+            cr.commit()
+            _db, pool = pooler.restart_pool(cr.dbname, update_module=True)
+        # get or create today's fiscal year
+        fy_obj = pool.get('account.fiscalyear')
+        if not fy_obj.find(cr, uid, False, exception=False, context=context):
+            fy_obj.create(cr, uid, {
+                    'name': time.strftime('%Y'),
+                    'code': time.strftime('%Y'),
+                    'date_start': "%s-01-01" % time.strftime('%Y'),
+                    'date_stop': "%s-12-31" % time.strftime('%Y'),
+                    })
+        
+    def install_all(self, cr, uid, ids, context=None):
+        """
+        Main wizard step. Set all installable modules to install
+        and actually install them.
+        """
+        module_obj = self.pool.get('ir.module.module')
+        module_ids = module_obj.search(
+            cr, uid, [('state', 'not in', ['installed', 'uninstallable', 'unknown'])])
+        if module_ids:
+            module_obj.write(
+                cr, uid, module_ids, {'state': 'to install'})
+            cr.commit()
+            _db, pool = pooler.restart_pool(cr.dbname, update_module=True)
+            self.write(cr, uid, ids, {'state': 'ready'})
+        return True
+
+install_all_wizard()
+

=== added file 'openerp/addons/openupgrade_records/model/openupgrade_record.py'
--- openerp/addons/openupgrade_records/model/openupgrade_record.py	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/model/openupgrade_record.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module Copyright (C) 2012 OpenUpgrade community
+#    https://launchpad.net/~openupgrade-committers
+#
+#    Contributors:
+#    Therp BV <http://therp.nl>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import osv, fields
+
+# Cannot use forward references in 6.0
+class openupgrade_record(osv.osv):
+    _name = 'openupgrade.record'
+openupgrade_record()
+
+class openupgrade_attribute(osv.osv):
+    _name = 'openupgrade.attribute'
+    _rec_name = 'attribute_id'
+    _columns = {
+        'name': fields.char(
+            'Name', size=24,
+            readonly=True,
+            ),
+        'value': fields.char(
+            'Value',
+            size=4096,
+            readonly=True,
+            ),
+        'record_id': fields.many2one(
+            'openupgrade.record', ondelete='CASCADE',
+            readonly=True,
+            ),
+        }
+openupgrade_attribute()
+
+class openupgrade_record(osv.osv):
+    _inherit = 'openupgrade.record'
+
+    _columns = {
+        'name': fields.char('Name', size=256, readonly=True),
+        'module': fields.char('Module', size=128, readonly=True),
+        'model': fields.char('Model', size=128, readonly=True),
+        'field': fields.char('Field', size=128, readonly=True),
+        'mode': fields.selection(
+            [('create', 'Create'), ('modify', 'Modify')],
+            'Mode',
+            help='Set to Create if a field is newly created '
+            'in this module. If this module modifies an attribute of an '
+            'exting field, set to Modify.',
+            readonly=True,
+             ),
+        'type': fields.selection(
+            [('field', 'Field'), ('xmlid', 'XML ID')],
+            'Type',
+            readonly=True,
+            ),
+        'attribute_ids': fields.one2many(
+            'openupgrade.attribute', 'record_id', 'Attributes',
+            readonly=True,
+            ),
+        }
+    def field_dump(self, cr, uid, context=None):
+        keys = [
+            'module',
+            'mode',
+            'model',
+            'field',
+            'type',
+            'isfunction',
+            'relation',
+            'required',
+            'selection_keys',
+            'req_default',
+            'inherits',
+            ]
+
+        template = dict([(x, False) for x in keys])
+        ids = self.search(cr, uid, [('type', '=', 'field')], context=context)
+        records = self.browse(cr, uid, ids, context=context)
+        data = []
+        for record in records:
+            repr = template.copy()
+            repr.update({
+                    'module': record.module,
+                    'model': record.model,
+                    'field': record.field,
+                    'mode': record.mode,
+                    })
+            repr.update(
+                dict([(x.name, x.value) for x in record.attribute_ids]))
+            data.append(repr)
+        return data
+
+openupgrade_record()

=== added directory 'openerp/addons/openupgrade_records/security'
=== added file 'openerp/addons/openupgrade_records/security/ir.model.access.csv'
--- openerp/addons/openupgrade_records/security/ir.model.access.csv	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/security/ir.model.access.csv	2012-05-09 12:37:19 +0000
@@ -0,0 +1,3 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_openupgrade_record","openupgrade.record all","model_openupgrade_record",,1,0,0,0
+"access_openupgrade_attribute","openupgrade.attribute all","model_openupgrade_attribute",,1,0,0,0

=== added directory 'openerp/addons/openupgrade_records/view'
=== added file 'openerp/addons/openupgrade_records/view/analysis_wizard.xml'
--- openerp/addons/openupgrade_records/view/analysis_wizard.xml	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/view/analysis_wizard.xml	2012-05-09 12:37:19 +0000
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_openupgrade_analysis_wizard_form" model="ir.ui.view">
+            <field name="name">view.openupgrade.analysis_wizard.form</field>
+            <field name="model">openupgrade.analysis.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="OpenUpgrade Analysis Wizard">
+                    <field name="server_config" readonly="1"/>
+                    <field name="state"/>
+                    <field name="log" colspan="4"
+                           attrs="{'invisible': [('state', '!=', 'ready')]}"/>
+                    <field name="write"                           
+                           attrs="{'readonly': [('state', '!=', 'init')]}"/>
+                    <button icon="gtk-close"
+                            special="cancel"
+                            string="Close"
+                            />
+                    <button icon="gtk-ok"
+                            string="Create" 
+                            name="get_communication"
+                            type="object"
+                            states="init"
+                            />
+                </form>
+            </field>
+        </record>
+    </data>
+</openerp>

=== added file 'openerp/addons/openupgrade_records/view/comparison_config.xml'
--- openerp/addons/openupgrade_records/view/comparison_config.xml	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/view/comparison_config.xml	2012-05-09 12:37:19 +0000
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_openupgrade_comparison_config_tree" model="ir.ui.view">
+            <field name="name">view.openupgrade.comparison_config.tree</field>
+            <field name="model">openupgrade.comparison.config</field>
+            <field name="type">tree</field>
+            <field name="arch" type="xml">
+                <tree string="OpenUpgrade Comparison Config">
+                    <field name="name" select="1"/>
+                    <field name="protocol"/>
+                    <field name="server" select="1"/>
+                    <field name="port" select="1"/>
+                    <field name="database" select="1"/>
+                </tree>
+            </field>
+        </record>
+        <record id="view_openupgrade_comparison_config_form" model="ir.ui.view">
+            <field name="name">view.openupgrade.comparison_config.form</field>
+            <field name="model">openupgrade.comparison.config</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="OpenUpgrade Comparison Config">
+                    <field name="name"/>
+                    <field name="protocol"/>
+                    <field name="server"/>
+                    <field name="port"/>
+                    <field name="database"/>
+                    <field name="username"/>
+                    <field name="password" password="1"/>
+                    <button
+                        name="test_connection" 
+                        string="Test Connection"
+                        type="object" icon="gtk-network"
+                        colspan="2"
+                        />
+                    <newline/>
+                    <button 
+                        name="analyze"
+                        string="Perform Analysis"
+                        type="object" icon="gtk-execute"
+                        colspan="2"
+                        />
+                    <separator string="Last log" colspan="4"/>
+                    <field name="last_log" nolabel="1" colspan="4"/>
+                </form>
+            </field>
+        </record>
+        <record id="action_openupgrade_comparison_config_tree" model="ir.actions.act_window">
+            <field name="name">OpenUpgrade Comparison Configs</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">openupgrade.comparison.config</field>
+            <field name="view_type">form</field>
+        </record>
+        <menuitem
+            action="action_openupgrade_comparison_config_tree"
+            id="menu_openupgrade_comparison_config"
+            name="Comparison Configurations"
+            parent="menu_openupgrade"
+            />
+    </data>
+</openerp>

=== added file 'openerp/addons/openupgrade_records/view/generate_records_wizard.xml'
--- openerp/addons/openupgrade_records/view/generate_records_wizard.xml	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/view/generate_records_wizard.xml	2012-05-09 12:37:19 +0000
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_openupgrade_generate_records_wizard_form" model="ir.ui.view">
+            <field name="name">view.openupgrade.generate_records_wizard.form</field>
+            <field name="model">openupgrade.generate.records.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="OpenUpgrade Generate Records Wizard">
+                    <group states="init" colspan="4">
+                        <label string="This will reinitialize all the modules installed on this database. Do not continue if you use this database in production."
+                               />
+                        <button icon="gtk-close"
+                                special="cancel"
+                                string="Cancel"
+                                />
+                        <button icon="gtk-ok"
+                                string="Continue" 
+                                name="generate"
+                                type="object"
+                                />
+                    </group>
+                    <group states="ready" colspan="4">
+                        <label string="Modules initialized and records created"
+                               />
+                        <field name="state" invisible="1"/>
+                        <button icon="gtk-close"
+                                special="cancel"
+                                string="Close"
+                            />
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_generate_records" model="ir.actions.act_window">
+            <field name="name">Generate Records</field>
+	    <field name="type">ir.actions.act_window</field>
+            <field name="res_model">openupgrade.generate.records.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form,tree</field>
+            <field name="target">new</field>
+        </record>
+
+        <menuitem name="Generate Records"
+            id="menu_openupgrade_generate_records"
+            parent="menu_openupgrade"
+            action="action_generate_records"
+            sequence="15"/>
+
+    </data>
+</openerp>

=== added file 'openerp/addons/openupgrade_records/view/install_all_wizard.xml'
--- openerp/addons/openupgrade_records/view/install_all_wizard.xml	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/view/install_all_wizard.xml	2012-05-09 12:37:19 +0000
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_openupgrade_install_all_wizard_form" model="ir.ui.view">
+            <field name="name">view.openupgrade.install_all_wizard.form</field>
+            <field name="model">openupgrade.install.all.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="OpenUpgrade Install All Modules Wizard">
+                    <group states="init" colspan="4">
+                        <label string="This will install all modules on the database. Do not continue if you use this database in production." colspan="4"
+                               />
+                        <field name="to_install"/>
+                        <newline/>
+                        <button icon="gtk-close"
+                                special="cancel"
+                                string="Cancel"
+                                />
+                        <button icon="gtk-ok"
+                                string="Continue" 
+                                name="install_all"
+                                type="object"
+                                />
+                    </group>
+                    <group states="ready" colspan="4">
+                        <label string="Modules installed"
+                               />
+                        <field name="state" invisible="1"/>
+                        <button icon="gtk-close"
+                                special="cancel"
+                                string="Close"
+                            />
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_install_all" model="ir.actions.act_window">
+            <field name="name">Install All Modules</field>
+	    <field name="type">ir.actions.act_window</field>
+            <field name="res_model">openupgrade.install.all.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form,tree</field>
+            <field name="target">new</field>
+        </record>
+
+        <menuitem name="Install All Modules"
+            id="menu_openupgrade_install_all"
+            parent="menu_openupgrade"
+            action="action_install_all"
+            sequence="14"/>
+
+    </data>
+</openerp>

=== added file 'openerp/addons/openupgrade_records/view/openupgrade_record.xml'
--- openerp/addons/openupgrade_records/view/openupgrade_record.xml	1970-01-01 00:00:00 +0000
+++ openerp/addons/openupgrade_records/view/openupgrade_record.xml	2012-05-09 12:37:19 +0000
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <!-- Top level menu under 'Database structure' -->
+        <menuitem
+            id="menu_openupgrade"
+            name="OpenUpgrade Development"
+            parent="base.menu_administration"
+            sequence="99"
+            />
+        <record id="view_openupgrade_record_tree" model="ir.ui.view">
+            <field name="name">view.openupgrade.record.tree</field>
+            <field name="model">openupgrade.record</field>
+            <field name="type">tree</field>
+            <field name="arch" type="xml">
+                <tree string="OpenUpgrade Records">
+                    <field name="module" select="1"/>
+                    <field name="model" select="1"/>
+                    <field name="field" select="1"/>
+                    <field name="name" select="1"/>
+                    <field name="type" select="1"/>
+                    <field name="mode" select="1"/>
+                </tree>
+            </field>
+        </record>
+        <record id="view_openupgrade_record_form" model="ir.ui.view">
+            <field name="name">view.openupgrade.record.form</field>
+            <field name="model">openupgrade.record</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="OpenUpgrade Record">
+                    <field name="module" select="1"/>
+                    <field name="model" select="1"/>
+                    <field name="field" select="1"/>
+                    <field name="name" select="1"/>
+                    <field name="type" select="1"/>
+                    <field name="mode" select="1"/>
+                    <separator string="Attributes" colspan="4"/>
+                    <field name="attribute_ids" mode="tree,form" nolabel="1" colspan="4">
+                        <tree string="Attributes">
+                            <field name="name"/>
+                            <field name="value"/>
+                        </tree>
+                        <form string="Attribute">
+                            <field name="name"/>
+                            <field name="value"/>
+                        </form>
+                    </field>
+                </form>
+            </field>
+        </record>
+        <record id="action_openupgrade_record_tree" model="ir.actions.act_window">
+            <field name="name">OpenUpgrade Records</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">openupgrade.record</field>
+            <field name="view_type">form</field>
+        </record>
+        <menuitem
+            action="action_openupgrade_record_tree"
+            id="menu_openupgrade_records"
+            name="Records"
+            parent="menu_openupgrade"
+            />
+    </data>
+</openerp>

=== modified file 'openerp/modules/loading.py'
--- openerp/modules/loading.py	2012-03-09 14:44:43 +0000
+++ openerp/modules/loading.py	2012-05-09 12:37:19 +0000
@@ -66,6 +66,15 @@
 
 _logger = logging.getLogger(__name__)
 
+### OpenUpgrade
+def table_exists(cr, table):
+    """ Check whether a certain table or view exists """
+    cr.execute(
+        'SELECT count(relname) FROM pg_class WHERE relname = %s',
+        (table,))
+    return cr.fetchone()[0] == 1
+### End of OpenUpgrade
+
 def open_openerp_namespace():
     # See comment for open_openerp_namespace.
     if openerp.conf.deprecation.open_openerp_namespace:
@@ -144,8 +153,6 @@
             finally:
                 fp.close()
 
-    fields_logger = logging.getLogger('OpenUpgrade_FIELD')
-    xmlid_logger = logging.getLogger('OpenUpgrade_XMLID')
     local_registry = {}
     def get_repr(properties, type='val'):
         """ 
@@ -180,24 +187,12 @@
         if isinstance(model, osv.orm.TransientModel):
             return
 
+        model_registry = local_registry.setdefault(
+                model._name, {})
         if model._inherits:
-            properties = { 
-                'model': model._name,
-                'field': '_inherits',
-                'type': '',
-                'isfunction': '',
-                'relation': '',
-                'required': '',
-                'selection_keys': '',
-                'req_default': '',
-                'inherits': unicode(model._inherits),
-                }
-            local_registry[get_repr(properties, 'key')] = get_repr(
-                properties)
-        for k,v  in model._columns.items():
-            properties = { 
-                'model': model._name,
-                'field': k,
+            model_registry['_inherits'] = {'_inherits': unicode(model._inherits)}
+        for k, v in model._columns.items():
+            properties = { 
                 'type': v._type,
                 'isfunction': (
                     isinstance(v, osv.fields.function) and 'function' or ''),
@@ -224,45 +219,70 @@
                 else:
                     properties['req_default'] = unicode(
                         model._defaults[k])
-            local_registry[get_repr(properties, 'key')] = get_repr(
-                properties)
+            for key, value in properties.items():
+                if value:
+                    model_registry.setdefault(k, {})[key] = value
 
-    def compare_registries():
+    def get_record_id(cr, module, model, field, mode):
+        """
+        OpenUpgrade: get or create the id from the record table matching
+        the key parameter values
+        """
+        cr.execute(
+            "SELECT id FROM openupgrade_record "
+            "WHERE module = %s AND model = %s AND "
+            "field = %s AND mode = %s AND type = %s",
+            (module, model, field, mode, 'field')
+            )
+        record = cr.fetchone()
+        if record:
+            return record[0]
+        cr.execute(
+            "INSERT INTO openupgrade_record "
+            "(module, model, field, mode, type) "
+            "VALUES (%s, %s, %s, %s, %s)",
+            (module, model, field, mode, 'field')
+            )
+        cr.execute(
+            "SELECT id FROM openupgrade_record "
+            "WHERE module = %s AND model = %s AND "
+            "field = %s AND mode = %s AND type = %s",
+            (module, model, field, mode, 'field')
+            )
+        return cr.fetchone()[0]
+        
+    def compare_registries(cr, module):
         """
         OpenUpgrade: Compare the local registry with the global registry,
         log any differences and merge the local registry with
         the global one.
         """
-        for key in sorted(local_registry.keys()):
-            if key in registry:
-                if registry[key] != local_registry[key]:
-                    fields_logger.info(
-                        '"%s","modify",%s,%s', 
-                        package.name, key, local_registry[key])
-            else:
-                fields_logger.info(
-                    '"%s","create",%s,%s',
-                    package.name, key, local_registry[key])
-            registry[key] = local_registry[key]
-            
-    def log_xmlids(cr, package_name):
-        """
-        OpenUpgrade: Log all XMLID's owned by this package.
-        TODO: other modules can really easily add items that 'belong' to
-        another module. Needs deeper digging in the load_data methods.
-
-        Need to pass the cursor, as the one passed to the upper method is
-        closed by now.
-        """
-        cr.execute(
-            'select model, name from ir_model_data where module=%s '
-            'order by model, name', (package_name,))
-        for res in cr.fetchall():
-            xmlid_logger.info(
-                ','.join([
-                        "\"" + string.replace(property, '\"', '\'') + "\""
-                        for property in (res[0], res[1], package_name)
-                        ]))
+        if not table_exists(cr, 'openupgrade_record'):
+            return
+        for model, fields in local_registry.items():
+            registry.setdefault(model, {})
+            for field, attributes in fields.items():
+                old_field = registry[model].setdefault(field, {})
+                mode = old_field and 'modify' or 'create'
+                record_id = False
+                for key, value in attributes.items():
+                    if key not in old_field or old_field[key] != value:
+                        if not record_id:
+                            record_id = get_record_id(
+                                cr, module, model, field, mode)
+                        cr.execute(
+                            "SELECT id FROM openupgrade_attribute "
+                            "WHERE name = %s AND value = %s AND "
+                            "record_id = %s",
+                            (key, value, record_id)
+                            )
+                        if not cr.fetchone():
+                            cr.execute(
+                                "INSERT INTO openupgrade_attribute "
+                                "(name, value, record_id) VALUES (%s, %s, %s)",
+                                (key, value, record_id)
+                                )
+                        old_field[key] = value
 
     if status is None:
         status = {}
@@ -294,11 +314,10 @@
         loaded_modules.append(package.name)
         if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
             # OpenUpgrade: add this module's models to the registry
-            fields_logger.info('module %s', package.name)
             local_registry = {}
             for model in models:
                 log_model(model)
-            compare_registries()
+            compare_registries(cr, package.name)
 
             init_module_models(cr, package.name, models)
 
@@ -364,7 +383,6 @@
                 if hasattr(package, kind):
                     delattr(package, kind)
 
-        log_xmlids(cr, package.name) # OpenUpgrade
         cr.commit()
 
     # mark new res_log records as read

=== modified file 'openerp/openupgrade/__init__.py'
--- openerp/openupgrade/__init__.py	2012-01-15 11:39:02 +0000
+++ openerp/openupgrade/__init__.py	2012-05-09 12:37:19 +0000
@@ -1,1 +0,0 @@
-import openupgrade

=== added file 'openerp/openupgrade/doc/source/analyse.rst'
--- openerp/openupgrade/doc/source/analyse.rst	1970-01-01 00:00:00 +0000
+++ openerp/openupgrade/doc/source/analyse.rst	2012-05-09 12:37:19 +0000
@@ -0,0 +1,29 @@
+How to run your own analysis
+============================
+If you do need to run your own analysis, you need to perform the following
+steps (the awkward processing of the server log file is now obsolete).
+
+* Set up two OpenUpgrade servers of subsequent OpenERP releases
+
+* On both instances, install a database without demo data and 
+  install the *openupgrade_records* module, which is included in the
+  OpenUpgrade server distribution. This will add a menu 
+  *OpenUpgrade Development* to the Administration menu.
+
+* On both instances, install the modules that you need to write migration
+  scripts for, or alternatively select *Install All Modules* from the
+  Development menu.
+
+* On both instances: from the development menu, select the *Generate Records*
+  option.
+
+* On the target instance (this is the more recent version): from the
+  Development menu, select the *Comparison Config* option and
+  create a new config to connect to the other instance. In the config's
+  form, click on *Perform Analysis*.
+
+Note that in many of the operations above you may get a client timeout or a
+concurrent access error even if the operation completes successfully. You
+should be able to assertain a succesful operation by verifying that all
+modules involved are in an installed state and the analysis files in the
+module directories have an appropriate modification time.

=== modified file 'openerp/openupgrade/doc/source/analysis.rst'
--- openerp/openupgrade/doc/source/analysis.rst	2012-02-15 22:19:54 +0000
+++ openerp/openupgrade/doc/source/analysis.rst	2012-05-09 12:37:19 +0000
@@ -1,20 +1,22 @@
 Database analysis
 +++++++++++++++++
 
-In this chapter you will find more information on how you can review the
-differences between databases that
-different versions of OpenERP generate, using a module based perspective.
+Database analysis files are now included in the openupgrade-addons
+distribution, so if you need to develop migration scripts for the
+standard modules you do not need to run the analysis process yourself.
+You can find the analysis file in the module's migrations directory
+under the current version, in a file called openupgrade_analysis.txt
 
-The process of migrating a module from OpenERP 5 to OpenERP 6.0 is the same as
-migrating a module from OpenERP 6.0 to OpenERP 6.1, but the OpenERP log file is
-formatted slightly different in 6.1, so it needs to be processed accordingly.
+The analysis of the base module is included in the openupgrade-server
+distribution. This module includes an additional file,
+openupgrade_general_log.txt. This file contains some statistics as well
+as the analysis records of modules that could not be found in the target
+release of OpenERP.
 
 .. toctree::
    :maxdepth: 2
 
-   install5
-   install6
-   install61
+   analyse
    xmlids
    format
    strategies

=== removed file 'openerp/openupgrade/doc/source/install5.rst'
--- openerp/openupgrade/doc/source/install5.rst	2012-02-14 09:55:11 +0000
+++ openerp/openupgrade/doc/source/install5.rst	1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
-Step 1: Setup OpenERP 5 database
-================================
-
-Install the openupgrade server version 5. Configure logging to file.
-Create a new database. Install the module that you want to write an upgrade
-script for.
-Stop the openupgrade server version 5
-Delete the server log file.
-Start the openupgrade server with -u all -d <database> --stop-after-init
-
-Extract a csv file with the database layout per module, using the following
-command::
-
-	grep OpenUpgrade_FIELD <server-5.log> |cut -d \: -f 5- | sort > server-5.csv
-
-Extract a text file with the XML IDs created per module, using the following
-command::
-
-	grep OpenUpgrade_XMLID <server-5.log> |cut -d \: -f 5- | sort > xmlids-5.txt
-

=== removed file 'openerp/openupgrade/doc/source/install6.rst'
--- openerp/openupgrade/doc/source/install6.rst	2012-02-14 09:55:11 +0000
+++ openerp/openupgrade/doc/source/install6.rst	1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
-Step 2: Setup OpenERP 6 database
-================================
-
-Next, we repeat the process for version 6.
-
-Install the openupgrade server version 6. Configure logging to file.
-Create a new database. Install the module that you want to write an upgrade
-script for.
-Stop the openupgrade server version 6
-Delete the server log file.
-Start the openupgrade server with -u all -d <database> --stop-after-init
-
-Extract a csv file with the database layout per module, using the following
-command::
-
-	grep OpenUpgrade_FIELD <server-6.log> |cut -d \: -f 5- | sort > server-6.csv
-
-Extract a text file with the XML IDs created per module, using the following
-command::
-
-	grep OpenUpgrade_XMLID <server-6.log> |cut -d \: -f 5- | sort > xmlids-6.txt
-
-Perform a rough matching mechanism on the csv files:
-
-	/path/to/openupgrade-server/bin/openupgrade/process-csv.py server-5.csv server-6.csv
-
-Save the results as a starting point for your work. See below for a description
-of the output.

=== removed file 'openerp/openupgrade/doc/source/install61.rst'
--- openerp/openupgrade/doc/source/install61.rst	2012-02-17 15:05:04 +0000
+++ openerp/openupgrade/doc/source/install61.rst	1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
-Step 2: Setup OpenERP 6.1 database
-==================================
-
-To extract the necessary information for OpenERP 6.1, install the openupgrade
-server version 6.1. Configure logging to file.
-Create a new database. Install the module that you want to write an upgrade
-script for.
-Stop the openupgrade server version 6.1
-Delete the server log file.
-Start the openupgrade server with -u all -d <database> --stop-after-init
-
-Extract a csv file with the database layout per module, using the following
-command::
-
-	grep OpenUpgrade_FIELD <server-6.1.log> |cut -d \  -f 7- | sort > server-6.1.csv
-
-Extract a text file with the XML IDs created per module, using the following
-command (note that this is slightly different from previous server versions)::
-
-	grep OpenUpgrade_XMLID <server-6.1.log> |cut -d \  -f 7- | sort > xmlids-6.1.txt
-
-Perform a rough matching mechanism on the csv files:
-
-	/path/to/openupgrade-server/bin/openupgrade/process-csv.py old-server.csv new-server.csv
-
-Save the results as a starting point for your work. See below for a description
-of the output.

=== modified file 'openerp/openupgrade/doc/source/modules60-61.rst'
--- openerp/openupgrade/doc/source/modules60-61.rst	2012-03-01 09:13:40 +0000
+++ openerp/openupgrade/doc/source/modules60-61.rst	2012-05-09 12:37:19 +0000
@@ -56,7 +56,7 @@
 +------------------------------+------------------------------+
 |base_calendar                 | Done                         |
 +------------------------------+------------------------------+
-|base_contact                  |                              |
+|base_contact                  | Done                         |
 +------------------------------+------------------------------+
 |base_crypt                    | Nothing to do                |
 +------------------------------+------------------------------+

=== modified file 'openerp/openupgrade/doc/source/status.rst'
--- openerp/openupgrade/doc/source/status.rst	2012-03-01 09:13:40 +0000
+++ openerp/openupgrade/doc/source/status.rst	2012-05-09 12:37:19 +0000
@@ -16,3 +16,9 @@
      
      * Documentation for developers and users. You are currently reading it. The documentation is maintained in the latest server branch. Status: always to be improved upon!
 
+.. toctree::
+   :maxdepth: 2
+
+   modules60-61
+
+

=== modified file 'openerp/openupgrade/doc/source/xmlids.rst'
--- openerp/openupgrade/doc/source/xmlids.rst	2012-02-15 22:19:54 +0000
+++ openerp/openupgrade/doc/source/xmlids.rst	2012-05-09 12:37:19 +0000
@@ -1,15 +1,14 @@
 XML IDs
 ========
-Create a diff file of the XML IDs between the two database versions:
-
-       diff xmlids-5.txt xmlids-6.txt > xmlids.diff
-
-This will give you a clear overview of the resources that are created by the
-modules. If you accidentally created the analysis from databases containing
+The OpenUpgrade analysis files give a representation of the XML IDs that a
+module defines, in comparison with the previous release of the module.
+
+Note, that if you run your own analysis on databases containing
 demo data, you will get a lot of noise here. 
 
 XML IDs which do not occur in the updated version of all installed modules
-will be removed automatically by the OpenERP server. 
+will be removed automatically by the OpenERP server, if they do not have
+the noupdate attribute. 
 
 You can ignore most entries here, most notably
 
@@ -63,4 +62,3 @@
 
 [1] You might want to use this information to semi-automatically audit any manual
 customizations. This subject falls out of scope of this project for now)
-

=== modified file 'openerp/openupgrade/openupgrade.py'
--- openerp/openupgrade/openupgrade.py	2012-03-06 22:36:49 +0000
+++ openerp/openupgrade/openupgrade.py	2012-05-09 12:37:19 +0000
@@ -4,11 +4,12 @@
 import pooler
 import logging
 import tools
+import openupgrade_tools
 
 logger = logging.getLogger('OpenUpgrade')
 
 __all__ = [
-    'load_xml',
+    'load_data',
     'rename_columns',
     'rename_tables',
     'drop_columns',
@@ -61,7 +62,9 @@
     finally:
         fp.close()
 
+# for backwards compatibility
 load_xml = load_data
+table_exists = openupgrade_tools.table_exists
 
 def rename_columns(cr, column_spec):
     """
@@ -212,13 +215,6 @@
         logger.warn('No rows affected for query "%s"', query)
     return res
 
-def table_exists(cr, table):
-    """ Check whether a certain table or view exists """
-    cr.execute(
-        'SELECT count(relname) FROM pg_class WHERE relname = %s',
-        (table,))
-    return cr.fetchone()[0] == 1
-
 def column_exists(cr, table, column):
     """ Check whether a certain column exists """
     cr.execute(

=== added file 'openerp/openupgrade/openupgrade_log.py'
--- openerp/openupgrade/openupgrade_log.py	1970-01-01 00:00:00 +0000
+++ openerp/openupgrade/openupgrade_log.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+from openupgrade_tools import table_exists
+
+def log_xml_id(cr, module, xml_id):
+    """
+    Log xml_ids at load time in the records table.
+    Called from openerp/tools/convert.py:xml_import._test_xml_id()
+
+    # Catcha's
+    - The module needs to be loaded with 'init', or the calling method
+    won't be called. This can be brought about by installing the
+    module or updating the 'state' field of the module to 'to install'
+    or call the server with '--init <module>' and the database argument.
+    
+    - Do you get the right results immediately when installing the module?
+    No, sorry. This method retrieves the model from the ir_model_table, but when
+    the xml id is encountered for the first time, this method is called
+    before the item is present in this table. Therefore, you will not
+    get any meaningful results until the *second* time that you 'init'
+    the module.
+
+    - The good news is that the openupgrade_records module that comes
+    with this distribution allows you to deal with all of this with
+    one click on the menu item Settings -> Customizations ->
+    Database Structure -> OpenUpgrade -> Generate Records
+
+    - You cannot reinitialize the modules in your production database
+    and expect to keep working on it happily ever after. Do not perform
+    this routine on your production database.
+
+    :param module: The module that contains the xml_id
+    :param xml_id: the xml_id, with or without 'module.' prefix
+    """
+    if not table_exists(cr, 'openupgrade_record'):
+        return
+    if not '.' in xml_id:
+        xml_id = '%s.%s' % (module, xml_id)
+    cr.execute(
+        "SELECT model FROM ir_model_data "
+        "WHERE module = %s AND name = %s",
+        xml_id.split('.'))
+    record = cr.fetchone()
+    if not record:
+        print "Cannot find xml_id %s" % xml_id
+        return
+    else:
+        cr.execute(
+            "SELECT id FROM openupgrade_record "
+            "WHERE module=%s AND model=%s AND name=%s AND type=%s",
+            (module, record[0], xml_id, 'xmlid'))
+        if not cr.fetchone():
+            cr.execute(
+                "INSERT INTO openupgrade_record "
+                "(module, model, name, type) values(%s, %s, %s, %s)",
+                (module, record[0], xml_id, 'xmlid'))
+

=== added file 'openerp/openupgrade/openupgrade_tools.py'
--- openerp/openupgrade/openupgrade_tools.py	1970-01-01 00:00:00 +0000
+++ openerp/openupgrade/openupgrade_tools.py	2012-05-09 12:37:19 +0000
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+def table_exists(cr, table):
+    """ Check whether a certain table or view exists """
+    cr.execute(
+        'SELECT count(relname) FROM pg_class WHERE relname = %s',
+        (table,))
+    return cr.fetchone()[0] == 1
+

=== modified file 'openerp/tools/convert.py'
--- openerp/tools/convert.py	2012-03-02 11:28:34 +0000
+++ openerp/tools/convert.py	2012-05-09 12:37:19 +0000
@@ -62,6 +62,8 @@
 unsafe_eval = eval
 from safe_eval import safe_eval as eval
 
+from openerp.openupgrade import openupgrade_log
+
 class ConvertError(Exception):
     def __init__(self, doc, orig_excpt):
         self.d = doc
@@ -256,6 +258,7 @@
 
         if len(id) > 64:
             _logger.error('id: %s is to long (max: 64)', id)
+        openupgrade_log.log_xml_id(self.cr, self.module, xml_id)
 
     def _tag_delete(self, cr, rec, data_node=None):
         d_model = rec.get("model",'')

=== modified file 'openerp/tools/sql.py'
--- openerp/tools/sql.py	2009-10-20 10:52:23 +0000
+++ openerp/tools/sql.py	2012-05-09 12:37:19 +0000
@@ -22,7 +22,8 @@
 def drop_view_if_exists(cr, viewname):
     cr.execute("select count(1) from pg_class where relkind=%s and relname=%s", ('v', viewname,))
     if cr.fetchone()[0]:
-        cr.execute("DROP view %s" % (viewname,))
+        # OpenUpgrade: add CASCADE
+        cr.execute("DROP view %s CASCADE" % (viewname,))
         cr.commit()
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:


Follow ups