Aftar install and configure OpenUpgrade on your local linux:
python3 ./migrate3.py --config=odoo12-server.conf --database=mydb12 --run-migrations=12.0,13.0 --branch-dir=/var/tmp/openupgrade
| #!/usr/bin/env python3 | |
| import os | |
| import sys | |
| try: | |
| import StringIO ## for Python 2 | |
| except ImportError: | |
| import io as StringIO ## for Python 3 | |
| from functools import reduce | |
| import psycopg2 | |
| import psycopg2.extensions | |
| from optparse import OptionParser | |
| try: | |
| from ConfigParser import SafeConfigParser | |
| except: | |
| from configparser import ConfigParser as SafeConfigParser | |
| try: | |
| import bzrlib.plugin | |
| import bzrlib.builtins | |
| except ImportError: | |
| pass | |
| def copy_database(conn_parms): | |
| db_old = conn_parms['database'] | |
| db_new = '%s_migrated' % conn_parms['database'] | |
| print('copying database %(db_old)s to %(db_new)s...' % {'db_old': db_old, | |
| 'db_new': db_new}) | |
| if conn_parms.get('host') == 'False': | |
| del conn_parms['host'] | |
| del conn_parms['port'] | |
| conn = psycopg2.connect(**conn_parms) | |
| conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) | |
| cur = conn.cursor() | |
| cur.execute('drop database if exists "%(db)s"' % {'db': db_new}) | |
| try: | |
| print("Copying the database using 'with template'") | |
| cur.execute('create database "%(db_new)s" with template "%(db_old)s"' % | |
| {'db_new': db_new, 'db_old': db_old}) | |
| cur.close() | |
| except psycopg2.OperationalError: | |
| print("Failed, fallback on creating empty database + loading a dump") | |
| cur.execute('create database "%(db)s"' % {'db': db_new}) | |
| cur.close() | |
| os.environ['PGUSER'] = conn_parms['user'] | |
| if conn_parms.get('host') and not os.environ.get('PGHOST'): | |
| os.environ['PGHOST'] = conn_parms['host'] | |
| if conn_parms.get('port') and not os.environ.get('PGPORT'): | |
| os.environ['PGPORT'] = conn_parms['port'] | |
| password_set = False | |
| if conn_parms.get('password') and not os.environ.get('PGPASSWORD'): | |
| os.environ['PGPASSWORD'] = conn_parms['password'] | |
| password_set = True | |
| os.system( | |
| ('pg_dump --format=custom --no-password %(db_old)s ' + | |
| '| pg_restore --no-password --dbname=%(db_new)s') % | |
| {'db_old': db_old, 'db_new': db_new} | |
| ) | |
| if password_set: | |
| del os.environ['PGPASSWORD'] | |
| return db_new | |
| migrations = { | |
| '14.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '14.0', | |
| 'addons_dir': os.path.join('odoo', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'odoo-bin --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '13.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '13.0', | |
| 'addons_dir': os.path.join('odoo', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'odoo-bin --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '12.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '12.0', | |
| 'addons_dir': os.path.join('odoo', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'odoo-bin --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '11.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '11.0', | |
| 'addons_dir': os.path.join('odoo', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'odoo-bin --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '10.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '10.0', | |
| 'addons_dir': os.path.join('odoo', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'odoo-bin --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '9.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '9.0', | |
| 'addons_dir': os.path.join('openerp', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'openerp-server --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '8.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '8.0', | |
| 'addons_dir': os.path.join('openerp', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'openerp-server --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc', | |
| }, | |
| }, | |
| '7.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '7.0', | |
| 'addons_dir': os.path.join('openerp', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'openerp-server --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc ' | |
| '--no-netrpc', | |
| }, | |
| }, | |
| '6.1': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '6.1', | |
| 'addons_dir': os.path.join('openerp', 'addons'), | |
| 'root_dir': os.path.join(''), | |
| 'cmd': 'openerp-server --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc ' | |
| '--no-netrpc', | |
| }, | |
| }, | |
| '6.0': { | |
| 'addons': { | |
| 'addons': { | |
| 'type': 'link', | |
| 'url': os.path.join('server', 'addons'), | |
| }, | |
| }, | |
| 'server': { | |
| 'type': 'git', | |
| 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', | |
| 'branch': '6.0', | |
| 'addons_dir': os.path.join('bin', 'addons'), | |
| 'root_dir': os.path.join('bin'), | |
| 'cmd': 'bin/openerp-server.py --update=all --database=%(db)s ' | |
| '--config=%(config)s --stop-after-init --no-xmlrpc ' | |
| '--no-netrpc', | |
| }, | |
| }, | |
| } | |
| config = SafeConfigParser() | |
| parser = OptionParser( | |
| description='Migrate script for the impatient or lazy. ' | |
| 'Makes a copy of your database, downloads the files necessary to migrate ' | |
| 'it as requested and runs the migration on the copy (so your original ' | |
| 'database will not be touched). While the migration is running only ' | |
| 'errors are shown, for a detailed log see ${branch-dir}/migration.log') | |
| parser.add_option( | |
| "-C", "--config", action="store", type="string", | |
| dest="config", | |
| help="current openerp config (required)") | |
| parser.add_option( | |
| "-D", "--database", action="store", type="string", | |
| dest="database", | |
| help="current openerp database (required if not given in config)") | |
| parser.add_option( | |
| "-B", "--branch-dir", action="store", type="string", | |
| dest="branch_dir", | |
| help="the directory to download openupgrade-server code to [%default]", | |
| default='/var/tmp/openupgrade') | |
| parser.add_option( | |
| "-R", "--run-migrations", action="store", type="string", | |
| dest="migrations", | |
| help="comma separated list of migrations to run, ie. \"" + | |
| ','.join(sorted([a for a in migrations])) + | |
| "\" (required)") | |
| parser.add_option( | |
| "-A", "--add", action="store", type="string", dest="add", | |
| help="load a python module that declares a dict " | |
| "'migrations' which is merged with the one of this script " | |
| "(see the source for details). You also can pass a string " | |
| "that evaluates to a dict. For the banking addons, pass " | |
| "\"{'6.1': {'addons': {'banking': 'lp:banking-addons/6.1'}}}\"") | |
| parser.add_option("-I", "--inplace", action="store_true", dest="inplace", | |
| help="don't copy database before attempting upgrade " | |
| "(dangerous)") | |
| parser.add_option( | |
| "-F", "--force-deps", action="store", dest="force_deps", | |
| help="force dependencies from a dict of the form \"{'module_name': " | |
| "['new_dependency1', 'new_dependency2']}\"") | |
| (options, args) = parser.parse_args() | |
| if not options.config or not options.migrations\ | |
| or not reduce(lambda a, b: a and (b in migrations), options.migrations.split(','), True): | |
| parser.print_help() | |
| sys.exit() | |
| config.read(options.config) | |
| conn_parms = {} | |
| for parm in ('host', 'port', 'user', 'password'): | |
| db_parm = 'db_' + parm | |
| if config.has_option('options', db_parm): | |
| conn_parms[parm] = config.get('options', db_parm) | |
| if 'user' not in conn_parms: | |
| print('No user found in configuration') | |
| sys.exit() | |
| db_name = options.database or config.get('options', 'db_name') | |
| if not db_name or db_name == '' or db_name.isspace()\ | |
| or db_name.lower() == 'false': | |
| parser.print_help() | |
| sys.exit() | |
| conn_parms['database'] = db_name | |
| if options.force_deps: | |
| try: | |
| eval(options.force_deps) | |
| except: | |
| parser.print_help() | |
| sys.exit() | |
| if options.add: | |
| merge_migrations = {} | |
| if os.path.isfile(options.add): | |
| import imp | |
| merge_migrations_mod = imp.load_source('merge_migrations_mod', | |
| options.add) | |
| merge_migrations = merge_migrations_mod.migrations | |
| else: | |
| try: | |
| merge_migrations = eval(options.add) | |
| except: | |
| parser.print_help() | |
| sys.exit() | |
| def deep_update(dict1, dict2): | |
| result = {} | |
| for (name, value) in dict1.items(): | |
| if name in dict2: | |
| if isinstance(dict1[name], dict) and isinstance(dict2[name], | |
| dict): | |
| result[name] = deep_update(dict1[name], dict2[name]) | |
| else: | |
| result[name] = dict2[name] | |
| else: | |
| result[name] = dict1[name] | |
| for (name, value) in dict2.items(): | |
| if name not in dict1: | |
| result[name] = value | |
| return result | |
| migrations = deep_update(migrations, merge_migrations) | |
| for version in options.migrations.split(','): | |
| if version not in migrations: | |
| print('%s is not a valid version! (valid verions are %s)' % ( | |
| version, | |
| ','.join(sorted([a for a in migrations])))) | |
| logfile = os.path.join(options.branch_dir, 'migration.log') | |
| print(logfile) | |
| if not os.path.exists(options.branch_dir): | |
| os.mkdir(options.branch_dir) | |
| for version in options.migrations.split(','): | |
| if not os.path.exists(os.path.join(options.branch_dir, version)): | |
| os.mkdir(os.path.join(options.branch_dir, version)) | |
| for (name, addon_config) in dict( | |
| migrations[version]['addons'], | |
| server=migrations[version]['server']).items(): | |
| addon_config = addon_config\ | |
| if isinstance(addon_config, dict)\ | |
| else {'url': addon_config} | |
| addon_config_type = addon_config.get('type', 'bzr') | |
| if os.path.exists(os.path.join(options.branch_dir, version, name)): | |
| if addon_config_type == 'link': | |
| continue | |
| elif addon_config_type == 'bzr': | |
| bzrlib.plugin.load_plugins() | |
| bzrlib.trace.enable_default_logging() | |
| cmd_revno = bzrlib.builtins.cmd_revno() | |
| cmd_revno.outf = StringIO.StringIO() | |
| cmd_revno.run(location=os.path.join(options.branch_dir, | |
| version, | |
| name)) | |
| print ('updating %s rev%s' % ( | |
| os.path.join(version, name), | |
| cmd_revno.outf.getvalue().strip())) | |
| cmd_update = bzrlib.builtins.cmd_update() | |
| cmd_update.outf = StringIO.StringIO() | |
| cmd_update.outf.encoding = 'utf8' | |
| cmd_update.run( | |
| dir=os.path.join(options.branch_dir, version, name)) | |
| if hasattr(cmd_update, '_operation'): | |
| cmd_update.cleanup_now() | |
| print ('now at rev' + cmd_revno.outf.getvalue().strip()) | |
| elif addon_config_type == 'git': | |
| os.system('cd %(location)s; git pull origin %(branch)s' % { | |
| 'branch': addon_config.get('branch', 'master'), | |
| 'location': os.path.join(options.branch_dir, | |
| version, | |
| name), | |
| }) | |
| else: | |
| raise Exception('Unknown type %s' % addon_config_type) | |
| else: | |
| if addon_config_type == 'link': | |
| print ('linking %s to %s' % (addon_config['url'], | |
| os.path.join(options.branch_dir, | |
| version, | |
| name))) | |
| os.symlink(addon_config['url'], | |
| os.path.join(options.branch_dir, version, name)) | |
| elif addon_config_type == 'bzr': | |
| bzrlib.plugin.load_plugins() | |
| bzrlib.trace.enable_default_logging() | |
| print ('getting ' + addon_config['url']) | |
| cmd_checkout = bzrlib.builtins.cmd_checkout() | |
| cmd_checkout.outf = StringIO.StringIO() | |
| cmd_checkout.run( | |
| addon_config['url'], | |
| os.path.join(options.branch_dir, version, name), | |
| lightweight=True) | |
| elif addon_config_type == 'git': | |
| print ('getting ' + addon_config['url']) | |
| os.system('git clone --branch %(branch)s --single-branch ' | |
| '--depth=1 %(url)s %(target)s' % | |
| { | |
| 'branch': addon_config.get('branch', 'master'), | |
| 'url': addon_config['url'], | |
| 'target': os.path.join(options.branch_dir, | |
| version, | |
| name), | |
| }) | |
| else: | |
| raise Exception('Unknown type %s' % addon_config_type) | |
| openupgradelib = os.path.join(options.branch_dir, 'openupgradelib') | |
| if os.path.exists(openupgradelib): | |
| os.system('cd %(location)s; git pull origin master' % { | |
| 'location': openupgradelib, | |
| }) | |
| else: | |
| os.system( | |
| 'git clone --single-branch --depth=1 %(url)s %(target)s' % { | |
| 'url': 'https://github.com/OCA/openupgradelib', | |
| 'target': openupgradelib, | |
| }) | |
| os.environ['PYTHONPATH'] = ':'.join(filter(None, [ | |
| openupgradelib, os.environ.get('PYTHONPATH')])) | |
| db_name = conn_parms['database'] | |
| if not options.inplace: | |
| db_name = copy_database(conn_parms) | |
| for version in options.migrations.split(','): | |
| print ('running migration for '+version) | |
| config.set('options', 'without_demo', 'True') | |
| config.set('options', 'logfile', logfile) | |
| config.set('options', 'port', 'False') | |
| config.set('options', 'netport', 'False') | |
| config.set('options', 'xmlrpc_port', 'False') | |
| config.set('options', 'netrpc_port', 'False') | |
| config.set( | |
| 'options', | |
| 'addons_path', | |
| ','.join( | |
| [os.path.join(options.branch_dir, | |
| version, | |
| 'server', | |
| migrations[version]['server']['addons_dir'])] + | |
| [os.path.join(options.branch_dir, | |
| version, | |
| name, | |
| addon_conf.get('addons_dir', '') | |
| if isinstance(addon_conf, dict) else '') | |
| for (name, addon_conf) | |
| in migrations[version]['addons'].items()])) | |
| config.set( | |
| 'options', | |
| 'root_path', | |
| os.path.join( | |
| options.branch_dir, | |
| version, | |
| 'server', | |
| migrations[version]['server']['root_dir'])) | |
| if options.force_deps: | |
| if not config.has_section('openupgrade'): | |
| config.add_section('openupgrade') | |
| config.set('openupgrade', 'force_deps', options.force_deps) | |
| config.write( | |
| open( | |
| os.path.join(options.branch_dir, version, 'server.cfg'), 'w+')) | |
| os.system( | |
| os.path.join( | |
| options.branch_dir, | |
| version, | |
| 'server', | |
| migrations[version]['server']['cmd'] % { | |
| 'db': db_name, | |
| 'config': os.path.join(options.branch_dir, version, | |
| 'server.cfg') | |
| })) |