Commit 2f5b00a68863a9a16a860072b9d9ab41cd3cdde8

Authored by Neil Blakey-Milner
1 parent 56d2a807

Upgrade functionality for KnowledgeTree - allows automated upgrades from

one version of KnowledgeTree to another.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@3359 c91229c3-7414-0410-bfa2-8a42b809f60b
lib/upgrades/UpgradeFunctions.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +class UpgradeFunctions {
  4 + var $upgrades = array(
  5 + "2.0.0" => array("setPermissionFolder", "rebuildSearchPermissions"),
  6 + "2.0.6" => array("addTemplateMimeTypes"),
  7 + );
  8 + var $descriptions = array(
  9 + "rebuildSearchPermissions" => "Rebuild search permissions with updated algorithm",
  10 + "setPermissionFolder" => "Set permission folder for each folder for simplified permissions management",
  11 + "addTemplateMimeTypes" => "Add MIME types for Excel and Word templates",
  12 + );
  13 + function setPermissionFolder() {
  14 + require_once(KT_LIB_DIR . '/foldermanagement/Folder.inc');
  15 +
  16 + $sQuery = "SELECT id FROM $default->folders_table WHERE permission_folder_id = NULL";
  17 +
  18 + $aIDs = DBUtil::getResultArrayKey($sQuery, 'id');
  19 +
  20 + foreach ($aIDs as $iID) {
  21 + $oFolder =& Folder::get($iID);
  22 + $oFolder->calculatePermissionFolder();
  23 + $oFolder->update();
  24 + }
  25 + }
  26 +
  27 + function rebuildSearchPermissions() {
  28 + require_once(KT_LIB_DIR . '/documentmanagement/Document.inc');
  29 + require_once(KT_LIB_DIR . '/security/Permission.inc');
  30 +
  31 + $aDocuments = Document::getList();
  32 + foreach ($aDocuments as $oDocument) {
  33 + Permission::updateSearchPermissionsForDocument($oDocument->getID());
  34 + }
  35 + return true;
  36 + }
  37 +
  38 + function addTemplateMimeTypes() {
  39 + global $default;
  40 + $table = $default->mimetypes_table;
  41 + $query = sprintf('SELECT id FROM %s WHERE filetypes = ?',
  42 + $table);
  43 +
  44 + $newTypes = array(
  45 + array(
  46 + 'filetypes' => 'xlt',
  47 + 'mimetypes' => 'application/vnd.ms-excel',
  48 + 'icon_path' => 'icons/excel.gif',
  49 + ),
  50 + array(
  51 + 'filetypes' => 'dot',
  52 + 'mimetypes' => 'application/msword',
  53 + 'icon_path' => 'icons/word.gif',
  54 + ),
  55 + );
  56 + foreach ($newTypes as $types) {
  57 + $res = DBUtil::getOneResultKey(array($query, $types['filetypes']), 'id');
  58 + if (PEAR::isError($res)) {
  59 + return $res;
  60 + }
  61 + if (is_null($res)) {
  62 + $res = DBUtil::autoInsert($table, $types);
  63 + if (PEAR::isError($res)) {
  64 + return $res;
  65 + }
  66 + }
  67 + }
  68 + return true;
  69 + }
  70 +}
  71 +
  72 +?>
... ...
lib/upgrades/UpgradeItems.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +// {{{ Format of the descriptor
  4 +/**
  5 + * Format of the descriptor
  6 + *
  7 + * type*version*phase*simple description for uniqueness
  8 + *
  9 + * type is: sql, function, subupgrade, upgrade
  10 + * version is: 1.2.4, 2.0.0rc5
  11 + * phase is: 0, 1, 0pre. Phase is _only_ evaluated by describeUpgrades.
  12 + * description is: anything, unique in terms of version and type.
  13 + */
  14 +// }}}
  15 +
  16 +require_once(KT_LIB_DIR . '/upgrades/UpgradeFunctions.inc.php');
  17 +require_once(KT_LIB_DIR . '/database/sqlfile.inc.php');
  18 +require_once(KT_LIB_DIR . '/database/datetime.inc');
  19 +
  20 +// {{{ Upgrade_Already_Applied
  21 +class Upgrade_Already_Applied extends PEAR_Error {
  22 + function Upgrade_Already_Applied($oUpgradeItem) {
  23 + $this->oUpgradeItem = $oUpgradeItem;
  24 + }
  25 +}
  26 +// }}}
  27 +
  28 +class UpgradeItem {
  29 + var $type = "";
  30 + var $name;
  31 + var $version;
  32 + var $description;
  33 + var $phase;
  34 + var $parent;
  35 + var $date;
  36 + var $result;
  37 +
  38 + function UpgradeItem($name, $version, $description = null, $phase = 0) {
  39 + $this->name = $name;
  40 + $this->version = $version;
  41 + if (is_null($description)) {
  42 + $description = $this->type . " upgrade to version " . $version . " phase " . $phase;
  43 + }
  44 + $this->description = $description;
  45 + $this->phase = $phase;
  46 + }
  47 +
  48 + function setParent($parent) {
  49 + $this->parent = $parent;
  50 + }
  51 + function setDate($date) {
  52 + $this->date = $date;
  53 + }
  54 +
  55 + function getDescriptor() {
  56 + return join("*", array($this->type, $this->version, $this->phase, $this->name));
  57 + }
  58 +
  59 + function getDescription() {
  60 + return $this->description;
  61 + }
  62 +
  63 + function getVersion() {
  64 + return $this->version;
  65 + }
  66 +
  67 + function getPhase() {
  68 + return $this->phase;
  69 + }
  70 +
  71 + function getType() {
  72 + return $this->type;
  73 + }
  74 +
  75 + function isAlreadyApplied() {
  76 + $query = "SELECT id FROM upgrades WHERE descriptor = ? AND result = ?";
  77 + $params = array($this->getDescriptor(), true);
  78 + $res = DBUtil::getOneResultKey(array($query, $params), 'id');
  79 + if (PEAR::isError($res)) {
  80 + return $res;
  81 + }
  82 + if (is_null($res)) {
  83 + return false;
  84 + }
  85 + return true;
  86 + }
  87 +
  88 + function performUpgrade($force = false) {
  89 + $res = $this->isAlreadyApplied();
  90 + if ($res === true || PEAR::isError($res)) {
  91 + if ($force !== true) {
  92 + // PHP5: Exception
  93 + return new Upgrade_Already_Applied($this);
  94 + }
  95 + }
  96 + $res = $this->_performUpgrade();
  97 + if (PEAR::isError($res)) {
  98 + $this->_recordUpgrade(false);
  99 + return $res;
  100 + }
  101 + $res = $this->_recordUpgrade(true);
  102 + if (PEAR::isError($res)) {
  103 + return $res;
  104 + }
  105 + return true;
  106 + }
  107 +
  108 + function _performUpgrade() {
  109 + return PEAR::raiseError("Unimplemented");
  110 + }
  111 +
  112 + function _recordUpgrade($result) {
  113 + if (is_null($this->date)) {
  114 + $this->date = getCurrentDateTime();
  115 + }
  116 + if ($this->parent) {
  117 + $parentid = $this->parent->getDescriptor();
  118 + } else {
  119 + $parentid = null;
  120 + }
  121 + return DBUtil::autoInsert("upgrades", array(
  122 + "descriptor" => $this->getDescriptor(),
  123 + "description" => $this->description,
  124 + "date_performed" => $this->date,
  125 + "result" => $result,
  126 + "parent" => $parentid,
  127 + ));
  128 + }
  129 +
  130 + // STATIC
  131 + function getAllUpgrades() {
  132 + return array();
  133 + }
  134 +}
  135 +
  136 +class SQLUpgradeItem extends UpgradeItem {
  137 + function SQLUpgradeItem($path, $version = null, $description = null, $phase = null) {
  138 + $this->type = "sql";
  139 + $details = $this->_getDetailsFromFileName($path);
  140 + if (is_null($version)) {
  141 + $version = $details[1];
  142 + }
  143 + if (is_null($description)) {
  144 + $description = $details[2];
  145 + }
  146 + if (is_null($phase)) {
  147 + $phase = $details[3];
  148 + }
  149 + $this->UpgradeItem($path, $version, $description, $phase);
  150 + }
  151 +
  152 + /**
  153 + * Describe the SQL scripts that will be used to upgrade KnowledgeTree
  154 + *
  155 + * Return an array of arrays with two components: a string identifier
  156 + * that uniquely describes the step to be taken and a string which is an
  157 + * HTML-formatted description of the step to be taken. These will be
  158 + * returned in any order - describeUpgrade performs the ordering.
  159 + *
  160 + * @param string Original version (e.g., "1.2.4")
  161 + * @param string Current version (e.g., "2.0.2")
  162 + *
  163 + * @return array Array of SQLUpgradeItem describing steps to be taken
  164 + *
  165 + * STATIC
  166 + */
  167 + function getUpgrades($origVersion, $currVersion) {
  168 + global $default;
  169 + $sqlupgradedir = KT_DIR . '/sql/' . $default->dbType . '/upgrade/';
  170 +
  171 + $ret = array();
  172 +
  173 + if (!is_dir($sqlupgradedir)) {
  174 + return PEAR::raiseError("SQL Upgrade directory ($sqlupgradedir) not accessible");
  175 + }
  176 + if (!($dh = opendir($sqlupgradedir))) {
  177 + return PEAR::raiseError("SQL Upgrade directory ($sqlupgradedir) not accessible");
  178 + }
  179 +
  180 + while (($file = readdir($dh)) !== false) {
  181 + // Each entry can be a file or a directory
  182 + //
  183 + // A file is legacy before the upgrade system was created, but
  184 + // will be supported anyway.
  185 + //
  186 + // A directory is the end-result version: so, 2.0.5 contains
  187 + // every script that differentiates it from a previous version,
  188 + // say, 2.0.5rc1 or 2.0.4.
  189 + //
  190 + if (in_array($file, array('.', '..', 'CVS'))) {
  191 + continue;
  192 + }
  193 + $fullpath = $sqlupgradedir . $file;
  194 + if (is_file($fullpath)) {
  195 + // Legacy file support, will be in form of
  196 + // 1.2.4-to-2.0.0.sql.
  197 + $details = SQLUpgradeItem::_getDetailsFromFileName($file);
  198 + if ($details) {
  199 + if (!gte_version($details[0], $origVersion)) {
  200 + continue;
  201 + }
  202 + if (!lte_version($details[1], $currVersion)) {
  203 + continue;
  204 + }
  205 + //print "Will run $file\n";
  206 + $ret[] = new SQLUpgradeItem($file);
  207 + }
  208 + }
  209 + if (is_dir($fullpath)) {
  210 + $subdir = $file;
  211 + if (!($subdh = opendir($fullpath))) {
  212 + continue;
  213 + }
  214 + while (($file = readdir($subdh)) !== false) {
  215 + $relpath = $subdir . '/' . $file;
  216 + $details = SQLUpgradeItem::_getDetailsFromFileName($relpath);
  217 + if ($details) {
  218 + if (!gte_version($details[0], $origVersion)) {
  219 + continue;
  220 + }
  221 + if (!lte_version($details[1], $currVersion)) {
  222 + continue;
  223 + }
  224 + //print "Will run $file\n";
  225 + $ret[] = new SQLUpgradeItem($relpath);
  226 + }
  227 + }
  228 + }
  229 + }
  230 + closedir($dh);
  231 + return $ret;
  232 + }
  233 +
  234 + function _getDetailsFromFileName($path) {
  235 + // Old format (pre 2.0.6)
  236 + $matched = preg_match('#^([\d.]*)-to-([\d.]*).sql$#', $path, $matches);
  237 + if ($matched != 0) {
  238 + $fromVersion = $matches[1];
  239 + $toVersion = $matches[2];
  240 + $description = "Database upgrade from version $fromVersion to $toVersion";
  241 + $phase = 0;
  242 + return array($fromVersion, $toVersion, $description, $phase);
  243 + }
  244 + $matched = preg_match('#^([\d.]*)/(?:(\d)-)?(.*)\.sql$#', $path, $matches);
  245 + if ($matched != 0) {
  246 + $fromVersion = $matches[1];
  247 + $toVersion = $matches[1];
  248 + $in = array('_');
  249 + $out = array(' ');
  250 + $phase = (int)$matches[2];
  251 + $description = "Database upgrade to version $toVersion: " . ucfirst(str_replace($in, $out, $matches[3]));
  252 + return array($fromVersion, $toVersion, $description, $phase);
  253 + }
  254 + // XXX: handle new format
  255 + return null;
  256 + }
  257 +
  258 + function _performUpgrade() {
  259 + global $default;
  260 + $sqlupgradedir = KT_DIR . '/sql/' . $default->dbType . '/upgrade/';
  261 + $queries = SQLFile::sqlFromFile($sqlupgradedir . $this->name);
  262 + var_dump($queries);
  263 + //return DBUtil::runQueries($queries);
  264 + }
  265 +}
  266 +
  267 +class FunctionUpgradeItem extends UpgradeItem {
  268 + function FunctionUpgradeItem ($func, $version, $description = null, $phase = null) {
  269 + $this->type = "func";
  270 + if (is_null($description)) {
  271 + $aUpgradeFunctions = new UpgradeFunctions;
  272 + $description = $UpgradeFunctions->descriptions[$func];
  273 + }
  274 + if (is_null($phase)) {
  275 + $phase = 0;
  276 + }
  277 + $this->UpgradeItem($func, $version, $description, $phase);
  278 + }
  279 +
  280 + function getUpgrades($origVersion, $currVersion) {
  281 + $aUpgradeFunctions = new UpgradeFunctions;
  282 +
  283 + $ret = array();
  284 +
  285 + foreach ($aUpgradeFunctions->upgrades as $version => $funcs) {
  286 + if (!gte_version($version, $origVersion)) {
  287 + continue;
  288 + }
  289 + if (!lte_version($version, $currVersion)) {
  290 + continue;
  291 + }
  292 + foreach ($funcs as $func) {
  293 + $ret[] = new FunctionUpgradeItem($func, $version, $aUpgradeFunctions->descriptions[$func], 0);
  294 + }
  295 + }
  296 + return $ret;
  297 + }
  298 +
  299 + function _performUpgrade() {
  300 + $function = array('UpgradeFunctions', $this->name);
  301 + return call_user_func($function);
  302 + }
  303 +}
  304 +
  305 +class RecordUpgradeItem extends UpgradeItem {
  306 + function RecordUpgradeItem ($version, $oldversion = null) {
  307 + $this->type = "upgrade";
  308 + if (is_null($oldversion)) {
  309 + $this->description = "Upgrade to version $version";
  310 + } else {
  311 + $this->description = "Upgrade from version $oldversion to $version";
  312 + }
  313 + $this->phase = 0;
  314 + $this->version = $version;
  315 + $this->name = 'upgrade' . $version;
  316 + }
  317 + function _performUpgrade() {
  318 + return true;
  319 + }
  320 +}
  321 +
  322 +?>
... ...
lib/upgrades/upgrade.inc.php 0 → 100644
  1 +<?php
  2 +/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3 +
  4 +/**
  5 + * $Id$
  6 + *
  7 + * Assists in discovering what needs to be done to upgrade one version
  8 + * of KnowledgeTree to another.
  9 + *
  10 + * Copyright (c) 2005 Jam Warehouse http://www.jamwarehouse.com
  11 + *
  12 + * This program is free software; you can redistribute it and/or modify
  13 + * it under the terms of the GNU General Public License as published by
  14 + * the Free Software Foundation; either version 2 of the License, or
  15 + * (at your option) any later version.
  16 + *
  17 + * This program is distributed in the hope that it will be useful,
  18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 + * GNU General Public License for more details.
  21 + *
  22 + * You should have received a copy of the GNU General Public License
  23 + * along with this program; if not, write to the Free Software
  24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25 + *
  26 + * @version $Revision$
  27 + * @author Neil Blakey-Milner <nbm@jamwarehouse.com>, Jam Warehouse (Pty) Ltd, South Africa
  28 + */
  29 +
  30 +require_once(KT_LIB_DIR . '/upgrades/UpgradeItems.inc.php');
  31 +
  32 +// {{{ Format of the descriptor
  33 +/**
  34 + * Format of the descriptor
  35 + *
  36 + * type*version*phase*simple description for uniqueness
  37 + *
  38 + * type is: sql, function, subupgrade, upgrade
  39 + * version is: 1.2.4, 2.0.0rc5
  40 + * phase is: 0, 1, 0pre. Phase is _only_ evaluated by describeUpgrades.
  41 + * description is: anything, unique in terms of version and type.
  42 + */
  43 +// }}}
  44 +
  45 +// {{{ describeUpgrade
  46 +/**
  47 + * Describe the upgrade path between two versions of KnowledgeTree.
  48 + *
  49 + * @param string Original version (e.g., "1.2.4")
  50 + * @param string Current version (e.g., "2.0.2")
  51 + *
  52 + * @return array Array of UpgradeItem describing steps to be taken
  53 + */
  54 +function &describeUpgrade ($origVersion, $currVersion) {
  55 + // How to figure out what upgrades to do:
  56 + //
  57 + // 1. Get all SQL upgrades >= origVersion and <= currVersion
  58 + // 2. Get all Function upgrades >= origVersion and <= currVersion
  59 + // 3. Categorise each into version they upgrade to
  60 + // 4. Sort each version subgroup into correct order
  61 + // 5. Add "recordSubUpgrade" for each version there.
  62 + // 6. Add back into one big list again
  63 + // 7. Add "recordUpgrade" for whole thing
  64 +
  65 + // $recordUpgrade = array('upgrade*' . $currVersion, 'Upgrade to ' . $currVersion, null);
  66 +
  67 + $steps = array();
  68 + foreach (array('SQLUpgradeItem', 'FunctionUpgradeItem') as $itemgen) {
  69 + $f = array($itemgen, 'getUpgrades');
  70 + $ssteps =& call_user_func($f, $origVersion, $currVersion);
  71 + $scount = count($ssteps);
  72 + for ($i = 0; $i < $scount; $i++) {
  73 + $steps[] =& $ssteps[$i];
  74 + }
  75 + }
  76 + $upgradestep =& new RecordUpgradeItem($currVersion, $origVersion);
  77 + $steps[] =& $upgradestep;
  78 + $stepcount = count($steps);
  79 + for ($i = 0; $i < $stepcount; $i++) {
  80 + $step =& $steps[$i];
  81 + $step->setParent($upgradestep);
  82 + }
  83 + usort($steps, 'step_sort_func');
  84 +
  85 + return $steps;
  86 +}
  87 +// }}}
  88 +
  89 +// {{{ step_sort_func
  90 +function step_sort_func ($obj1, $obj2) {
  91 + $res = compare_version($obj1->getVersion(), $obj2->getVersion());
  92 + if ($res !== 0) {
  93 + return $res;
  94 + }
  95 + if ($obj1->getPhase() > $obj2->getPhase()) {
  96 + return 1;
  97 + }
  98 + if ($obj1->getPhase() < $obj2->getPhase()) {
  99 + return -1;
  100 + }
  101 + return 0;
  102 +}
  103 +// }}}
  104 +
  105 +// {{{ compare_version
  106 +/**
  107 + * Compares two version numbers and returns a value based on this comparison
  108 + *
  109 + * Using standard software version rules, such as 2.0.5rc1 comes before
  110 + * 2.0.5, and 2.0.5rc1 comes after 2.0.5alpha1, compare two version
  111 + * numbers, and determine which is the higher.
  112 + *
  113 + * XXX: Actually, just does $version1 < $version2
  114 + *
  115 + * @param string First version number
  116 + * @param string Second version number
  117 + *
  118 + * @return int -1, 0, 1
  119 + */
  120 +function compare_version($version1, $version2) {
  121 + // XXX: Version comparisons should be better.
  122 + if ($version1 < $version2) {
  123 + return -1;
  124 + }
  125 + if ($version1 > $version2) {
  126 + return 1;
  127 + }
  128 + return 0;
  129 +}
  130 +// }}}
  131 +
  132 +// {{{ lte_version
  133 +/**
  134 + * Quick-hand for checking if a version number is lower-than-or-equal-to
  135 + */
  136 +function lte_version($version1, $version2) {
  137 + if (in_array(compare_version($version1, $version2), array(-1, 0))) {
  138 + return true;
  139 + }
  140 + return false;
  141 +}
  142 +// }}
  143 +
  144 +// {{ gte_version
  145 +/**
  146 + * Quick-hand for checking if a version number is greater-than-or-equal-to
  147 + */
  148 +function gte_version($version1, $version2) {
  149 + if (in_array(compare_version($version1, $version2), array(0, 1))) {
  150 + return true;
  151 + }
  152 + return false;
  153 +}
  154 +// }}}
  155 +
  156 +?>
... ...