def make_update_script_for_model(cls, engine, oldmodel, model, repository, **opts): """Create a migration script""" # Compute differences. if isinstance(repository, basestring): # oh dear, an import cycle! from migrate.versioning.repository import Repository repository = Repository(repository) oldmodel = load_model(oldmodel) model = load_model(model) diff = schemadiff.getDiffOfModelAgainstModel( oldmodel, model, engine, excludeTables=[repository.version_table]) decls, upgradeCommands, downgradeCommands = \ genmodel.ModelGenerator(diff).toUpgradeDowngradePython() # Store differences into file. template_file = None src = template.get_script(template_file) contents = open(src).read() search = 'def upgrade():' contents = contents.replace(search, '\n\n'.join((decls, search)), 1) if upgradeCommands: contents = contents.replace(' pass', upgradeCommands, 1) if downgradeCommands: contents = contents.replace(' pass', downgradeCommands, 1) return contents
def commit_db_model(db_uri, db_repo, model_dotted_name, commit_msg): logger.info( "Committing new change on model : {}".format(model_dotted_name)) # Test if the migrate repository exists if not os.path.isdir(db_repo): raise OSError(2, "Migrate repository doesn't exists ! ", db_repo) new_model = load_model(model_dotted_name) # Display detected changes to user print("------------------------------") print(mapi.compare_model_to_db(db_uri, db_repo, new_model)) print("------------------------------") if not confirm( "Are these changes correct (ignored tables {} are listed here but will be ignored ) ?" .format(IGNORED_TABLES)): logger.info("Changes not confirmed aborting :(") return with TemporaryDirectory(prefix="OPVDBMigrate") as temp_dir: sys.path.append(temp_dir) # Used to read generated python old_model_fpath = Path(temp_dir) / "oldmodel.py" # generating old model from database logger.info("Generated old model python script from database") old_model_source = mapi.create_model(db_uri, db_repo) logger.debug("Old model python : \n {}".format(old_model_source)) old_model_source = correction_geography(old_model_source) save_to_file(old_model_source, old_model_fpath) # get latest version new_version = mapi.version(db_repo) + 1 update_script_path = Path( db_repo) / "versions" / get_update_script_name( new_version, commit_msg) logger.debug("Lastest version in repository {} is {}".format( db_repo, new_version)) # make_update_script_for_model, save it in repo lastest_version + 1 + commit msg oldmodel = load_model('oldmodel:meta') oldmodel = filter_tables(oldmodel, IGNORED_TABLES) update_script_source = mapi.make_update_script_for_model( db_uri, db_repo, oldmodel, new_model) print(update_script_source) input("Wait ... ") save_to_file(update_script_source, update_script_path) if confirm( "Did you check (and modify if necessary) the upgrade script ({}) ? !! Confirm will upgrade the database !!" .format(update_script_path)): logger.info("Upgrading the database") # upgrade mapi.upgrade(db_uri, db_repo) logger.info("Migration done and versionned :) ") else: logger.info("Removing the update script") os.unlink(update_script_path)
def make_update_script_for_model(cls, engine, oldmodel, model, repository, **opts): """Create a migration script based on difference between two SA models. :param repository: path to migrate repository :param oldmodel: dotted.module.name:SAClass or SAClass object :param model: dotted.module.name:SAClass or SAClass object :param engine: SQLAlchemy engine :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>` :type oldmodel: string or Class :type model: string or Class :type engine: Engine instance :returns: Upgrade / Downgrade script :rtype: string """ if isinstance(repository, basestring): # oh dear, an import cycle! from migrate.versioning.repository import Repository repository = Repository(repository) oldmodel = load_model(oldmodel) model = load_model(model) # Compute differences. diff = schemadiff.getDiffOfModelAgainstModel( model, oldmodel, excludeTables=[repository.version_table]) # TODO: diff can be False (there is no difference?) decls, upgradeCommands, downgradeCommands = \ genmodel.ModelGenerator(diff,engine).genB2AMigration() # Store differences into file. src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None)) f = open(src) contents = f.read() f.close() # generate source search = 'def upgrade(migrate_engine):' contents = contents.replace(search, '\n\n'.join((decls, search)), 1) if upgradeCommands: contents = contents.replace(' pass', upgradeCommands, 1) if downgradeCommands: contents = contents.replace(' pass', downgradeCommands, 1) return contents
def make_update_script_for_model(cls, engine, oldmodel, model, repository, **opts): """Create a migration script based on difference between two SA models. :param repository: path to migrate repository :param oldmodel: dotted.module.name:SAClass or SAClass object :param model: dotted.module.name:SAClass or SAClass object :param engine: SQLAlchemy engine :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>` :type oldmodel: string or Class :type model: string or Class :type engine: Engine instance :returns: Upgrade / Downgrade script :rtype: string """ if isinstance(repository, six.string_types): # oh dear, an import cycle! from migrate.versioning.repository import Repository repository = Repository(repository) oldmodel = load_model(oldmodel) model = load_model(model) # Compute differences. diff = schemadiff.getDiffOfModelAgainstModel( model, oldmodel, excludeTables=[repository.version_table]) # TODO: diff can be False (there is no difference?) decls, upgradeCommands, downgradeCommands = \ genmodel.ModelGenerator(diff,engine).genB2AMigration() # Store differences into file. src = Template(opts.pop('templates_path', None)).get_script( opts.pop('templates_theme', None)) f = open(src) contents = f.read() f.close() # generate source search = 'def upgrade(migrate_engine):' contents = contents.replace(search, '\n\n'.join((decls, search)), 1) if upgradeCommands: contents = contents.replace(' pass', upgradeCommands, 1) if downgradeCommands: contents = contents.replace(' pass', downgradeCommands, 1) return contents
def compare_model_to_db(cls, engine, model, repository): """ Compare the current model against the current database. """ if isinstance(repository, basestring): repository = Repository(repository) model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase(model, engine, excludeTables=[repository.version_table]) return diff
def compare_model_to_db(cls, engine, model, repository): """ Compare the current model against the current database. """ if isinstance(repository, basestring): repository = Repository(repository) model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase( model, engine, excludeTables=[repository.version_table]) return diff
def update_db_from_model(self, model): """ Modify the database to match the structure of the current Python model. """ model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase( model, self.engine, excludeTables=[self.repository.version_table]) genmodel.ModelGenerator(diff, self.engine).runB2A() self.update_repository_table(self.version, int(self.repository.latest)) self.load()
def update_db_from_model(self, model): """ Modify the database to match the structure of the current Python model. """ if isinstance(self.repository, basestring): self.repository=Repository(self.repository) model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase( model, self.engine, excludeTables=[self.repository.version_table]) genmodel.ModelGenerator(diff).applyModel() update = self.table.update( self.table.c.repository_id == str(self.repository.id)) self.engine.execute(update, version=int(self.repository.latest))
def update_db_from_model(self, model): """ Modify the database to match the structure of the current Python model. """ if isinstance(self.repository, basestring): self.repository = Repository(self.repository) model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase( model, self.engine, excludeTables=[self.repository.version_table]) genmodel.ModelGenerator(diff).applyModel() update = self.table.update( self.table.c.repository_id == str(self.repository.id)) self.engine.execute(update, version=int(self.repository.latest))
def update_db_from_model(self, model): """ Modify the database to match the structure of the current Python model. """ model = load_model(model) diff = schemadiff.getDiffOfModelAgainstDatabase( model, self.engine, excludeTables=[self.repository.version_table]) genmodel.ModelGenerator(diff).applyModel() self.update_repository_table(self.version, int(self.repository.latest)) self.load()
def create_or_migrate(db_uri, db_repo, model_dotted_name): """ Create or migrate a database. :param db_uri: Database URI. :param db_repo: Migrate repository. :param model_dotted_name: path to model in form of string: ``some.python.module:Class` """ logger.info("Create or migrate database: {} with migrate repo: {}".format( db_uri, db_repo)) # Test if the migrate repository exists if not os.path.isdir(db_repo): raise OSError(2, "Migrate repository doesn't exists ! ", db_repo) engine = create_engine(db_uri) # if database isn't under versionning, building it or setting correction version if not is_under_version_control(db_uri=db_uri, db_repo=db_repo): if lastest_unversionned_schemas_deployed( engine=engine): # DB exists is the lastest not versionned logger.info( "Database {} wasn't versionned but is the latest unversionned schema, setting it's" .format(db_uri) + "version to 0, to apply migrations.") mapi.version_control( db_uri, db_repo, 0) # considering it's an old db, before versionning else: logger.info( "Database {} tables doesn't seems to exists, try to create it." .format(db_uri)) meta = load_model(model_dotted_name) meta.create_all(engine) lastest_version_rep = mapi.version(db_repo) logger.debug( "Lastest version in repo is {}, setting db to this version". format(lastest_version_rep)) mapi.version_control(db_uri, db_repo, lastest_version_rep) # upgrading to newest version logger.info("Upgrading database") mapi.upgrade(db_uri, db_repo)
def update_pylons_db_from_model(url, model_str, commit=False): """update_pylons_db_from_model URL MODEL_STR COMMIT Modify the database to match the structure of the current Pylons model. NOTE: This is EXPERIMENTAL. """ # TODO: get rid of EXPERIMENTAL label global _debug_messages # engine = opts.pop('engine') # relies on @with_engine, and url being first argument engine = construct_engine(url) # direct approach if _debug_messages: print "engine= ", engine if _debug_messages: print "sqlalchemy-migrate-pylons : engine created" model_metadata = load_model(model_str) if _debug_messages: print "sqlalchemy-migrate-pylons : model metadata loaded from model_str" #schema.MetaData(engine).bind=model_metadata #print " Meta Internal: ", model.metadata, "\n" #print " Meta Migrate : ", sqlalchemy.MetaData(engine), "\n" #model.metadata=sqlalchemy.MetaData(engine) #model_metadata = declarative_base(metadata=sqlalchemy.MetaData(engine)) #model_metadata.DBsession.configure(bind=engine, autocommit=False) #model_metadata.engine = engine #model_metadata.reflect(bind=engine) #declarative_base(metadata=model_metadata) #sqlalchemy.MetaData(engine).bind = engine diff = schemadiff.getDiffOfModelAgainstDatabase(model_metadata, engine) print "\n====== sqlalchemy-migrate-pylons : Model vs. Database ======\n", diff, "\n" if commit: # genmodel.ModelGenerator(diff).applyModel() # print "\n Engine in Diffs : ", diff.conn.engine, "\n" #print " Meta Internal: ", model.session, "\n" #print " Meta Migrate : ", sqlalchemy.MetaData(diff.conn.engine), "\n" #meta = model.metadata #sqlalchemy.MetaData(diff.conn.engine).bind = engine #meta.DBsession.configure(bind=engine, autocommit=False) if hasattr(diff, 'tablesMissingInDatabase'): print "MISSING : ", diff.tablesMissingInDatabase print "MISSING : ", sqlalchemy.sql.util.sort_tables(diff.tablesMissingInDatabase) diff.tablesMissingInDatabase = sqlalchemy.sql.util.sort_tables(diff.tablesMissingInDatabase) print "====== sqlalchemy-migrate-pylons : Table Creation order : ======\n", diff, "\n" #sqlalchemy.MetaData(engine).bind = engine if hasattr(diff, 'tablesMissingInDatabase'): ## Oldrelease... newmodel = genmodel.ModelGenerator(diff, declarative=True) #newmodel.reflect(bind=engine) else: # This is a change for new release... newmodel = genmodel.ModelGenerator(diff, engine, declarative=True) if hasattr(diff, 'tablesMissingInDatabase'): ## Oldrelease... print "====== sqlalchemy-migrate-pylons : Different Model created ======\n" print " New Model (in Python): \n\n", newmodel.toUpgradeDowngradePython()[0], "\n" # Show the Declarations print "# Upgrade Code :\n", newmodel.toUpgradeDowngradePython()[1], "\n" # Show the Upgrade code newmodel.applyModel() print "====== sqlalchemy-migrate-pylons : Database Migrated ======\n" diff = schemadiff.getDiffOfModelAgainstDatabase(model_metadata, engine) print "\n====== sqlalchemy-migrate-pylons : Model vs. Database (after migration) ======\n", diff, "\n" if isinstance(engine, Engine): engine.dispose()