Mercurial > kallithea
changeset 4224:1142ebbf04cd kallithea-2.2.5-rebrand
db: introduce kallithea/bin/rebranddb.py script for changing branding of database
author | Bradley M. Kuhn <bkuhn@sfconservancy.org> |
---|---|
date | Wed, 02 Jul 2014 19:08:38 -0400 |
parents | 400fbab35389 |
children | 3e6291d99a6f |
files | kallithea/bin/rebranddb.py |
diffstat | 1 files changed, 174 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/bin/rebranddb.py Wed Jul 02 19:08:38 2014 -0400 @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Script for rebranding of database to and from what Kallithea expects + +Works on databases from v1.7.2 to v2.2.5 +""" + +import os +import sys +from sqlalchemy import * +import sqlalchemy.orm +import sqlalchemy.ext.declarative +import migrate.changeset # a part of sqlalchemy-migrate which is available on pypi + +def do_migrate(db, old, new): + print 'Migrating %s from %s to %s' % (db, old or '?', new) + metadata = MetaData() + metadata.bind = create_engine(db) + metadata.reflect() + assert metadata.tables, 'Cannot reflect table names from db' + + if not old: + assert 'db_migrate_version' in metadata.tables, 'Cannot reflect db_migrate_version from db' + t = metadata.tables['db_migrate_version'] + l = t.select().where(t.c.repository_path == 'versions').execute().fetchall() + assert len(l) == 1, 'Cannot find a single versions entry in db_migrate_version' + assert l[0].repository_id.endswith('_db_migrations') + old = l[0].repository_id[:-len('_db_migrations')] + print 'Detected migration from old name %s' % old + if new != old: + assert not t.select().where(t.c.repository_id == new + '_db_migrations').execute().fetchall(), 'db_migrate_version has entries for both old and new name' + + def tablename(brand, s): + return s if brand == 'kallithea' else (brand + '_' + s) + new_ui_name = tablename(new, 'ui') + old_ui_name = tablename(old, 'ui') + new_settings_name = tablename(new, 'settings') + old_settings_name = tablename(old, 'settings') + + # Table renames using sqlalchemy-migrate (available on pypi) + if new_ui_name == old_ui_name: + print 'No renaming of %s' % new_ui_name + else: + try: + t = metadata.tables[old_ui_name] + print 'Renaming', t, 'to', new_ui_name + migrate.changeset.rename_table(t, new_ui_name) + except KeyError, e: + print 'Not renaming ui:', e + + if new_settings_name == old_settings_name: + print 'No renaming of %s' % new_settings_name + else: + try: + t = metadata.tables[old_settings_name] + print 'Renaming', t, 'to', new_settings_name + migrate.changeset.rename_table(t, new_settings_name) + except KeyError, e: + print 'Not renaming settings:', e + + # using this API because ... dunno ... it is simple and works + conn = metadata.bind.connect() + trans = conn.begin() + t = metadata.tables['users'] + + print 'Bulk fixing of User extern_name' + try: + t.c.extern_name + except AttributeError: + print 'No extern_name to rename' + else: + t.update().where(t.c.extern_name == old).values(extern_name=new).execute() + + print 'Bulk fixing of User extern_type' + try: + t.c.extern_type + except AttributeError: + print 'No extern_type to rename' + else: + t.update().where(t.c.extern_type == old).values(extern_type=new).execute() + + trans.commit() + + # For the following conversions, use ORM ... and create stub models that works for that purpose + Base = sqlalchemy.ext.declarative.declarative_base() + + class Ui(Base): + __tablename__ = new_ui_name + ui_id = Column("ui_id", Integer(), primary_key=True) + ui_section = Column("ui_section", String()) + ui_key = Column("ui_key", String()) + ui_value = Column("ui_value", String()) + ui_active = Column("ui_active", Boolean()) + + class Setting(Base): + __tablename__ = new_settings_name + app_settings_id = Column("app_settings_id", Integer(), primary_key=True) + app_settings_name = Column("app_settings_name", String()) + app_settings_value = Column("app_settings_value", String()) + #app_settings_type = Column("app_settings_type", String()) # not present in v1.7.2 + + class DbMigrateVersion(Base): + __tablename__ = 'db_migrate_version' + repository_id = Column('repository_id', String(), primary_key=True) + repository_path = Column('repository_path', Text) + version = Column('version', Integer) + + Session = sqlalchemy.orm.sessionmaker(bind=metadata.bind) + session = Session() + + print 'Fixing hook names' + + oldhooks = u'python:%s.lib.hooks.' % old + newhooks = u'python:%s.lib.hooks.' % new + for u in session.query(Ui).filter(Ui.ui_section == 'hooks').all(): + if u.ui_value.startswith(oldhooks): + print '- fixing %s' % u.ui_key + u.ui_value = newhooks + u.ui_value[len(oldhooks):] + session.add(u) + session.commit() + + print 'Fixing auth module names' + old_auth_name = 'internal' if old == 'kallithea' else old + new_auth_name = 'internal' if new == 'kallithea' else new + for s in session.query(Setting).filter(Setting.app_settings_name == 'auth_plugins').all(): + print '- fixing %s' % s.app_settings_name + s.app_settings_value = (s.app_settings_value + .replace(old + '.lib.auth_modules.auth_', new + '.lib.auth_modules.auth_') + .replace('.auth_modules.auth_' + old_auth_name, '.auth_modules.auth_' + new_auth_name)) + session.add(s) + for s in session.query(Setting).filter(Setting.app_settings_name == 'auth_' + old_auth_name + '_enabled').all(): + print '- fixing %s' % s.app_settings_name + s.app_settings_name = 'auth_' + new_auth_name + '_enabled' + session.add(s) + session.commit() + + print 'Fixing db migration version number' + for s in session.query(DbMigrateVersion).filter(DbMigrateVersion.repository_id == old + '_db_migrations', DbMigrateVersion.repository_path == 'versions').all(): + print '- fixing %s' % s.repository_id + s.repository_id = new + '_db_migrations' + session.commit() + + print 'Done' + +def main(argv): + if len(argv) < 2 or argv[1] in ['-h', '--help']: + print 'usage: kallithea/bin/rebranddb.py DBSTRING [NEW] [OLD]' + print ' where DBSTRING is the value of sqlalchemy.db1.url from the .ini,' + print ' NEW defaults to "kallithea", OLD is by default detected from the db"' + raise SystemExit(0) + db = argv[1] + new = 'kallithea' + if len(argv) > 2: + new = argv[2] + old = None + if len(argv) > 3: + old = argv[3] + do_migrate(argv[1], old, new) + +if __name__ == '__main__': + main(sys.argv)