Skip to content

Commit

Permalink
#31: Migrations directory is now configured in the config file. Also,…
Browse files Browse the repository at this point in the history
… refactored to separate all configuration in the 'Config' class.
  • Loading branch information
guilhermechapiewski committed Apr 30, 2009
1 parent 9e684b1 commit 572860d
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 87 deletions.
4 changes: 3 additions & 1 deletion example/simple-db-migrate.conf
Expand Up @@ -5,4 +5,6 @@ HOST = os.getenv("DB_HOST") or "localhost"
USERNAME = os.getenv("DB_USERNAME") or "root"
PASSWORD = os.getenv("DB_PASSWORD") or ""
DATABASE = os.getenv("DB_DATABASE") or "migration_example"
MIGRATIONS_DIR = os.getenv("MIGRATIONS_DIR") or "example"

# relative path from this config file location
MIGRATIONS_DIR = os.getenv("MIGRATIONS_DIR") or "."
9 changes: 7 additions & 2 deletions src/db-migrate
Expand Up @@ -7,7 +7,12 @@ from simple_db_migrate.main import Main
(options, args) = CLI().parse()

# Create config
config = Config(options.db_config_file)
config = Config(options.config_file)
config.put("schema_version", options.schema_version)
config.put("show_sql", options.show_sql)
config.put("show_sql_only", options.show_sql_only)
config.put("new_migration", options.new_migration)
config.put("drop_db_first", options.drop_db_first)

# If CLI was correctly parsed, execute db-migrate.
Main(options, args).execute()
Main(config).execute()
13 changes: 4 additions & 9 deletions src/simple_db_migrate/cli.py
Expand Up @@ -13,17 +13,12 @@ def __config_parser(self):
dest="schema_version",
default=None,
help="Schema version to migrate to. If not provided will migrate to the last version available in the migrations directory.")

self.__parser.add_option("-c", "--config",
dest="db_config_file",
dest="config_file",
default="simple-db-migrate.conf",
help="Use a specific config file. If not provided, will search for 'simple-db-migrate.conf' in the current directory.")

self.__parser.add_option("-d", "--dir",
dest="migrations_dir",
default=".",
help="Try to find migration files in a specific directory. If not provided will search for files in the current directory.")


self.__parser.add_option("--showsql",
action="store_true",
dest="show_sql",
Expand All @@ -37,7 +32,7 @@ def __config_parser(self):
help="Show all SQL statements that would be executed but DON'T execute them in the database.")

self.__parser.add_option("--create", "--new",
dest="create_migration",
dest="new_migration",
default=None,
help="Create migration file with the given nickname. The nickname should contain only lowercase characters and underscore '_'. Example: 'create_table_xyz'.")

Expand Down
25 changes: 17 additions & 8 deletions src/simple_db_migrate/core.py
@@ -1,11 +1,15 @@
from cli import CLI
from time import strftime
from helpers import Utils
import os
import shutil
import re

class Config(object):

def __repr__(self):
return str(self.__config)

def __init__(self, config_file="simple-db-migrate.conf"):
self.__cli = CLI()
self.__config = {}
Expand All @@ -19,12 +23,17 @@ def __init__(self, config_file="simple-db-migrate.conf"):
else:
f.close()

self.put("database_host", HOST)
self.put("database_user", USERNAME)
self.put("database_password", PASSWORD)
self.put("database_name", DATABASE)
self.put("database_version_table", "__db_version__")
self.put("migrations_dir", MIGRATIONS_DIR)
self.put("db_host", HOST)
self.put("db_user", USERNAME)
self.put("db_password", PASSWORD)
self.put("db_name", DATABASE)
self.put("db_version_table", "__db_version__")

migrations_dir = self.__get_migrations_absolute_dir(config_file, MIGRATIONS_DIR)
self.put("migrations_dir", migrations_dir)

def __get_migrations_absolute_dir(self, config_file_path, migrations_dir):
return os.path.abspath(Utils.get_path_without_config_file_name(config_file_path) + "/" + migrations_dir)

def get(self, config_key):
try:
Expand All @@ -41,8 +50,8 @@ class Migrations(object):

__migration_files_extension = ".migration"

def __init__(self, migrations_dir):
self.__migrations_dir = migrations_dir
def __init__(self, config=None):
self.__migrations_dir = config.get("migrations_dir")
self.__cli = CLI()

def get_all_migration_files(self):
Expand Down
13 changes: 11 additions & 2 deletions src/simple_db_migrate/helpers.py
@@ -1,7 +1,16 @@
#TODO: there should be something like this somewhere... Gotta find it!
import re

class Lists(object):

@classmethod
def subtract(self, list_a, list_b):
return [l for l in list_a if l not in list_b]
return [l for l in list_a if l not in list_b]

class Utils(object):

@classmethod
def get_path_without_config_file_name(self, path):
info = re.match(r"^(.*/).*$", path, re.S)
if info is None or info == "":
return "."
return info.group(1)
26 changes: 13 additions & 13 deletions src/simple_db_migrate/main.py
Expand Up @@ -6,29 +6,28 @@

class Main(object):

def __init__(self, options=None, args=None, mysql=None, db_migrate=None):
def __init__(self, config=None, mysql=None, db_migrate=None):
self.__cli = CLI()
self.__options = options
self.__args = args
self.__config = config

self.__mysql = mysql
if self.__mysql is None and not self.__options.create_migration:
self.__mysql = MySQL(db_config_file=self.__options.db_config_file, drop_db_first=self.__options.drop_db_first)
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(self.__options.migrations_dir)
self.__db_migrate = Migrations(config)

def execute(self):
self.__cli.msg("\nStarting DB migration...")
if self.__options.create_migration:
if self.__config.get("new_migration"):
self._create_migration()
else:
self._migrate()
self.__cli.msg("\nDone.\n")

def _create_migration(self):
new_file = self.__db_migrate.create_migration(self.__options.create_migration)
new_file = self.__db_migrate.create_migration(self.__config.get("new_migration"))
self.__cli.msg("- Created file '%s'" % (new_file))

def _migrate(self):
Expand All @@ -48,7 +47,7 @@ def _migrate(self):
self._execute_migrations(current_version, destination_version, is_migration_up)

def _get_destination_version(self):
destination_version = self.__options.schema_version
destination_version = self.__config.get("schema_version")
if destination_version is None:
destination_version = self.__db_migrate.latest_schema_version_available()

Expand Down Expand Up @@ -84,7 +83,7 @@ def _execute_migrations(self, current_version, destination_version, is_migration
sys.exit(0)

up_down_label = "up" if is_migration_up else "down"
if self.__options.show_sql_only:
if self.__config.get("show_sql_only"):
self.__cli.msg("\nWARNING: database migrations are not being executed ('--showsqlonly' activated)")
else:
self.__cli.msg("\nStarting migration %s!" % up_down_label)
Expand All @@ -96,14 +95,15 @@ def _execute_migrations(self, current_version, destination_version, is_migration
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.__options.show_sql_only:
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 += sql

if self.__options.show_sql or self.__options.show_sql_only:
if self.__config.get("show_sql") or self.__config.get("show_sql_only"):
self.__cli.msg("__________ SQL statements executed __________")
self.__cli.msg(sql_statements_executed)
self.__cli.msg("_____________________________________________")
self.__cli.msg("_____________________________________________")

26 changes: 8 additions & 18 deletions src/simple_db_migrate/mysql.py
Expand Up @@ -4,26 +4,16 @@

class MySQL(object):

def __init__(self, db_config_file="simple-db-migrate.conf", mysql_driver=MySQLdb, drop_db_first=False):
def __init__(self, config=None, mysql_driver=MySQLdb):
self.__cli = CLI()

# read configurations
try:
f = open(db_config_file, "r")
exec(f.read())
except IOError:
self.__cli.error_and_exit("%s: file not found" % db_config_file)
else:
f.close()

self.__mysql_driver = mysql_driver
self.__mysql_host = HOST
self.__mysql_user = USERNAME
self.__mysql_passwd = PASSWORD
self.__mysql_db = DATABASE
self.__version_table = "__db_version__"
if drop_db_first:
self.__mysql_host = config.get("db_host")
self.__mysql_user = config.get("db_user")
self.__mysql_passwd = config.get("db_password")
self.__mysql_db = config.get("db_name")
self.__version_table = config.get("db_version_table")

if config.get("drop_db_first"):
self._drop_database()

self._create_database_if_not_exists()
Expand Down
4 changes: 1 addition & 3 deletions tests/cli_test.py
Expand Up @@ -14,16 +14,14 @@ def test_it_should_configure_all_options(self):
self.assertTrue(parser.has_option("-c"))
self.assertTrue(parser.has_option("--config"))

self.assertTrue(parser.has_option("-d"))
self.assertTrue(parser.has_option("--dir"))

self.assertTrue(parser.has_option("-v"))
self.assertTrue(parser.has_option("--version"))

self.assertTrue(parser.has_option("--showsql"))
self.assertTrue(parser.has_option("--showsqlonly"))

self.assertTrue(parser.has_option("--create"))
self.assertTrue(parser.has_option("--new"))

self.assertTrue(parser.has_option("--drop"))
self.assertTrue(parser.has_option("--drop-database-first"))
Expand Down

0 comments on commit 572860d

Please sign in to comment.