class Main(object): def __init__(self, config=None, mysql=None, db_migrate=None): self.__cli = CLI() self.__config = config self.__mysql = mysql if self.__mysql is None and not self.__config.get("new_migration"): self.__mysql = MySQL(config) self.__db_migrate = db_migrate if self.__db_migrate is None: self.__db_migrate = Migrations(config) def execute(self): self.__cli.msg("\nStarting DB migration...", "PINK") if self.__config.get("new_migration"): self._create_migration() else: self._migrate() self.__cli.msg("\nDone.\n", "PINK") def _create_migration(self): new_file = self.__db_migrate.create_migration(self.__config.get("new_migration")) self.__cli.msg("- Created file '%s'" % (new_file)) def _migrate(self): destination_version = self._get_destination_version() current_version = self.__mysql.get_current_schema_version() self.__cli.msg("- Current version is: %s" % current_version, "GREEN") self.__cli.msg("- Destination version is: %s" % destination_version, "GREEN") # if current and destination versions are the same, # will consider a migration up to execute remaining files is_migration_up = True if int(current_version) > int(destination_version): is_migration_up = False # do it! self._execute_migrations(current_version, destination_version, is_migration_up) def _get_destination_version(self): destination_version = self.__config.get("schema_version") if destination_version is None: destination_version = self.__db_migrate.latest_schema_version_available() if not self.__db_migrate.check_if_version_exists(destination_version): self.__cli.error_and_exit("version not found (%s)" % destination_version) return destination_version def _get_migration_files_to_be_executed(self, current_version, destination_version): mysql_versions = self.__mysql.get_all_schema_versions() migration_versions = self.__db_migrate.get_all_migration_versions() # migration up: the easy part if current_version <= destination_version: remaining_versions_to_execute = Lists.subtract(migration_versions, mysql_versions) remaining_versions_to_execute = [ version for version in remaining_versions_to_execute if version <= destination_version ] return remaining_versions_to_execute # migration down... down_versions = [ version for version in mysql_versions if version <= current_version and version > destination_version ] for version in down_versions: if version not in migration_versions: self.__cli.error_and_exit( "impossible to migrate down: one of the versions was not found (%s)" % version ) down_versions.reverse() return down_versions def _execute_migrations(self, current_version, destination_version, is_migration_up): # getting only the migration sql files to be executed versions_to_be_executed = self._get_migration_files_to_be_executed(current_version, destination_version) if versions_to_be_executed is None or len(versions_to_be_executed) == 0: self.__cli.msg("\nNothing to do.\n", "PINK") sys.exit(0) up_down_label = "up" if is_migration_up else "down" if self.__config.get("show_sql_only"): self.__cli.msg("WARNING: database migrations are not being executed ('--showsqlonly' activated)", "YELLOW") else: self.__cli.msg("\nStarting migration %s!" % up_down_label) self.__cli.msg("*** versions: %s\n" % versions_to_be_executed, "GRAY") sql_statements_executed = [] for migration_version in versions_to_be_executed: sql_file = self.__db_migrate.get_migration_file_name_from_version_number(migration_version) sql = self.__db_migrate.get_sql_command(sql_file, is_migration_up) if not self.__config.get("show_sql_only"): self.__cli.msg("===== executing %s (%s) =====" % (sql_file, up_down_label)) self.__mysql.change(sql, migration_version, is_migration_up) # recording the last statement executed sql_statements_executed.append(sql) if self.__config.get("show_sql") or self.__config.get("show_sql_only"): self.__cli.msg("__________ SQL statements executed __________", "YELLOW") for sql in sql_statements_executed: self.__cli.msg(sql, "YELLOW") self.__cli.msg("_____________________________________________", "YELLOW")
class Main(object): def __init__(self, config=None, mysql=None, db_migrate=None): self.cli = CLI() self.config = config or {} self.mysql = mysql if self.mysql is None and not self.config.get("new_migration"): self.mysql = MySQL(config) self.db_migrate = db_migrate or SimpleDBMigrate(config) def execute(self): self.cli.msg("\nStarting DB migration...", "PINK") if self.config.get("new_migration"): self.create_migration() else: self.migrate() self.cli.msg("\nDone.\n", "PINK") def create_migration(self): # TODO: create file in the migrations directory, not in current new_file = Migration.create(self.config.get("new_migration")) self.cli.msg("- Created file '%s'" % (new_file)) def migrate(self): destination_version = self.get_destination_version() current_version = self.mysql.get_current_schema_version() self.cli.msg("- Current version is: %s" % current_version, "GREEN") self.cli.msg("- Destination version is: %s" % destination_version, "GREEN") # if current and destination versions are the same, # will consider a migration up to execute remaining files is_migration_up = True if int(current_version) > int(destination_version): is_migration_up = False # do it! self.execute_migrations(current_version, destination_version, is_migration_up) def get_destination_version(self): destination_version = self.config.get("schema_version") if destination_version is None: destination_version = self.db_migrate.latest_version_available() if destination_version is not '0' and not self.db_migrate.check_if_version_exists(destination_version): raise Exception("version not found (%s)" % destination_version) return destination_version def get_migration_files_to_be_executed(self, current_version, destination_version): mysql_versions = self.mysql.get_all_schema_versions() migration_versions = self.db_migrate.get_all_migration_versions() # migration up: the easy part if current_version <= destination_version: remaining_versions_to_execute = Lists.subtract(migration_versions, mysql_versions) remaining_versions_to_execute = [version for version in remaining_versions_to_execute if version <= destination_version] return remaining_versions_to_execute # migration down... down_versions = [version for version in mysql_versions if version <= current_version and version > destination_version] for version in down_versions: if version not in migration_versions: raise Exception("impossible to migrate down: one of the versions was not found (%s)" % version) down_versions.reverse() return down_versions def execute_migrations(self, current_version, destination_version, is_migration_up): # getting only the migration sql files to be executed versions_to_be_executed = self.get_migration_files_to_be_executed(current_version, destination_version) if versions_to_be_executed is None or len(versions_to_be_executed) == 0: self.cli.msg("\nNothing to do.\n", "PINK") return up_down_label = is_migration_up and "up" or "down" if self.config.get("show_sql_only"): self.cli.msg("\nWARNING: database migrations are not being executed ('--showsqlonly' activated)", "YELLOW") else: self.cli.msg("\nStarting migration %s!" % up_down_label) if self.config.get("log_level") >= 1: self.cli.msg("*** versions: %s\n" % versions_to_be_executed, "CYAN") sql_statements_executed = [] for migration_version in versions_to_be_executed: migration = self.db_migrate.get_migration_from_version_number(migration_version) sql = is_migration_up and migration.sql_up or migration.sql_down if not self.config.get("show_sql_only"): if self.config.get("log_level") >= 1: self.cli.msg("===== executing %s (%s) =====" % (migration.file_name, up_down_label)) log = None if self.config.get("log_level") >= 2: log = self.cli.msg self.mysql.change(sql, migration_version, is_migration_up, execution_log=log) # paused mode if self.config.get("paused_mode"): raw_input("* press <enter> to continue... ") # recording the last statement executed sql_statements_executed.append(sql) if self.config.get("show_sql") or self.config.get("show_sql_only"): self.cli.msg("__________ SQL statements executed __________", "YELLOW") for sql in sql_statements_executed: self.cli.msg(sql, "YELLOW") self.cli.msg("_____________________________________________", "YELLOW")
class Main(object): def __init__(self, config=None, mysql=None, db_migrate=None): self.cli = CLI() self.config = config or {} self.log = LOG(self.config.get("log_dir")) self.mysql = mysql if self.mysql is None and not self.config.get("new_migration"): self.mysql = MySQL(config) self.db_migrate = db_migrate or SimpleDBMigrate(config) def execution_log(self, msg, color="CYAN", log_level_limit=2): if self.config.get("log_level") >= log_level_limit: self.cli.msg(msg) self.log.debug(msg) def execute(self): self.execution_log("\nStarting DB migration...", "PINK", log_level_limit=1) if self.config.get("new_migration"): self.create_migration() else: self.migrate() self.execution_log("\nDone.\n", "PINK", log_level_limit=1) def create_migration(self): migrations_dir = self.config.get("migrations_dir") new_file = Migration.create(self.config.get("new_migration"), migrations_dir[0], self.config.get("db_script_encoding", "utf-8")) self.execution_log("- Created file '%s'" % (new_file), log_level_limit=1) def migrate(self): destination_version = self.get_destination_version() current_version = self.mysql.get_current_schema_version() # do it! self.execute_migrations(current_version, destination_version) def get_destination_version(self): destination_version = self.config.get("schema_version") if destination_version is None: destination_version = self.db_migrate.latest_version_available() if destination_version is not '0' and not self.db_migrate.check_if_version_exists(destination_version): raise Exception("version not found (%s)" % destination_version) return destination_version def get_migration_files_to_be_executed(self, current_version, destination_version, is_migration_up): mysql_versions = self.mysql.get_all_schema_versions() migration_versions = self.db_migrate.get_all_migration_versions() # migration up if is_migration_up: remaining_versions_to_execute = Lists.subtract(migration_versions, mysql_versions) remaining_migrations_to_execute = [self.db_migrate.get_migration_from_version_number(version) for version in remaining_versions_to_execute if version <= destination_version] return remaining_migrations_to_execute # migration down... destination_version_id = self.mysql.get_version_id_from_version_number(destination_version) migrations = self.mysql.get_all_schema_migrations() down_migrations_to_execute = [migration for migration in migrations if migration.id > destination_version_id] for migration in down_migrations_to_execute: if not migration.sql_down: if migration.version not in migration_versions: raise Exception("impossible to migrate down: one of the versions was not found (%s)" % migration.version) migration_tmp = self.db_migrate.get_migration_from_version_number(migration.version) migration.sql_up = migration_tmp.sql_up migration.sql_down = migration_tmp.sql_down migration.file_name = migration_tmp.file_name down_migrations_to_execute.reverse() return down_migrations_to_execute def execute_migrations(self, current_version, destination_version): """ passed a version: this version don't exists in the database and is younger than the last version -> do migrations up until the this version this version don't exists in the database and is older than the last version -> do nothing, is a unpredictable behavior this version exists in the database and is older than the last version -> do migrations down until this version didn't pass a version -> do migrations up until the last available version """ is_migration_up = True # check if a version was passed to the program if self.config.get("schema_version"): # if was passed and this version is present in the database, check if is older than the current version destination_version_id = self.mysql.get_version_id_from_version_number(destination_version) if destination_version_id: current_version_id = self.mysql.get_version_id_from_version_number(current_version) # if this version is previous to the current version in database, then will be done a migration down to this version if current_version_id > destination_version_id: is_migration_up = False # if was passed and this version is not present in the database and is older than the current version, raise an exception # cause is trying to go down to something that never was done elif current_version > destination_version: raise Exception("Trying to migrate to a lower version wich is not found on database (%s)" % destination_version) # getting only the migration sql files to be executed migrations_to_be_executed = self.get_migration_files_to_be_executed(current_version, destination_version, is_migration_up) self.execution_log("- Current version is: %s" % current_version, "GREEN", log_level_limit=1) if migrations_to_be_executed is None or len(migrations_to_be_executed) == 0: self.execution_log("- Destination version is: %s" % current_version, "GREEN", log_level_limit=1) self.execution_log("\nNothing to do.\n", "PINK", log_level_limit=1) return self.execution_log("- Destination version is: %s" % (is_migration_up and migrations_to_be_executed[-1].version or destination_version), "GREEN", log_level_limit=1) up_down_label = is_migration_up and "up" or "down" if self.config.get("show_sql_only"): self.execution_log("\nWARNING: database migrations are not being executed ('--showsqlonly' activated)", "YELLOW", log_level_limit=1) else: self.execution_log("\nStarting migration %s!" % up_down_label, log_level_limit=1) if self.config.get("log_level") >= 1: self.execution_log("*** versions: %s\n" % ([ migration.version for migration in migrations_to_be_executed]), "CYAN", log_level_limit=1) sql_statements_executed = [] for migration in migrations_to_be_executed: sql = is_migration_up and migration.sql_up or migration.sql_down if not self.config.get("show_sql_only"): if self.config.get("log_level") >= 1: self.execution_log("===== executing %s (%s) =====" % (migration.file_name, up_down_label), log_level_limit=1) self.mysql.change(sql, migration.version, migration.file_name, migration.sql_up, migration.sql_down, is_migration_up, execution_log=self.execution_log) # paused mode if self.config.get("paused_mode"): raw_input("* press <enter> to continue... ") # recording the last statement executed sql_statements_executed.append(sql) if self.config.get("show_sql") or self.config.get("show_sql_only"): self.execution_log("__________ SQL statements executed __________", "YELLOW", log_level_limit=1) for sql in sql_statements_executed: self.execution_log(sql, "YELLOW", log_level_limit=1) self.execution_log("_____________________________________________", "YELLOW", log_level_limit=1)