Commit 3ef9d629 authored by Adrian Rossouw's avatar Adrian Rossouw Committed by adrian

Replacement provision_invoke function which is a lot cleaner and simpler than...

Replacement provision_invoke function which is a lot cleaner and simpler than the old one. It now automatically does pre_task, task and post_task variations, and handles rollbacks correctly across the whole set. This means broken site installs now roll back correctly.
parent c119925d
......@@ -234,11 +234,12 @@ function provision_drupal_provision_pre_install($url, &$data) {
function provision_drupal_provision_install($url, &$data) {
$cmd = sprintf("php %s/install.php %s %s %s %s", dirname(__FILE__), escapeshellarg($url), escapeshellarg($data['profile']), escapeshellarg($data['language']), escapeshellarg($data['client_email']));
if (provision_exec($cmd, $url, $data)) {
$data['installed'] = TRUE;
_provision_drupal_maintain_aliases($url, $data); # Create symlinks for site aliases (if any)
}
$cmd = sprintf("php %s/install.php %s %s %s %s", dirname(__FILE__), escapeshellarg($url), escapeshellarg($data['profile']), escapeshellarg($data['language']), escapeshellarg($data['client_email']));
if (provision_exec($cmd, $data)) {
$data['installed'] = TRUE;
// Create symlinks for site aliases (if any)
_provision_drupal_maintain_aliases($url, $data);
}
}
function provision_drupal_provision_post_install($url, &$data) {
......
......@@ -24,6 +24,8 @@ define('PROVISION_OUTPUT', 'PROVISION_OUTPUT>>>');
* If at any point during execution, the provision_get_error() function returns anything but 0, provision_invoke will
* trigger $hook_rollback for each of the hooks that implement it, in reverse order from how they were executed.
*
* This function will also trigger pre_$hook and post_$hook variants of the hook and it's rollbacks automatically.
*
* @param hook
* The hook name to be executed for all the modules.
* @param url
......@@ -31,21 +33,25 @@ define('PROVISION_OUTPUT', 'PROVISION_OUTPUT>>>');
* @param data
* A reference to the associated array containing the data for the site. This needs to be a reference,
* because the modules might provide additional information about the site.
* @param rollback
* A boolean specifying whether or not the entire task needs to be rolled back.
* This is used specifically in commands which implement multiple hooks, such as 'install',
* which implements 'pre_install', 'install' and 'post_install' hooks.
* @return
* A boolean specifying whether or not any rollback has been performed.
* A boolean specifying whether or not the command was successfully completed.
*
*/
function provision_invoke($hook, $url, &$data, $rollback = FALSE) {
if (!$rollback) {
foreach (module_implements("provision_$hook") as $name) {
_provision_log_messages();
$completed[] = $name;
$func = $name .'_provision_'. $hook;
function provision_invoke($hook, $url, &$data) {
// First we build a list of functions are about to execute
$variations = array("pre_$hook", $hook, "post_$hook");
foreach ($variations as $var_hook) {
foreach (module_implements("provision_$var_hook") as $name) {
$functions[] = $name . '_provision_' . $var_hook;
}
}
$rollback = FALSE;
$completed = array();
foreach ($functions as $func) {
$completed[] = $func;
if (function_exists($func)) {
$func($url, $data);
//this is run before and after so that messages appear in the correct order.
_provision_log_messages();
......@@ -56,23 +62,20 @@ function provision_invoke($hook, $url, &$data, $rollback = FALSE) {
}
}
}
else {
$completed = module_implements("provision_$hook");
}
// something went wrong, we need to undo
if ($rollback) {
foreach (array_reverse($completed) as $name) {
$func = $name .'_'. $hook .'_rollback';
if (function_exists($func)) {
$func($url, $data);
provision_set_log('Rollback', "Changes for $name module have been rolled back.");
foreach (array_reverse($completed) as $func) {
$rb_func = $func . '_rollback';
if (function_exists($rb_func)) {
$rb_func($url, $data);
_provision_log_messages();
provision_log('Rollback', "Changes for $name module have been rolled back.");
}
}
return TRUE;
}
else {
return FALSE;
}
return !$rollback;
}
......@@ -364,7 +367,7 @@ function provision_save_site_data($url, $data) {
global $args;
$conf_file = "sites/$url/site.php";
$exclude = array('task_id', 'url');
$exclude = array('task_id', 'url', 'backend');
$options = array();
include(PROVISION_DOCROOT_PATH . '/drushrc.php'); // load drush rc
$exclude = array_merge($exclude, array_keys($options));
......
......@@ -362,97 +362,12 @@ function provision_install_cmd($url) {
provision_set_error(PROVISION_FRAMEWORK_ERROR);
provision_output($url, $data);
}
$ops = array('pre_install', 'install', 'post_install'); //these are the provision hooks that will get triggered.
if (_provision_drupal_site_installed($url)) {
provision_set_error(PROVISION_SITE_INSTALLED);
provision_log("error", t("Site has already been installed. Exiting."));
provision_output($url, $data);
}
foreach ($ops as $op ) {
$func = "_provision_$op";
$func($url, $data);
if (provision_invoke("install", $url, $data)) {
provision_save_site_data($url, $data);
}
provision_save_site_data($url, $data);
provision_output($url, $data);
}
/**
* Drush task.
*
* Calls hook_provision_pre_install().
* Also responsible for calling creating site directory layout, and the drupal settings file.
*
* @param url
* The url of the site being invoked.
* @param data
* A reference to the associated array containing the data for the site. This needs to be a reference,
* because the modules might provide additional information about the site.
* @return
* Boolean denoting whether the provision_invoke rolled back changes made.
*/
function _provision_pre_install($url, &$data) {
return provision_invoke("pre_install", $url, $data);
}
/**
* Install drupal site
*
* The magic here is that we need to drive the install api through this code.
* At this point, we no longer have access to the central database, and we need to be able
* to drive this code blind, without causing bad stuff to happen.
*
* Install profile gets triggered at the end of this code.
*
* @param url
* The url of the site being invoked.
* @param data
* A reference to the associated array containing the data for the site. This needs to be a reference,
* because the modules might provide additional information about the site.
* @return
* Boolean denoting whether the provision_invoke rolled back changes made.
*/
function _provision_install($url, &$data) {
return provision_invoke("install", $url, $data);
}
/**
* Clean up after installation.
*
* Most notably give the web server the opportunity to recheck it's configuration files.
*
* @param url
* The url of the site being installed.
* @param data
* A reference to the associated array containing the data for the site. This needs to be a reference,
* because the modules might provide additional information about the site.
* @return
* Boolean denoting whether the provision_invoke rolled back changes made.
*/
function _provision_post_install($url, &$data) {
return provision_invoke("post_install", $url, $data);
}
/**
* Regenerate the config files of an already running site.
*
* @param url
* The url of the site being synched.
* @return
* Output of provision_output() function.
* Will exit with a PROVISION_SITE_NOT_FOUND error if the site does not exist.
*/
function _provision_synch($url = NULL) {
if (!$url) {
global $args;
provision_output(NULL, $data);
}
else {
}
}
/**
* Generate a backup of the site using a site package.
*
......@@ -505,7 +420,7 @@ function _provision_backup_site($url, &$data, $file = NULL) {
}
$data['backup_file'] = (!empty($file)) ? ereg_replace('.gz$', '', $file) : $suggested;
$rolled_back = provision_invoke("backup", $url, $data);
provision_invoke("backup", $url, $data);
provision_shell_exec("gzip %s", $data['backup_file']);
$data['backup_file'] = $data['backup_file'] .'.gz';
}
......@@ -527,7 +442,7 @@ function _provision_import($url) {
provision_set_error(PROVISION_FRAMEWORK_ERROR);
provision_output($url, $data);
}
$rolled_back = provision_invoke("import", $url, $data);
provision_invoke("import", $url, $data);
provision_output($url, $data);
}
......@@ -561,15 +476,10 @@ function _provision_verify($url = NULL) {
$data = provision_get_site_data($url);
}
if (!$rolled_back = provision_invoke("pre_verify", $url, $data)) {
if (!$rolled_back = provision_invoke("verify", $url, $data)) {
$rolled_back = provision_invoke("post_verify", $url, $data);
}
}
// We only save the settings if they validated correctly, not before.
if (!$rolled_back) {
if (provision_invoke("verify", $url, $data)) {
if (!$url) {
_provision_generate_config();
}
......@@ -617,30 +527,7 @@ function _provision_restore($url, $restore_file) {
$data = provision_get_site_data($url);
$data['restore_file'] = $restore_file;
$phases = array("pre_restore", "restore", "post_restore");
$completed = array();
$rolled_back = FALSE; // initializes to FALSE.
foreach ($phases as $phase) {
$rolled_back = provision_invoke($phase, $url, $data, $rolled_back);
if (!$rolled_back) {
$completed[] = $phase;
}
else {
break; // exit out of the loop, to allow any changes to be reversed next.
}
}
if ($rolled_back) {
// An error has occurred, and we must undo all the changes we made, in reverse
// This works by triggering the _rollback functions for each of the hooks.
foreach (array_reverse($completed) as $phase) {
provision_invoke($phase, $url, $data, $rolled_back);
}
}
else {
if (provision_invoke("restore", $url, $data)) {
provision_save_site_data($url, $data);
}
}
......@@ -673,10 +560,11 @@ function _provision_disable($url) {
$data = provision_get_site_data($url);
_provision_backup_site($url, $data); # Backup site for posterity, before disabling
$rolled_back = provision_invoke("disable", $url, $data);
if (provision_invoke("disable", $url, $data)) {
$data['enabled'] = FALSE;
provision_save_site_data($url, $data);
}
$data['enabled'] = FALSE;
provision_save_site_data($url, $data);
provision_output($url, $data);
}
......@@ -688,10 +576,11 @@ function _provision_enable($url) {
}
$data = provision_get_site_data($url);
$rolled_back = provision_invoke("enable", $url, $data);
if (provision_invoke("enable", $url, $data)) {
$data['enabled'] = TRUE;
provision_save_site_data($url, $data);
}
$data['enabled'] = TRUE;
provision_save_site_data($url, $data);
provision_output($url, $data);
}
......@@ -702,7 +591,7 @@ function _provision_delete($url) {
$file = array_shift($args);
_provision_backup_site($url, $data, $file);
$rolled_back = provision_invoke("delete", $url, $data);
provision_invoke("delete", $url, $data);
provision_output($url, $data);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment