You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
8.9 KiB
290 lines
8.9 KiB
2 years ago
|
<?php
|
||
|
|
||
|
// This file is part of Moodle - http://moodle.org/
|
||
|
//
|
||
|
// Moodle is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// Moodle is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
/**
|
||
|
* Provides base converter classes
|
||
|
*
|
||
|
* @package core
|
||
|
* @subpackage backup-convert
|
||
|
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||
|
*/
|
||
|
|
||
|
defined('MOODLE_INTERNAL') || die();
|
||
|
|
||
|
require_once($CFG->dirroot . '/backup/util/includes/convert_includes.php');
|
||
|
|
||
|
/**
|
||
|
* Base converter class
|
||
|
*
|
||
|
* All Moodle backup converters are supposed to extend this base class.
|
||
|
*
|
||
|
* @throws convert_exception
|
||
|
*/
|
||
|
abstract class base_converter implements loggable {
|
||
|
|
||
|
/** @var string unique identifier of this converter instance */
|
||
|
protected $id;
|
||
|
|
||
|
/** @var string the name of the directory containing the unpacked backup being converted */
|
||
|
protected $tempdir;
|
||
|
|
||
|
/** @var string the name of the directory where the backup is converted to */
|
||
|
protected $workdir;
|
||
|
|
||
|
/** @var null|base_logger logger to use during the conversion */
|
||
|
protected $logger = null;
|
||
|
|
||
|
/**
|
||
|
* Constructor
|
||
|
*
|
||
|
* @param string $tempdir the relative path to the directory containing the unpacked backup to convert
|
||
|
* @param null|base_logger logger to use during the conversion
|
||
|
*/
|
||
|
public function __construct($tempdir, $logger = null) {
|
||
|
|
||
|
$this->tempdir = $tempdir;
|
||
|
$this->id = convert_helper::generate_id($tempdir);
|
||
|
$this->workdir = $tempdir . '_' . $this->get_name() . '_' . $this->id;
|
||
|
$this->set_logger($logger);
|
||
|
$this->log('instantiating '.$this->get_name().' converter '.$this->get_id(), backup::LOG_DEBUG);
|
||
|
$this->log('conversion source directory', backup::LOG_DEBUG, $this->tempdir);
|
||
|
$this->log('conversion target directory', backup::LOG_DEBUG, $this->workdir);
|
||
|
$this->init();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the logger to use during the conversion
|
||
|
*
|
||
|
* @param null|base_logger $logger
|
||
|
*/
|
||
|
public function set_logger($logger) {
|
||
|
if (is_null($logger) or ($logger instanceof base_logger)) {
|
||
|
$this->logger = $logger;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If the logger was set for the converter, log the message
|
||
|
*
|
||
|
* If the $display is enabled, the spaces in the $message text are removed
|
||
|
* and the text is used as a string identifier in the core_backup language file.
|
||
|
*
|
||
|
* @see backup_helper::log()
|
||
|
* @param string $message message text
|
||
|
* @param int $level message level {@example backup::LOG_WARNING}
|
||
|
* @param null|mixed $a additional information
|
||
|
* @param null|int $depth the message depth
|
||
|
* @param bool $display whether the message should be sent to the output, too
|
||
|
*/
|
||
|
public function log($message, $level, $a = null, $depth = null, $display = false) {
|
||
|
if ($this->logger instanceof base_logger) {
|
||
|
backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get instance identifier
|
||
|
*
|
||
|
* @return string the unique identifier of this converter instance
|
||
|
*/
|
||
|
public function get_id() {
|
||
|
return $this->id;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get converter name
|
||
|
*
|
||
|
* @return string the system name of the converter
|
||
|
*/
|
||
|
public function get_name() {
|
||
|
$parts = explode('_', get_class($this));
|
||
|
return array_shift($parts);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts the backup directory
|
||
|
*/
|
||
|
public function convert() {
|
||
|
|
||
|
try {
|
||
|
$this->log('creating the target directory', backup::LOG_DEBUG);
|
||
|
$this->create_workdir();
|
||
|
|
||
|
$this->log('executing the conversion', backup::LOG_DEBUG);
|
||
|
$this->execute();
|
||
|
|
||
|
$this->log('replacing the source directory with the converted version', backup::LOG_DEBUG);
|
||
|
$this->replace_tempdir();
|
||
|
} catch (Exception $e) {
|
||
|
}
|
||
|
|
||
|
// clean-up stuff if needed
|
||
|
$this->destroy();
|
||
|
|
||
|
// eventually re-throw the execution exception
|
||
|
if (isset($e) and ($e instanceof Exception)) {
|
||
|
throw $e;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return string the full path to the working directory
|
||
|
*/
|
||
|
public function get_workdir_path() {
|
||
|
global $CFG;
|
||
|
|
||
|
return make_backup_temp_directory($this->workdir);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return string the full path to the directory with the source backup
|
||
|
*/
|
||
|
public function get_tempdir_path() {
|
||
|
global $CFG;
|
||
|
|
||
|
return make_backup_temp_directory($this->tempdir);
|
||
|
}
|
||
|
|
||
|
/// public static methods //////////////////////////////////////////////////
|
||
|
|
||
|
/**
|
||
|
* Makes sure that this converter is available at this site
|
||
|
*
|
||
|
* This is intended for eventual PHP extensions check, environment check etc.
|
||
|
* All checks that do not depend on actual backup data should be done here.
|
||
|
*
|
||
|
* @return boolean true if this converter should be considered as available
|
||
|
*/
|
||
|
public static function is_available() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Detects the format of the backup directory
|
||
|
*
|
||
|
* Moodle 2.x format is being detected by the core itself. The converters are
|
||
|
* therefore supposed to detect the source format. Eventually, if the target
|
||
|
* format os not {@link backup::FORMAT_MOODLE} then they should be able to
|
||
|
* detect both source and target formats.
|
||
|
*
|
||
|
* @param string $tempdir the name of the backup directory
|
||
|
* @return null|string null if not recognized, backup::FORMAT_xxx otherwise
|
||
|
*/
|
||
|
public static function detect_format($tempdir) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the basic information about the converter
|
||
|
*
|
||
|
* The returned array must contain the following keys:
|
||
|
* 'from' - the supported source format, eg. backup::FORMAT_MOODLE1
|
||
|
* 'to' - the supported target format, eg. backup::FORMAT_MOODLE
|
||
|
* 'cost' - the cost of the conversion, non-negative non-zero integer
|
||
|
*/
|
||
|
public static function description() {
|
||
|
|
||
|
return array(
|
||
|
'from' => null,
|
||
|
'to' => null,
|
||
|
'cost' => null,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// end of public API //////////////////////////////////////////////////////
|
||
|
|
||
|
/**
|
||
|
* Initialize the instance if needed, called by the constructor
|
||
|
*/
|
||
|
protected function init() {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts the contents of the tempdir into the target format in the workdir
|
||
|
*/
|
||
|
protected abstract function execute();
|
||
|
|
||
|
/**
|
||
|
* Prepares a new empty working directory
|
||
|
*/
|
||
|
protected function create_workdir() {
|
||
|
|
||
|
fulldelete($this->get_workdir_path());
|
||
|
if (!check_dir_exists($this->get_workdir_path())) {
|
||
|
throw new convert_exception('failed_create_workdir');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replaces the source backup directory with the converted version
|
||
|
*
|
||
|
* If $CFG->keeptempdirectoriesonbackup is defined, the original source
|
||
|
* source backup directory is kept for debugging purposes.
|
||
|
*/
|
||
|
protected function replace_tempdir() {
|
||
|
global $CFG;
|
||
|
|
||
|
$tempdir = $this->get_tempdir_path();
|
||
|
|
||
|
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||
|
fulldelete($tempdir);
|
||
|
} else {
|
||
|
if (!rename($tempdir, $tempdir . '_' . $this->get_name() . '_' . $this->id . '_source')) {
|
||
|
throw new convert_exception('failed_rename_source_tempdir');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!rename($this->get_workdir_path(), $tempdir)) {
|
||
|
throw new convert_exception('failed_move_converted_into_place');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Cleans up stuff after the execution
|
||
|
*
|
||
|
* Note that we do not know if the execution was successful or not.
|
||
|
* An exception might have been thrown.
|
||
|
*/
|
||
|
protected function destroy() {
|
||
|
global $CFG;
|
||
|
|
||
|
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||
|
fulldelete($this->get_workdir_path());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* General convert-related exception
|
||
|
*
|
||
|
* @author David Mudrak <david@moodle.com>
|
||
|
*/
|
||
|
class convert_exception extends moodle_exception {
|
||
|
|
||
|
/**
|
||
|
* Constructor
|
||
|
*
|
||
|
* @param string $errorcode key for the corresponding error string
|
||
|
* @param object $a extra words and phrases that might be required in the error string
|
||
|
* @param string $debuginfo optional debugging information
|
||
|
*/
|
||
|
public function __construct($errorcode, $a = null, $debuginfo = null) {
|
||
|
parent::__construct($errorcode, '', '', $a, $debuginfo);
|
||
|
}
|
||
|
}
|