MDL-15249 removing copy of getopt, using standard version instead
[moodle.git] / lib / upgradelib.php
CommitLineData
db9d4a3d 1<?php //$Id$
2
3/**
4 * upgradelib.php - Contains functions used during upgrade
5 *
6 * @author Martin Dougiamas and many others
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 * @package moodlecore
9 */
10
11define('UPGRADE_LOG_NORMAL', 0);
12define('UPGRADE_LOG_NOTICE', 1);
795a08ad 13define('UPGRADE_LOG_ERROR', 2);
14
15/**
16 * Exception indicating unknown error during upgrade.
17 */
18class upgrade_exception extends moodle_exception {
19 function __construct($plugin, $version) {
20 global $CFG;
21 $a = (object)array('plugin'=>$plugin, 'version'=>$version);
22 parent::__construct('upgradeerror', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
23 }
24}
25
26/**
27 * Exception indicating downgrade error during upgrade.
28 */
29class downgrade_exception extends moodle_exception {
30 function __construct($plugin, $oldversion, $newversion) {
31 global $CFG;
32 $plugin = is_null($plugin) ? 'moodle' : $plugin;
33 $a = (object)array('plugin'=>$plugin, 'oldversion'=>$oldversion, 'newversion'=>$newversion);
34 parent::__construct('cannotdowngrade', 'debug', "$CFG->wwwroot/$CFG->admin/index.php", $a);
35 }
36}
37
38class upgrade_requires_exception extends moodle_exception {
39 function __construct($plugin, $pluginversion, $currentmoodle, $requiremoodle) {
40 global $CFG;
41 $a = new object();
42 $a->pluginname = $plugin;
43 $a->pluginversion = $pluginversion;
44 $a->currentmoodle = $currentmoodle;
45 $a->requiremoodle = $currentmoodle;
46 parent::__construct('pluginrequirementsnotmet', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
47 }
48}
49
50class plugin_defective_exception extends moodle_exception {
51 function __construct($plugin, $details) {
52 global $CFG;
53 parent::__construct('detectedbrokenplugin', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $plugin, $details);
54 }
55}
db9d4a3d 56
57/**
58 * Insert or update log display entry. Entry may already exist.
59 * $module, $action must be unique
60 *
61 * @param string $module
62 * @param string $action
63 * @param string $mtable
64 * @param string $field
65 * @return void
66 *
67 */
68function update_log_display_entry($module, $action, $mtable, $field) {
69 global $DB;
70
71 if ($type = $DB->get_record('log_display', array('module'=>$module, 'action'=>$action))) {
72 $type->mtable = $mtable;
73 $type->field = $field;
74 $DB->update_record('log_display', $type);
75
76 } else {
77 $type = new object();
78 $type->module = $module;
79 $type->action = $action;
80 $type->mtable = $mtable;
81 $type->field = $field;
82
83 $DB->insert_record('log_display', $type, false);
84 }
85}
86
87/**
88 * Upgrade savepoint, marks end of each upgrade block.
89 * It stores new main version, resets upgrade timeout
90 * and abort upgrade if user cancels page loading.
91 *
92 * Please do not make large upgrade blocks with lots of operations,
93 * for example when adding tables keep only one table operation per block.
94 *
95 * @param bool $result false if upgrade step failed, true if completed
96 * @param string or float $version main version
97 * @param bool $allowabort allow user to abort script execution here
98 * @return void
99 */
100function upgrade_main_savepoint($result, $version, $allowabort=true) {
101 global $CFG;
102
795a08ad 103 if (!$result) {
104 throw new upgrade_exception('moodle core', $version);
105 }
106
107 if ($CFG->version >= $version) {
108 // something really wrong is going on in main upgrade script
109 throw new downgrade_exception(null, $CFG->version, $version);
db9d4a3d 110 }
111
795a08ad 112 set_config('version', $version);
113 upgrade_log(UPGRADE_LOG_NORMAL, null, 'Upgrade savepoint reached');
114
db9d4a3d 115 // reset upgrade timeout to default
116 upgrade_set_timeout();
117
118 // this is a safe place to stop upgrades if user aborts page loading
119 if ($allowabort and connection_aborted()) {
120 die;
121 }
122}
123
124/**
125 * Module upgrade savepoint, marks end of module upgrade blocks
126 * It stores module version, resets upgrade timeout
127 * and abort upgrade if user cancels page loading.
128 *
129 * @param bool $result false if upgrade step failed, true if completed
130 * @param string or float $version main version
131 * @param string $modname name of module
132 * @param bool $allowabort allow user to abort script execution here
133 * @return void
134 */
135function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) {
136 global $DB;
137
795a08ad 138 if (!$result) {
139 throw new upgrade_exception("mod/$modname", $version);
140 }
141
db9d4a3d 142 if (!$module = $DB->get_record('modules', array('name'=>$modname))) {
143 print_error('modulenotexist', 'debug', '', $modname);
144 }
145
795a08ad 146 if ($module->version >= $version) {
147 // something really wrong is going on in upgrade script
148 throw new downgrade_exception("mod/$modname", $module->version, $version);
db9d4a3d 149 }
795a08ad 150 $module->version = $version;
151 $DB->update_record('modules', $module);
152 upgrade_log(UPGRADE_LOG_NORMAL, "mod/$modname", 'Upgrade savepoint reached');
db9d4a3d 153
154 // reset upgrade timeout to default
155 upgrade_set_timeout();
156
157 // this is a safe place to stop upgrades if user aborts page loading
158 if ($allowabort and connection_aborted()) {
159 die;
160 }
161}
162
163/**
164 * Blocks upgrade savepoint, marks end of blocks upgrade blocks
165 * It stores block version, resets upgrade timeout
166 * and abort upgrade if user cancels page loading.
167 *
168 * @param bool $result false if upgrade step failed, true if completed
169 * @param string or float $version main version
170 * @param string $blockname name of block
171 * @param bool $allowabort allow user to abort script execution here
172 * @return void
173 */
795a08ad 174function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) {
db9d4a3d 175 global $DB;
176
795a08ad 177 if (!$result) {
178 throw new upgrade_exception("blocks/$blockname", $version);
179 }
180
db9d4a3d 181 if (!$block = $DB->get_record('block', array('name'=>$blockname))) {
182 print_error('blocknotexist', 'debug', '', $blockname);
183 }
184
795a08ad 185 if ($block->version >= $version) {
186 // something really wrong is going on in upgrade script
187 throw new downgrade_exception("blocks/$blockname", $block->version, $version);
db9d4a3d 188 }
795a08ad 189 $block->version = $version;
190 $DB->update_record('block', $block);
191 upgrade_log(UPGRADE_LOG_NORMAL, "blocks/$blockname", 'Upgrade savepoint reached');
db9d4a3d 192
193 // reset upgrade timeout to default
194 upgrade_set_timeout();
195
196 // this is a safe place to stop upgrades if user aborts page loading
197 if ($allowabort and connection_aborted()) {
198 die;
199 }
200}
201
202/**
203 * Plugins upgrade savepoint, marks end of blocks upgrade blocks
204 * It stores plugin version, resets upgrade timeout
205 * and abort upgrade if user cancels page loading.
206 *
207 * @param bool $result false if upgrade step failed, true if completed
208 * @param string or float $version main version
209 * @param string $type name of plugin
210 * @param string $dir location of plugin
211 * @param bool $allowabort allow user to abort script execution here
212 * @return void
213 */
214function upgrade_plugin_savepoint($result, $version, $type, $dir, $allowabort=true) {
795a08ad 215 if (!$result) {
216 throw new upgrade_exception("$type/$dir", $version);
db9d4a3d 217 }
218
795a08ad 219 $fullname = $type.'_'.$dir;
220 $component = $type.'/'.$dir;
221
222 $installedversion = get_config($fullname, 'version');
223 if ($installedversion >= $version) {
224 // Something really wrong is going on in the upgrade script
225 throw new downgrade_exception($component, $installedversion, $version);
226 }
227 set_config('version', $version, $fullname);
228 upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
229
db9d4a3d 230 // Reset upgrade timeout to default
231 upgrade_set_timeout();
232
233 // This is a safe place to stop upgrades if user aborts page loading
234 if ($allowabort and connection_aborted()) {
235 die;
236 }
237}
238
239
240/**
241 * Upgrade plugins
242 *
243 * @uses $CFG
244 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
245 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
246 * @param string $return The url to prompt the user to continue to
247 */
795a08ad 248function upgrade_plugins($type, $dir, $startcallback, $endcallback) {
db9d4a3d 249 global $CFG, $DB;
250
251/// special cases
252 if ($type === 'mod') {
795a08ad 253 return upgrade_plugins_modules($startcallback, $endcallback);
254 } else if ($type === 'block') {
255 return upgrade_plugins_blocks($startcallback, $endcallback);
db9d4a3d 256 }
257
258 $plugs = get_list_of_plugins($dir);
db9d4a3d 259
260 foreach ($plugs as $plug) {
261
795a08ad 262 $fullplug = $CFG->dirroot.'/'.$dir.'/'.$plug;
263 $component = $type.'/'.$plug; // standardised plugin name
db9d4a3d 264
795a08ad 265 if (!is_readable($fullplug.'/version.php')) {
266 continue;
db9d4a3d 267 }
268
795a08ad 269 $plugin = new object();
270 require($fullplug.'/version.php'); // defines $plugin with version etc
db9d4a3d 271
795a08ad 272 if (empty($plugin->version)) {
273 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 274 }
275
795a08ad 276 $plugin->name = $plug; // The name MUST match the directory
277 $plugin->fullname = $type.'_'.$plug; // The name MUST match the directory
278
279
db9d4a3d 280 if (!empty($plugin->requires)) {
281 if ($plugin->requires > $CFG->version) {
795a08ad 282 throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
db9d4a3d 283 }
284 }
285
db9d4a3d 286 $installedversion = get_config($plugin->fullname, 'version');
287
795a08ad 288 if (empty($installedversion)) { // new installation
289 $startcallback($component, true);
db9d4a3d 290
795a08ad 291 /// Install tables if defined
292 if (file_exists($fullplug.'/db/install.xml')) {
293 $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml');
db9d4a3d 294 }
795a08ad 295 /// execute post install file
296 if (file_exists($fullplug.'/db/install.php')) {
297 require_once($fullplug.'/db/install.php');
298 $post_install_function = 'xmldb_'.$plugin->fullname.'_install';;
299 $post_install_function();
300 }
301
302 /// store version
303 upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false);
304
305 /// Install various components
306 update_capabilities($component);
307 events_update_definition($component);
308 message_update_providers($component);
309
310 $endcallback($component, true);
311
312 } else if ($installedversion < $plugin->version) { // upgrade
313 /// Run the upgrade function for the plugin.
314 $startcallback($component, false);
315
316 if (is_readable($fullplug.'/db/upgrade.php')) {
317 require_once($fullplug.'/db/upgrade.php'); // defines upgrading function
318
319 $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade';
320 $result = $newupgrade_function($installedversion);
321 } else {
322 $result = true;
323 }
324
325 $installedversion = get_config($plugin->fullname, 'version');
326 if ($installedversion < $plugin->version) {
327 // store version if not already there
328 upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false);
329 }
330
331 /// Upgrade various components
332 update_capabilities($component);
333 events_update_definition($component);
334 message_update_providers($component);
335
336 $endcallback($component, false);
337
338 } else if ($installedversion > $plugin->version) {
339 throw new downgrade_exception($component, $installedversion, $plugin->version);
db9d4a3d 340 }
341 }
db9d4a3d 342}
343
344/**
345 * Find and check all modules and load them up or upgrade them if necessary
346 */
795a08ad 347function upgrade_plugins_modules($startcallback, $endcallback) {
db9d4a3d 348 global $CFG, $DB;
349
795a08ad 350 $mods = get_list_of_plugins('mod');
db9d4a3d 351
352 foreach ($mods as $mod) {
353
354 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
355 continue;
356 }
357
795a08ad 358 $fullmod = $CFG->dirroot.'/mod/'.$mod;
359 $component = 'mod/'.$mod;
db9d4a3d 360
795a08ad 361 if (!is_readable($fullmod.'/version.php')) {
362 throw new plugin_defective_exception($component, 'Missing version.php');
db9d4a3d 363 }
364
795a08ad 365 $module = new object();
366 require($fullmod .'/version.php'); // defines $module with version etc
db9d4a3d 367
795a08ad 368 if (empty($module->version)) {
c1fe2368 369 if (isset($module->version)) {
370 // Version is empty but is set - it means its value is 0 or ''. Let us skip such module.
371 // This is inteded for developers so they can work on the early stages of the module.
372 continue;
373 }
795a08ad 374 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 375 }
376
377 if (!empty($module->requires)) {
378 if ($module->requires > $CFG->version) {
795a08ad 379 throw new upgrade_requires_exception($component, $module->version, $CFG->version, $module->requires);
db9d4a3d 380 }
381 }
382
383 $module->name = $mod; // The name MUST match the directory
384
795a08ad 385 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
db9d4a3d 386
795a08ad 387 if (empty($currmodule->version)) {
388 $startcallback($component, true);
db9d4a3d 389
795a08ad 390 /// Execute install.xml (XMLDB) - must be present in all modules
391 $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml');
db9d4a3d 392
393 /// Post installation hook - optional
394 if (file_exists("$fullmod/db/install.php")) {
395 require_once("$fullmod/db/install.php");
396 $post_install_function = 'xmldb_'.$module->name.'_install';;
397 $post_install_function();
398 }
399
400 /// Continue with the installation, roles and other stuff
401 $module->id = $DB->insert_record('modules', $module);
402
795a08ad 403 /// Install various components
404 update_capabilities($component);
405 events_update_definition($component);
406 message_update_providers($component);
407
408 $endcallback($component, true);
db9d4a3d 409
795a08ad 410 } else if ($currmodule->version < $module->version) {
411 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
412 $startcallback($component, false);
413
414 if (is_readable($fullmod.'/db/upgrade.php')) {
415 require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function
416 $newupgrade_function = 'xmldb_'.$module->name.'_upgrade';
417 $result = $newupgrade_function($currmodule->version, $module);
418 } else {
419 $result = true;
420 }
421
422 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
423 if ($currmodule->version < $module->version) {
424 // store version if not already there
425 upgrade_mod_savepoint($result, $module->version, $mod, false);
426 }
427
428 /// Upgrade various components
429 update_capabilities($component);
430 events_update_definition($component);
431 message_update_providers($component);
432
433 remove_dir($CFG->dataroot.'/cache', true); // flush cache
434
435 $endcallback($component, false);
436
437 } else if ($currmodule->version > $module->version) {
438 throw new downgrade_exception($component, $currmodule->version, $module->version);
439 }
440 }
441}
db9d4a3d 442
db9d4a3d 443
795a08ad 444/**
445 * This function finds all available blocks and install them
446 * into blocks table or do all the upgrade process if newer.
447 */
448function upgrade_plugins_blocks($startcallback, $endcallback) {
449 global $CFG, $DB;
450
795a08ad 451 require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
452
453 $blocktitles = array(); // we do not want duplicate titles
454
455 //Is this a first install
456 $first_install = null;
457
458 $blocks = get_list_of_plugins('blocks');
459
460 foreach ($blocks as $blockname) {
461
462 if (is_null($first_install)) {
463 $first_install = ($DB->count_records('block') == 0);
464 }
465
466 if ($blockname == 'NEWBLOCK') { // Someone has unzipped the template, ignore it
467 continue;
db9d4a3d 468 }
469
795a08ad 470 $fullblock = $CFG->dirroot.'/blocks/'.$blockname;
471 $component = 'block/'.$blockname;
db9d4a3d 472
795a08ad 473 if (!is_readable($fullblock.'/block_'.$blockname.'.php')) {
474 throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.');
db9d4a3d 475 }
795a08ad 476 require_once($fullblock.'/block_'.$blockname.'.php');
db9d4a3d 477
795a08ad 478 $classname = 'block_'.$blockname;
479
480 if (!class_exists($classname)) {
481 throw new plugin_defective_exception($component, 'Can not load main class.');
482 }
483
484 $blockobj = new $classname; // This is what we 'll be testing
485 $blocktitle = $blockobj->get_title();
486
487 // OK, it's as we all hoped. For further tests, the object will do them itself.
488 if (!$blockobj->_self_test()) {
489 throw new plugin_defective_exception($component, 'Self test failed.');
490 }
491
492 $block = new object(); // This may be used to update the db below
493 $block->name = $blockname; // The name MUST match the directory
494 $block->version = $blockobj->get_version();
495 $block->cron = !empty($blockobj->cron) ? $blockobj->cron : 0;
496 $block->multiple = $blockobj->instance_allow_multiple() ? 1 : 0;
497
498 if (empty($block->version)) {
499 throw new plugin_defective_exception($component, 'Missing block version.');
500 }
501
502 $currblock = $DB->get_record('block', array('name'=>$block->name));
503
504 if (empty($currblock->version)) { // block not installed yet, so install it
505 // If it allows multiples, start with it enabled
506
507 $conflictblock = array_search($blocktitle, $blocktitles);
508 if ($conflictblock !== false) {
509 // Duplicate block titles are not allowed, they confuse people
510 // AND PHP's associative arrays ;)
511 throw new plugin_defective_exception($component, get_string('blocknameconflict', '', (object)array('name'=>$block->name, 'conflict'=>$conflictblock)));
512 }
513 $startcallback($component, true);
514
515 if (file_exists($fullblock.'/db/install.xml')) {
516 $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml');
517 }
518 $block->id = $DB->insert_record('block', $block);
519
520 if (file_exists($fullblock.'/db/install.php')) {
521 require_once($fullblock.'/db/install.php');
522 $post_install_function = 'xmldb_block_'.$blockname.'_install';;
523 $post_install_function();
524 }
525
526 $blocktitles[$block->name] = $blocktitle;
527
528 // Install various components
529 update_capabilities($component);
530 events_update_definition($component);
531 message_update_providers($component);
532
533 $endcallback($component, true);
534
535 } else if ($currblock->version < $block->version) {
536 $startcallback($component, false);
537
538 if (is_readable($fullblock.'/db/upgrade.php')) {
539 require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function
540 $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade';
541 $result = $newupgrade_function($currblock->version, $block);
542 } else {
543 $result = true;
544 }
545
546 $currblock = $DB->get_record('block', array('name'=>$block->name));
547 if ($currblock->version < $block->version) {
548 // store version if not already there
549 upgrade_block_savepoint($result, $block->version, $block->name, false);
550 }
551
552 if ($currblock->cron != $block->cron) {
553 // update cron flag if needed
554 $currblock->cron = $block->cron;
555 $DB->update_record('block', $currblock);
556 }
557
558 // Upgrade various componebts
559 events_update_definition($component);
560 update_capabilities($component);
561 message_update_providers($component);
562
563 $endcallback($component, false);
564
565 } else if ($currblock->version > $block->version) {
566 throw new downgrade_exception($component, $currblock->version, $block->version);
567 }
568 }
569
570
571 // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks
572 if ($first_install) {
795a08ad 573 //Iterate over each course - there should be only site course here now
574 if ($courses = $DB->get_records('course')) {
575 foreach ($courses as $course) {
9d1d606e 576 blocks_add_default_course_blocks($course);
db9d4a3d 577 }
578 }
795a08ad 579
9d1d606e 580 blocks_add_default_system_blocks();
795a08ad 581 }
582}
583
584/**
585 * This function checks to see whether local database customisations are up-to-date
586 * by comparing $CFG->local_version to the variable $local_version defined in
587 * local/version.php. If not, it looks for a function called 'xmldb_local_upgrade'
588 * in a file called 'local/db/upgrade.php', and if it's there calls it with the
589 * appropiate $oldversion parameter. Then it updates $CFG->local_version.
590 *
591 * @uses $CFG
592 */
593function upgrade_local_db($startcallback, $endcallback) {
594 global $CFG, $DB;
595
596 // if we don't have code version, just return false
597 if (!file_exists($CFG->dirroot.'/local/version.php')) {
598 return;
599 }
600
601 $local_version = null;
602 require($CFG->dirroot.'/local/version.php'); // Get code versions
603
604 if (empty($CFG->local_version)) { // install
605 $startcallback('local', true);
606
607 if (file_exists($CFG->dirroot.'/local/db/install.php')) {
608 require_once($CFG->dirroot.'/local/db/install.php');
609 xmldb_local_install();
610 }
611 set_config('local_version', $local_version);
612
613 /// Install various components
614 events_update_definition('local');
615 update_capabilities('local');
616 message_update_providers('local');
617
618 $endcallback('local', true);
619
620 } else if ($local_version > $CFG->local_version) { // upgrade!
621 $startcallback('local', false);
622
623 if (file_exists($CFG->dirroot.'/local/db/upgrade.php')) {
624 require_once($CFG->dirroot.'/local/db/upgrade.php');
625 xmldb_local_upgrade($CFG->local_version);
626 }
627 set_config('local_version', $local_version);
628
629 /// Upgrade various components
630 events_update_definition('local');
631 update_capabilities('local');
632 message_update_providers('local');
633
634 $endcallback('local', false);
635
636 } else if ($local_version < $CFG->local_version) {
637 throw new downgrade_exception('local', $CFG->local_version, $local_version);
db9d4a3d 638 }
639}
640
641
642////////////////////////////////////////////////
643/// upgrade logging functions
644////////////////////////////////////////////////
645
795a08ad 646function upgrade_handle_exception($ex, $plugin=null) {
647 global $CFG;
648
649 if ($ex instanceof moodle_exception) {
650 $details = get_string($ex->errorcode, $ex->module, $ex->a)."<br />debugging:".$ex->debuginfo;
651 } else {
652 $details = get_string('generalexceptionmessage', 'error', $ex->getMessage());
653 }
654 $info = "Exception: ".get_class($ex);
655 $backtrace = $ex->getTrace();
656 $place = array('file'=>$ex->getFile(), 'line'=>$ex->getLine(), 'exception'=>get_class($ex));
657 array_unshift($backtrace, $place);
658
659 /// first log upgrade error
660 upgrade_log(UPGRADE_LOG_ERROR, $plugin, $info, $details, $backtrace);
661
662 // always turn on debugging - admins need to know what is going on
663 $CFG->debug = DEBUG_DEVELOPER;
664
665 // now print the exception info as usually
666 if ($ex instanceof moodle_exception) {
667 _print_normal_error($ex->errorcode, $ex->module, $ex->a, $ex->link, $backtrace, $ex->debuginfo);
668 } else {
669 _print_normal_error('generalexceptionmessage', 'error', $ex->getMessage(), '', $backtrace);
670 }
671
672 die; // not reached
db9d4a3d 673}
674
675/**
676 * Adds log entry into upgrade_log table
677 *
678 * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR
679 * @param string $plugin plugin or null if main
680 * @param string $info short description text of log entry
681 * @param string $details long problem description
682 * @param string $backtrace string used for errors only
683 * @return void
684 */
685function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) {
686 global $DB, $USER, $CFG;
687
795a08ad 688 $plugin = ($plugin==='moodle') ? null : $plugin;
689
690 $backtrace = print_backtrace($backtrace, true);
db9d4a3d 691
692 $version = null;
693
694 //first try to find out current version number
795a08ad 695 if (empty($plugin) or $plugin === 'moodle') {
db9d4a3d 696 //main
697 $version = $CFG->version;
698
795a08ad 699 } else if ($plugin === 'local') {
700 //customisation
701 $version = $CFG->local_version;
702
703 } else if (strpos($plugin, 'mod/') === 0) {
db9d4a3d 704 try {
705 $modname = substr($plugin, strlen('mod/'));
706 $version = $DB->get_field('modules', 'version', array('name'=>$modname));
795a08ad 707 $version = ($version === false) ? null : $version;
db9d4a3d 708 } catch (Exception $ignored) {
709 }
710
795a08ad 711 } else if (strpos($plugin, 'block/') === 0) {
db9d4a3d 712 try {
795a08ad 713 $blockname = substr($plugin, strlen('block/'));
db9d4a3d 714 if ($block = $DB->get_record('block', array('name'=>$blockname))) {
715 $version = $block->version;
716 }
717 } catch (Exception $ignored) {
718 }
795a08ad 719
720 } else {
721 $pluginversion = get_config(str_replace('/', '_', $plugin), 'version');
722 if (!empty($pluginversion)) {
723 $version = $pluginversion;
724 }
db9d4a3d 725 }
726
727 $log = new object();
728 $log->type = $type;
729 $log->plugin = $plugin;
730 $log->version = $version;
731 $log->info = $info;
732 $log->details = $details;
733 $log->backtrace = $backtrace;
734 $log->userid = $USER->id;
735 $log->timemodified = time();
db9d4a3d 736 try {
737 $DB->insert_record('upgrade_log', $log);
738 } catch (Exception $ignored) {
795a08ad 739 // possible during install or 2.0 upgrade
db9d4a3d 740 }
741}
742
743/**
744 * Marks start of upgrade, blocks any other access to site.
745 * The upgrade is finished at the end of script or after timeout.
746 */
747function upgrade_started($preinstall=false) {
c13a5e71 748 global $CFG, $DB, $PAGE;
db9d4a3d 749
750 static $started = false;
751
752 if ($preinstall) {
753 ignore_user_abort(true);
754 upgrade_setup_debug(true);
755
756 } else if ($started) {
757 upgrade_set_timeout(120);
758
759 } else {
c13a5e71 760 if (!CLI_SCRIPT and !$PAGE->headerprinted) {
db9d4a3d 761 $strupgrade = get_string('upgradingversion', 'admin');
762
9ace5094 763 print_header($strupgrade.' - Moodle '.$CFG->target_release, $strupgrade,
db9d4a3d 764 build_navigation(array(array('name' => $strupgrade, 'link' => null, 'type' => 'misc'))), '',
765 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
766 }
767
768 ignore_user_abort(true);
769 register_shutdown_function('upgrade_finished_handler');
770 upgrade_setup_debug(true);
771 set_config('upgraderunning', time()+300);
772 $started = true;
773 }
774}
775
776/**
777 * Internal function - executed if upgrade interruped.
778 */
779function upgrade_finished_handler() {
780 upgrade_finished();
781}
782
783/**
784 * Indicates upgrade is finished.
785 *
786 * This function may be called repeatedly.
787 */
788function upgrade_finished($continueurl=null) {
789 global $CFG, $DB;
790
791 if (!empty($CFG->upgraderunning)) {
792 unset_config('upgraderunning');
793 upgrade_setup_debug(false);
794 ignore_user_abort(false);
795 if ($continueurl) {
796 print_continue($continueurl);
9ace5094 797 print_footer('upgrade');
db9d4a3d 798 die;
799 }
800 }
801}
802
803function upgrade_setup_debug($starting) {
804 global $CFG, $DB;
805
806 static $originaldebug = null;
807
808 if ($starting) {
809 if ($originaldebug === null) {
810 $originaldebug = $DB->get_debug();
811 }
812 if (!empty($CFG->upgradeshowsql)) {
813 $DB->set_debug(true);
814 }
815 } else {
816 $DB->set_debug($originaldebug);
817 }
818}
819
90509582 820function print_upgrade_reload($url) {
821 global $CFG;
822
823 echo "<br />";
824 echo '<div class="continuebutton">';
825 echo '<a href="'.$url.'" title="'.get_string('reload').'" ><img src="'.$CFG->pixpath.'/i/reload.gif" alt="" /> '.get_string('reload').'</a>';
826 echo '</div><br />';
827}
828
db9d4a3d 829function print_upgrade_separator() {
830 if (!CLI_SCRIPT) {
831 echo '<hr />';
832 }
833}
834
795a08ad 835/**
836 * Default start upgrade callback
837 * @param string $plugin
838 * @param bool $installation true if installation, false menas upgrade
839 */
840function print_upgrade_part_start($plugin, $installation) {
841 if (empty($plugin) or $plugin == 'moodle') {
842 upgrade_started($installation); // does not store upgrade running flag yet
843 print_heading(get_string('coresystem'));
844 } else {
845 upgrade_started();
846 print_heading($plugin);
847 }
848 if ($installation) {
849 if (empty($plugin) or $plugin == 'moodle') {
850 // no need to log - log table not yet there ;-)
851 } else {
852 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation');
853 }
854 } else {
855 if (empty($plugin) or $plugin == 'moodle') {
856 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade');
857 } else {
858 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade');
859 }
860 }
861}
862
863/**
864 * Default end upgrade callback
865 * @param string $plugin
866 * @param bool $installation true if installation, false menas upgrade
867 */
868function print_upgrade_part_end($plugin, $installation) {
869 upgrade_started();
870 if ($installation) {
871 if (empty($plugin) or $plugin == 'moodle') {
872 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed');
873 } else {
874 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed');
875 }
876 } else {
877 if (empty($plugin) or $plugin == 'moodle') {
878 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded');
879 } else {
880 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded');
881 }
882 }
883 notify(get_string('success'), 'notifysuccess');
884 print_upgrade_separator();
885}
db9d4a3d 886
887function upgrade_get_javascript() {
888 global $CFG;
2d6b0b04 889 return '<script type="text/javascript" src="'.$CFG->wwwroot.'/lib/scroll_to_page_end.js"></script>';
db9d4a3d 890}
891
892
893/**
894 * Try to upgrade the given language pack (or current language)
db9d4a3d 895 */
896function upgrade_language_pack($lang='') {
897 global $CFG;
898
899 if (empty($lang)) {
900 $lang = current_language();
901 }
902
903 if ($lang == 'en_utf8') {
904 return true; // Nothing to do
905 }
906
551fe0e5 907 upgrade_started(false);
908 print_heading(get_string('langimport', 'admin').': '.$lang);
db9d4a3d 909
910 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
911 @mkdir ($CFG->dataroot.'/lang/');
912
913 require_once($CFG->libdir.'/componentlib.class.php');
914
915 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
916 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
917
918 if ($status == COMPONENT_INSTALLED) {
db9d4a3d 919 @unlink($CFG->dataroot.'/cache/languages');
551fe0e5 920 if ($parentlang = get_parent_language($lang)) {
921 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $parentlang.'.zip', 'languages.md5', 'lang')) {
922 $cd->install();
923 }
924 }
925 notify(get_string('success'), 'notifysuccess');
db9d4a3d 926 }
927 }
928
551fe0e5 929 print_upgrade_separator();
db9d4a3d 930}