From de7711942f37b356c19e06ee71c45dd8f22e3fec Mon Sep 17 00:00:00 2001 From: Matt Button Date: Thu, 30 Dec 2010 03:22:32 +0000 Subject: [PATCH] Changing migration system so that the migration manager is responsible for organising dry-runs This makes more sense from a structural point of view, and reduces the complexity of the db:migrate code. Can now successfully do a dry run with query output :) Also added a view so as to display task results. --- classes/minion/migration/manager.php | 78 +++++++++++++++++++++++++--- classes/minion/task/db/migrate.php | 45 +++++++++------- views/minion/task/db/migrate.php | 31 +++++++++++ 3 files changed, 127 insertions(+), 27 deletions(-) create mode 100644 views/minion/task/db/migrate.php diff --git a/classes/minion/migration/manager.php b/classes/minion/migration/manager.php index dc46501..5f25055 100644 --- a/classes/minion/migration/manager.php +++ b/classes/minion/migration/manager.php @@ -21,6 +21,24 @@ class Minion_Migration_Manager { */ protected $_model; + /** + * Whether this is a dry run migration + * @var boolean + */ + protected $_dry_run = FALSE; + + /** + * A set of SQL queries that were generated on the dry run + * @var array + */ + protected $_dry_run_sql = array(); + + /** + * Set of migrations that were executed + */ + protected $_executed_migrations = array(); + + /** * Constructs the object, allows injection of a Database connection * @@ -64,6 +82,30 @@ class Minion_Migration_Manager { return $this; } + /** + * Set whether the manager should execute a dry run instead of a real run + * + * @param boolean Whether we should do a dry run + * @return Minion_Migration_Manager + */ + public function set_dry_run($dry_run) + { + $this->_dry_run = (bool) $dry_run; + + return $this; + } + + /** + * Ruturns a set of queries that would've been executed had dry run not been + * enabled. If dry run was not enabled, this returns an empty array + * + * @return array SQL Queries + */ + public function get_dry_run_sql() + { + return $this->_dry_run_sql; + } + /** * Run migrations in the specified locations so as to reach specified targets * @@ -97,14 +139,14 @@ class Minion_Migration_Manager { * @param array Set of locations to update, empty array means all * @param array Versions for specified locations * @param boolean The default direction (up/down) for migrations without a specific version - * @param boolean Whether successful migrations should be recorded * @return array Array of all migrations that were successfully applied */ - public function run_migration(array $locations = array(), $versions = array(), $default_direction = TRUE, $record_success = TRUE) + public function run_migration(array $locations = array(), $versions = array(), $default_direction = TRUE) { $migrations = $this->_model->fetch_required_migrations($locations, $versions, $default_direction); + $db = $this->_get_db_instance(); - foreach($migrations as $location) + foreach($migrations as $path => $location) { $method = $location['direction'] ? 'up' : 'down'; @@ -125,7 +167,7 @@ class Minion_Migration_Manager { $class = Minion_Migration_Util::get_class_from_migration($migration); - $this->_db->query(NULL, 'START TRANSACTION'); + $db->query(NULL, 'START TRANSACTION'); try { @@ -133,18 +175,22 @@ class Minion_Migration_Manager { $instance = new $class; - $instance->$method($this->_db); + $instance->$method($db); } catch(Exception $e) { - $this->_db->query(NULL, 'ROLLBACK'); + $db->query(NULL, 'ROLLBACK'); throw $e; } - $this->_db->query('COMMIT'); + $db->query(NULL, 'COMMIT'); - if($record_success) + if($this->_dry_run) + { + $this->_dry_run_sql[$path][$migration['timestamp']] = $db->reset_query_stack(); + } + else { $this->_model->mark_migration($migration, $location['direction']); } @@ -214,4 +260,20 @@ class Minion_Migration_Manager { return Minion_Migration_Util::compile_migrations_from_files($files); } + + /** + * Gets a database connection for running the migrations + * + * @return Kohana_Database Database connection + */ + protected function _get_db_instance() + { + // If this isn't a dry run then just use the normal database connection + if( ! $this->_dry_run) + return $this->_db; + + $db_group = array_search($this->_db, Database::$instances); + + return Minion_Migration_Database::faux_instance($db_group); + } } diff --git a/classes/minion/task/db/migrate.php b/classes/minion/task/db/migrate.php index 757f497..9e6fd38 100644 --- a/classes/minion/task/db/migrate.php +++ b/classes/minion/task/db/migrate.php @@ -40,6 +40,11 @@ * No value taken, if this is specified then instead of executing the SQL it * will be printed to the console * + * --quiet + * + * Suppress all unnessacery output. If --dry-run is enabled then only dry run + * SQL will be output + * * @author Matt Button */ class Minion_Task_Db_Migrate extends Minion_Task @@ -59,7 +64,8 @@ class Minion_Task_Db_Migrate extends Minion_Task 'environment', 'versions', 'locations', - 'dry-run' + 'dry-run', + 'quiet' ); /** @@ -75,32 +81,33 @@ class Minion_Task_Db_Migrate extends Minion_Task $environment = Arr::get($config, 'environment', 'development'); $specified_locations = Arr::get($config, 'locations', NULL); $versions = Arr::get($config, 'versions', NULL); - $dry_run = isset($config['dry-run']); + $dry_run = array_key_exists('dry-run', $config); + $quiet = array_key_exists('quiet', $config); $targets = $this->_parse_target_versions($versions); $locations = $this->_parse_locations($specified_locations); + $db_group = $k_config['db_connections'][$environment]; + $db = Database::instance($db_group); + $model = new Model_Minion_Migration($db); - $db = Database::instance($k_config['db_connections'][$environment]); + $manager = new Minion_Migration_Manager($db, $model); - if($dry_run) - { - $manager = new Minion_Migration_Manager( - Minion_Migration_Database::instance($k_config['db_connections'][$environment]), - new Model_Minion_Migration($db) - ); - } - else - { - $manager = new Minion_Migration_Manager($db); - } - - $results = $manager + $manager // Sync the available migrations with those in the db ->sync_migration_files() - // Run migrations for specified locations & versions, and if it's - // a dry run don't log results to DB - ->run_migration($locations, $targets, $this->_default_direction, ! $dry_run); + + ->set_dry_run($dry_run) + + // Run migrations for specified locations & versions + ->run_migration($locations, $targets, $this->_default_direction); + + $view = View::factory('minion/task/db/migrate') + ->set('dry_run', $dry_run) + ->set('quiet', $quiet) + ->set('dry_run_sql', $manager->get_dry_run_sql()); + + echo $view; } /** diff --git a/views/minion/task/db/migrate.php b/views/minion/task/db/migrate.php new file mode 100644 index 0000000..5ea7cc1 --- /dev/null +++ b/views/minion/task/db/migrate.php @@ -0,0 +1,31 @@ + + + +This was a dry run, SQL is as follows: + + + $migrations): ?> + +#################### +# Begin Location: # +#################### + + $sql): ?> +# Begin + + + +; + + +# End + + + +################## +# End Location: # +################## + + + +