aboutsummaryrefslogtreecommitdiff
path: root/engine/lib
diff options
context:
space:
mode:
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-02-18 00:46:54 +0000
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-02-18 00:46:54 +0000
commit5a06233304a9965c8319ec5c1fcc4fd582393d02 (patch)
treec70268e7920779f890ad3858c39b1ed2b0fa1623 /engine/lib
parent5ee52a817885e641a56eef6ebcdd4250ef8be4b5 (diff)
downloadelgg-5a06233304a9965c8319ec5c1fcc4fd582393d02.tar.gz
elgg-5a06233304a9965c8319ec5c1fcc4fd582393d02.tar.bz2
Fixes #1433, #2183. Upgrades are now tracked and will be run if needed regardless of version.
git-svn-id: http://code.elgg.org/elgg/trunk@8277 36083f99-b078-4883-b0ff-0f9b5a30f544
Diffstat (limited to 'engine/lib')
-rw-r--r--engine/lib/database.php64
-rw-r--r--engine/lib/deprecated-1.8.php70
-rw-r--r--engine/lib/upgrades/create_upgrade.php117
-rw-r--r--engine/lib/version.php211
4 files changed, 354 insertions, 108 deletions
diff --git a/engine/lib/database.php b/engine/lib/database.php
index b2cc5ca29..fa5b4a894 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -629,70 +629,6 @@ function run_sql_script($scriptlocation) {
}
/**
- * Upgrade the database schema in an ordered sequence.
- *
- * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order.
- * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql
- * where II is an incrementor starting from 01.
- *
- * Files that are < $version will be ignored.
- *
- * @warning Plugin authors should not call this function directly.
- *
- * @param int $version The version you are upgrading from in the format YYYYMMDDII.
- * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/
- * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6.
- *
- * @return bool
- * @see upgrade.php
- * @see version.php
- */
-function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
- global $CONFIG;
-
- $version = (int) $version;
-
- if (!$fromdir) {
- $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
- }
-
- if ($handle = opendir($fromdir)) {
- $sqlupgrades = array();
-
- while ($sqlfile = readdir($handle)) {
- if (!is_dir($fromdir . $sqlfile)) {
- if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
- $sql_version = (int) $matches[1];
- if ($sql_version > $version) {
- $sqlupgrades[] = $sqlfile;
- }
- }
- }
- }
-
- asort($sqlupgrades);
-
- if (sizeof($sqlupgrades) > 0) {
- foreach ($sqlupgrades as $sqlfile) {
-
- // hide all errors.
- if ($quiet) {
- try {
- run_sql_script($fromdir . $sqlfile);
- } catch (DatabaseException $e) {
- error_log($e->getmessage());
- }
- } else {
- run_sql_script($fromdir . $sqlfile);
- }
- }
- }
- }
-
- return TRUE;
-}
-
-/**
* Sanitise a string for database use, but with the option of escaping extra characters.
*
* @param string $string The string to sanitise
diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php
index 76abc5c95..3f65fb58e 100644
--- a/engine/lib/deprecated-1.8.php
+++ b/engine/lib/deprecated-1.8.php
@@ -3808,7 +3808,7 @@ function register_metadata_url_handler($function, $extender_name = "all") {
}
/**
- *
+ *
* @deprecated 1.8 Use {@link elgg_register_relationship_url_handler()}
*/
function register_relationship_url_handler($function_name, $relationship_type = "all") {
@@ -4335,3 +4335,71 @@ function display_widget(ElggObject $widget) {
elgg_deprecated_notice("display_widget() was been deprecated. Use elgg_view_entity().", 1.8);
return elgg_view_entity($widget);
}
+
+
+/**
+ * Upgrade the database schema in an ordered sequence.
+ *
+ * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order.
+ * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql
+ * where II is an incrementor starting from 01.
+ *
+ * Files that are < $version will be ignored.
+ *
+ * @warning Plugin authors should not call this function directly.
+ *
+ * @param int $version The version you are upgrading from in the format YYYYMMDDII.
+ * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/
+ * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6.
+ *
+ * @return bool
+ * @see upgrade.php
+ * @see version.php
+ * @deprecated 1.8 Use PHP upgrades for sql changes.
+ */
+function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
+ global $CONFIG;
+
+ elgg_deprecated_notice('db_upgrade() is deprecated by using PHP upgrades.', 1.8);
+
+ $version = (int) $version;
+
+ if (!$fromdir) {
+ $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
+ }
+
+ if ($handle = opendir($fromdir)) {
+ $sqlupgrades = array();
+
+ while ($sqlfile = readdir($handle)) {
+ if (!is_dir($fromdir . $sqlfile)) {
+ if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
+ $sql_version = (int) $matches[1];
+ if ($sql_version > $version) {
+ $sqlupgrades[] = $sqlfile;
+ }
+ }
+ }
+ }
+
+ asort($sqlupgrades);
+
+ if (sizeof($sqlupgrades) > 0) {
+ foreach ($sqlupgrades as $sqlfile) {
+
+ // hide all errors.
+ if ($quiet) {
+ try {
+ run_sql_script($fromdir . $sqlfile);
+ } catch (DatabaseException $e) {
+ error_log($e->getmessage());
+ }
+ } else {
+ run_sql_script($fromdir . $sqlfile);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/engine/lib/upgrades/create_upgrade.php b/engine/lib/upgrades/create_upgrade.php
new file mode 100644
index 000000000..9575ada74
--- /dev/null
+++ b/engine/lib/upgrades/create_upgrade.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Creates an upgrade file for Elgg.
+ *
+ * Run this from the command line:
+ * php create_upgrade.php upgrade_name
+ */
+
+error_reporting(E_NOTICE);
+
+// only allow from the command line.
+if (php_sapi_name() != 'cli') {
+ die('Upgrades can only be created from the command line.');
+}
+
+if (count($argv) < 2) {
+ elgg_create_upgrade_show_usage('No upgrade name.');
+}
+
+$name = $argv[1];
+
+if (strlen($name) > 24) {
+ elgg_create_upgrade_show_usage('Upgrade names cannot be longer than 24 characters.');
+}
+
+require_once '../../../version.php';
+require_once '../elgglib.php';
+$upgrade_path = dirname(__FILE__);
+
+$upgrade_name = strtolower($name);
+$upgrade_name = str_replace(array(' ', '-'), '_', $upgrade_name);
+$upgrade_release = str_replace(array(' ', '-'), '_', $release);
+$time = time();
+$upgrade_rnd = substr(md5($time), 0, 16);
+$upgrade_date = date('Ymd', $time);
+
+// determine the inc count
+$upgrade_inc = 0;
+$files = elgg_get_file_list($upgrade_path);
+sort($files);
+
+foreach ($files as $filename) {
+ $filename = basename($filename);
+ $date = (int)substr($filename, 0, 8);
+ $inc = (int)substr($filename, 8, 2);
+
+ if ($upgrade_date == $date) {
+ if ($inc >= $upgrade_inc) {
+ $upgrade_inc = $inc + 1;
+ }
+ }
+}
+
+// zero-pad
+// if there are more than 10 upgrades in a day, someone needs talking to.
+if ($upgrade_inc < 10) {
+ $upgrade_inc = "0$upgrade_inc";
+}
+
+// make filename
+if (substr($release, 0, 3) == '1.7') {
+ // 1.7 upgrades are YYYYMMDDXX
+ $upgrade_name = $upgrade_date . $upgrade_inc . '.php';
+} else {
+ // 1.8+ upgrades are YYYYMMDDXX-release-friendly_name-rnd
+ $upgrade_name = $upgrade_date . $upgrade_inc . "-$upgrade_release-$name-$upgrade_rnd.php";
+}
+
+$upgrade_file = $upgrade_path . '/' . $upgrade_name;
+
+if (is_file($upgrade_file)) {
+ elgg_create_upgrade_show_usage("Upgrade file $upgrade_file already exists. This script has failed you.");
+}
+
+$upgrade_code = <<<___UPGRADE
+<?php
+/**
+ * Elgg $version upgrade $date$inc
+ * $name
+ */
+
+// upgrade code here.
+
+___UPGRADE;
+
+$h = fopen($upgrade_file, 'wb');
+
+if (!$h) {
+ die("Could not open file $upgrade_file");
+}
+
+if (!fputs($h, $upgrade_code)) {
+ die("Could not write to $upgrade_file");
+} else {
+ echo "\nCreated file $upgrade_name. Add your upgrade code there.\n\n";
+}
+
+fclose($h);
+
+
+/**
+ * Shows the usage for the create_upgrade script and dies().
+ *
+ * @param string $msg Optional message to display
+ * @return void
+ */
+function elgg_create_upgrade_show_usage($msg = '') {
+ $text = <<<___MSG
+$msg
+
+Example:
+ php create_upgrade.php my_upgrade
+
+___MSG;
+
+ die($text);
+} \ No newline at end of file
diff --git a/engine/lib/version.php b/engine/lib/version.php
index 4ffe85bc5..60ae2c973 100644
--- a/engine/lib/version.php
+++ b/engine/lib/version.php
@@ -19,47 +19,151 @@ function upgrade_code($version, $quiet = FALSE) {
global $CONFIG;
$version = (int) $version;
+ $upgrade_path = elgg_get_config('path') . 'engine/lib/upgrades/';
+ $processed_upgrades = unserialize(datalist_get('processed_upgrades'));
+ // the day we started the new upgrade names
+ $upgrade_epoch = 2011021700;
- if ($handle = opendir($CONFIG->path . 'engine/lib/upgrades/')) {
- $upgrades = array();
-
- while ($updatefile = readdir($handle)) {
- // Look for upgrades and add to upgrades list
- if (!is_dir($CONFIG->path . 'engine/lib/upgrades/' . $updatefile)) {
- if (preg_match('/^([0-9]{10})\.(php)$/', $updatefile, $matches)) {
- $core_version = (int) $matches[1];
- if ($core_version > $version) {
- $upgrades[] = $updatefile;
- }
+ if (!$processed_upgrades) {
+ $processed_upgrades = array();
+ }
+
+ $upgrades = array();
+
+ $upgrade_files = elgg_get_upgrade_files($upgrade_path);
+
+ if ($upgrade_files === false) {
+ return false;
+ }
+
+ // bootstrap into the new upgrade system.
+ // can't do this in an upgrade because we need to check for 2010050701,
+ // which would already have been run by then.
+ if ($version < $upgrade_epoch) {
+ foreach ($upgrade_files as $upgrade_file) {
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
+
+ // the upgrade that made life difficult
+ // the only way to test if we're upgrading from 1.7 to 1.8 or within 1.8
+ // is to test for the the walled_garden config option, which
+ // 2010050701 explicitly sets
+ if ($upgrade_version == 2010050701) {
+ $db_prefix = elgg_get_config('dbprefix');
+ $site_guid = elgg_get_config('site_guid');
+ $q = "SELECT value FROM {$db_prefix}config
+ WHERE name = 'walled_garden' AND site_guid = {$site_guid}";
+ $result = get_data_row($q);
+ if (!$result) {
+ $upgrades[] = $upgrade_file;
}
+
+ continue;
+ } elseif ($version < $upgrade_version) {
+ $upgrades[] = $upgrade_file;
+ } else {
+ // all of the upgrades before the epoch have been run except one...
+ $processed_upgrades[] = $upgrade_file;
}
}
+ } else {
+ // add any upgrades that haven't been run to the upgrades list
+ $upgrades = elgg_get_unprocessed_upgrades($upgrade_files, $processed_upgrades);
+ }
+
+ // Sort and execute
+ ksort($upgrades);
+
+ foreach ($upgrades as $upgrade) {
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade);
+ $success = true;
- // Sort and execute
- asort($upgrades);
-
- if (sizeof($upgrades) > 0) {
- foreach ($upgrades as $upgrade) {
- // hide all errors.
- if ($quiet) {
- // hide include errors as well as any exceptions that might happen
- try {
- if (!@include($CONFIG->path . 'engine/lib/upgrades/' . $upgrade)) {
- error_log($e->getmessage());
- }
- } catch (Exception $e) {
- error_log($e->getmessage());
- }
- } else {
- include($CONFIG->path . 'engine/lib/upgrades/' . $upgrade);
+ // hide all errors.
+ if ($quiet) {
+ // hide include errors as well as any exceptions that might happen
+ try {
+ if (!@include("$upgrade_path/$upgrade")) {
+ $success = false;
+ error_log($e->getmessage());
}
+ } catch (Exception $e) {
+ $success = false;
+ error_log($e->getmessage());
+ }
+ } else {
+ if (!include("$upgrade_path/$upgrade")) {
+ $success = false;
}
}
- return TRUE;
+ if ($success) {
+ // incrementally set upgrade so we know where to start if something fails.
+ $processed_upgrades[] = $upgrade;
+
+ // don't set the version to a lower number in instances where an upgrade
+ // has been merged from a lower version
+ if ($upgrade_version > $version) {
+ datalist_set('version', $upgrade_version);
+ }
+
+ $processed_upgrades = array_unique($processed_upgrades);
+ datalist_set('processed_upgrades', serialize($processed_upgrades));
+ } else {
+ return false;
+ }
}
- return FALSE;
+ return true;
+}
+
+/**
+ * Returns the version of the upgrade filename.
+ *
+ * @param string $filename The upgrade filename. No full path.
+ * @return int|false
+ * @since 1.8
+ */
+function elgg_get_upgrade_file_version($filename) {
+ preg_match('/^([0-9]{10})([\.a-z0-9-_]+)?\.(php)$/i', $filename, $matches);
+
+ if (isset($matches[1])) {
+ return (int) $matches[1];
+ }
+
+ return false;
+}
+
+/**
+ * Returns a list of upgrade files relative to the $upgrade_path dir.
+ *
+ * @param string $upgrade_path The up
+ * @return array|false
+ */
+function elgg_get_upgrade_files($upgrade_path = null) {
+ if (!$upgrade_path) {
+ $upgrade_path = elgg_get_config('path') . 'engine/lib/upgrades/';
+ }
+ $upgrade_path = sanitise_filepath($upgrade_path);
+ $handle = opendir($upgrade_path);
+
+ if (!$handle) {
+ return false;
+ }
+
+ $upgrade_files = array();
+
+ while ($upgrade_file = readdir($handle)) {
+ // make sure this is a wellformed upgrade.
+ if (is_dir($upgrade_path . '$upgrade_file')) {
+ continue;
+ }
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
+ if (!$upgrade_version) {
+ continue;
+ }
+ $upgrade_files[] = $upgrade_file;
+ }
+
+ return $upgrade_files;
}
/**
@@ -82,6 +186,30 @@ function get_version($humanreadable = false) {
}
/**
+ * Checks if any upgrades need to be run.
+ *
+ * @param null|array $upgrade_files Optional upgrade files
+ * @param null|array $processed_upgrades Optional processed upgrades
+ *
+ * @return array()
+ */
+function elgg_get_unprocessed_upgrades($upgrade_files = null, $processed_upgrades = null) {
+ if ($upgrade_files === null) {
+ $upgrade_files = elgg_get_upgrade_files();
+ }
+
+ if ($processed_upgrades === null) {
+ $processed_upgrades = unserialize(datalist_get('processed_upgrades'));
+ if (!is_array($processed_upgrades)) {
+ $processed_upgrades = array();
+ }
+ }
+
+ $unprocessed = array_diff($upgrade_files, $processed_upgrades);
+ return $unprocessed;
+}
+
+/**
* Determines whether or not the database needs to be upgraded.
*
* @return true|false Depending on whether or not the db version matches the code version
@@ -114,23 +242,20 @@ function version_upgrade() {
// See http://trac.elgg.org/elgg/ticket/1432 for more.
$quiet = !$dbversion;
- // Upgrade database
- if (db_upgrade($dbversion, '', $quiet)) {
- system_message(elgg_echo('upgrade:db'));
- }
+ // Note: Database upgrades are deprecated as of 1.8. Use code upgrades. See #1433
- // Upgrade core
if (upgrade_code($dbversion, $quiet)) {
system_message(elgg_echo('upgrade:core'));
- }
- // Now we trigger an event to give the option for plugins to do something
- $upgrade_details = new stdClass;
- $upgrade_details->from = $dbversion;
- $upgrade_details->to = get_version();
+ // Now we trigger an event to give the option for plugins to do something
+ $upgrade_details = new stdClass;
+ $upgrade_details->from = $dbversion;
+ $upgrade_details->to = get_version();
+
+ elgg_trigger_event('upgrade', 'upgrade', $upgrade_details);
- elgg_trigger_event('upgrade', 'upgrade', $upgrade_details);
+ return true;
+ }
- // Update the version
- datalist_set('version', get_version());
+ return false;
}