MDL-49329 admin: Make plugin manager able to install from local zips too
The plugin manager's method install_remote_plugins() has been changed to install_plugins() and it is now able to install plugins from the provided list of locally available ZIP files, too. This is used by the Install plugins admin tool.
This commit is contained in:
+8
-8
@@ -368,7 +368,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
if ($installdepx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_remote_plugins($installable, $confirminstalldep,
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
@@ -380,7 +380,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_remote_plugins($installable, $confirminstalldep,
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
@@ -391,7 +391,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
if ($installupdatex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
@@ -402,7 +402,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
@@ -493,7 +493,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
if ($installdepx) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_remote_plugins($installable, $confirminstalldep,
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
@@ -505,7 +505,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_remote_plugins($installable, $confirminstalldep,
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
@@ -516,7 +516,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
if ($installupdatex) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
@@ -527,7 +527,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
require_sesskey();
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
|
||||
+2
-2
@@ -183,7 +183,7 @@ if ($installupdatex) {
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
@@ -201,7 +201,7 @@ if ($installupdate and $installupdateversion) {
|
||||
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_remote_plugins($installable, $confirminstallupdate,
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
|
||||
+1
-1
@@ -1033,7 +1033,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @param moodle_url $cancel URL for the cancel link, defaults to the current page
|
||||
* @return string HTML
|
||||
*/
|
||||
public function install_remote_plugins_buttons(moodle_url $continue=null, $label=null, moodle_url $cancel=null) {
|
||||
public function install_plugins_buttons(moodle_url $continue=null, $label=null, moodle_url $cancel=null) {
|
||||
|
||||
$out = html_writer::start_div('install-remote-plugins-buttons');
|
||||
|
||||
|
||||
+3
-3
@@ -68,9 +68,9 @@ $string['overviewall'] = 'All plugins';
|
||||
$string['overviewext'] = 'Additional plugins';
|
||||
$string['overviewupdatable'] = 'Available updates';
|
||||
$string['packagesdebug'] = 'Debugging output enabled';
|
||||
$string['packagesdownloading'] = 'Downloading packages';
|
||||
$string['packagesextracting'] = 'Extracting packages';
|
||||
$string['packagesvalidating'] = 'Validating packages';
|
||||
$string['packagesdownloading'] = 'Downloading {$a}';
|
||||
$string['packagesextracting'] = 'Extracting {$a}';
|
||||
$string['packagesvalidating'] = 'Validating {$a}';
|
||||
$string['packagesvalidatingfailed'] = 'Installation aborted due to validation failure';
|
||||
$string['packagesvalidatingok'] = 'Validation successful, installation can continue';
|
||||
$string['plugincheckall'] = 'All plugins';
|
||||
|
||||
@@ -1092,6 +1092,20 @@ class core_plugin_manager {
|
||||
return $this->get_code_manager()->unzip_plugin_file($zipfilepath, $targetdir, $rootdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the plugin's name from its ZIP file.
|
||||
*
|
||||
* Plugin ZIP packages are expected to contain a single directory and the
|
||||
* directory name would become the plugin name once extracted to the Moodle
|
||||
* dirroot.
|
||||
*
|
||||
* @param string $zipfilepath full path to the ZIP files
|
||||
* @return string|bool false on error
|
||||
*/
|
||||
public function get_plugin_zip_root_dir($zipfilepath) {
|
||||
return $this->get_code_manager()->get_plugin_zip_root_dir($zipfilepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of missing dependencies.
|
||||
*
|
||||
@@ -1199,18 +1213,26 @@ class core_plugin_manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the installation of plugins available in the plugins directory.
|
||||
* Perform the installation of plugins.
|
||||
*
|
||||
* The list of plugins is supposed to be processed by
|
||||
* {@link self::filter_installable()} to make sure all the plugins are
|
||||
* valid.
|
||||
* If used for installation of remote plugins from the Moodle Plugins
|
||||
* directory, the $plugins must be list of {@link \core\update\remote_info}
|
||||
* object that represent installable remote plugins. The caller can use
|
||||
* {@link self::filter_installable()} to prepare the list.
|
||||
*
|
||||
* @param array $plugins list of installable remote plugins
|
||||
* If used for installation of plugins from locally available ZIP files,
|
||||
* the $plugins should be list of objects with properties ->component and
|
||||
* ->zipfilepath.
|
||||
*
|
||||
* The method uses {@link mtrace()} to produce direct output and can be
|
||||
* used in both web and cli interfaces.
|
||||
*
|
||||
* @param array $plugins list of plugins
|
||||
* @param bool $confirmed should the files be really deployed into the dirroot?
|
||||
* @param bool $silent perform without output
|
||||
* @return bool true on success
|
||||
*/
|
||||
public function install_remote_plugins(array $plugins, $confirmed, $silent) {
|
||||
public function install_plugins(array $plugins, $confirmed, $silent) {
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
if (empty($plugins)) {
|
||||
@@ -1223,24 +1245,32 @@ class core_plugin_manager {
|
||||
$silent or $this->mtrace(get_string('packagesdebug', 'core_plugin'), PHP_EOL, DEBUG_NORMAL);
|
||||
|
||||
// Download all ZIP packages if we do not have them yet.
|
||||
$silent or $this->mtrace(get_string('packagesdownloading', 'core_plugin'), ' ... ');
|
||||
$zips = array();
|
||||
foreach ($plugins as $plugin) {
|
||||
$zips[$plugin->component] = $this->get_remote_plugin_zip($plugin->version->downloadurl, $plugin->version->downloadmd5);
|
||||
$silent or $this->mtrace(PHP_EOL.$plugin->version->downloadurl, '', DEBUG_DEVELOPER);
|
||||
$silent or $this->mtrace(PHP_EOL.' -> '.$zips[$plugin->component], ' ... ', DEBUG_DEVELOPER);
|
||||
if (!$zips[$plugin->component]) {
|
||||
$silent or $this->mtrace(get_string('error'));
|
||||
return false;
|
||||
if ($plugin instanceof \core\update\remote_info) {
|
||||
$zips[$plugin->component] = $this->get_remote_plugin_zip($plugin->version->downloadurl,
|
||||
$plugin->version->downloadmd5);
|
||||
$silent or $this->mtrace(get_string('packagesdownloading', 'core_plugin', $plugin->component), ' ... ');
|
||||
$silent or $this->mtrace(PHP_EOL.' <- '.$plugin->version->downloadurl, '', DEBUG_DEVELOPER);
|
||||
$silent or $this->mtrace(PHP_EOL.' -> '.$zips[$plugin->component], ' ... ', DEBUG_DEVELOPER);
|
||||
if (!$zips[$plugin->component]) {
|
||||
$silent or $this->mtrace(get_string('error'));
|
||||
return false;
|
||||
}
|
||||
$silent or $this->mtrace($ok);
|
||||
} else {
|
||||
if (empty($plugin->zipfilepath)) {
|
||||
throw new coding_exception('Unexpected data structure provided');
|
||||
}
|
||||
$zips[$plugin->component] = $plugin->zipfilepath;
|
||||
$silent or $this->mtrace('ZIP '.$plugin->zipfilepath, PHP_EOL, DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
$silent or $this->mtrace($ok);
|
||||
|
||||
// Validate all downloaded packages.
|
||||
$silent or $this->mtrace(get_string('packagesvalidating', 'core_plugin'), ' ... '.PHP_EOL);
|
||||
foreach ($plugins as $plugin) {
|
||||
$zipfile = $zips[$plugin->component];
|
||||
$silent or $this->mtrace('* '.s($plugin->name). ' ('.$plugin->component.')', ' ... ');
|
||||
$silent or $this->mtrace(get_string('packagesvalidating', 'core_plugin', $plugin->component), ' ... ');
|
||||
list($plugintype, $pluginname) = core_component::normalize_component($plugin->component);
|
||||
$tmp = make_request_directory();
|
||||
$zipcontents = $this->unzip_plugin_file($zipfile, $tmp, $pluginname);
|
||||
@@ -1305,9 +1335,8 @@ class core_plugin_manager {
|
||||
}
|
||||
|
||||
// Extract all ZIP packs do the dirroot.
|
||||
$silent or $this->mtrace(get_string('packagesextracting', 'core_plugin'), ' ... '.PHP_EOL);
|
||||
foreach ($plugins as $plugin) {
|
||||
$silent or $this->mtrace('* '.s($plugin->name). ' ('.$plugin->component.')', ' ... ');
|
||||
$silent or $this->mtrace(get_string('packagesextracting', 'core_plugin', $plugin->component), ' ... ');
|
||||
$zipfile = $zips[$plugin->component];
|
||||
list($plugintype, $pluginname) = core_component::normalize_component($plugin->component);
|
||||
$target = $this->get_plugintype_root($plugintype);
|
||||
|
||||
@@ -220,6 +220,46 @@ class code_manager {
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the plugin's name from its ZIP file.
|
||||
*
|
||||
* Plugin ZIP packages are expected to contain a single directory and the
|
||||
* directory name would become the plugin name once extracted to the Moodle
|
||||
* dirroot.
|
||||
*
|
||||
* @param string $zipfilepath full path to the ZIP files
|
||||
* @return string|bool false on error
|
||||
*/
|
||||
public function get_plugin_zip_root_dir($zipfilepath) {
|
||||
|
||||
$fp = get_file_packer('application/zip');
|
||||
$files = $fp->list_files($zipfilepath);
|
||||
|
||||
if (empty($files)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rootdirname = null;
|
||||
foreach ($files as $file) {
|
||||
$pathnameitems = explode('/', $file->pathname);
|
||||
if (empty($pathnameitems)) {
|
||||
return false;
|
||||
}
|
||||
// Set the expected name of the root directory in the first
|
||||
// iteration of the loop.
|
||||
if ($rootdirname === null) {
|
||||
$rootdirname = $pathnameitems[0];
|
||||
}
|
||||
// Require the same root directory for all files in the ZIP
|
||||
// package.
|
||||
if ($rootdirname !== $pathnameitems[0]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $rootdirname;
|
||||
}
|
||||
|
||||
// This is the end, my only friend, the end ... of external public API.
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,4 +159,15 @@ class core_update_code_manager_testcase extends advanced_testcase {
|
||||
$zipfilepath = __DIR__.'/fixtures/update_validator/zips/bar.zip';
|
||||
$files = $codeman->unzip_plugin_file($zipfilepath, $targetdir, 'bar');
|
||||
}
|
||||
|
||||
public function test_get_plugin_zip_root_dir() {
|
||||
$codeman = new \core\update\testable_code_manager();
|
||||
|
||||
$zipfilepath = __DIR__.'/fixtures/update_validator/zips/invalidroot.zip';
|
||||
$this->assertEquals('invalid-root', $codeman->get_plugin_zip_root_dir($zipfilepath));
|
||||
|
||||
$zipfilepath = __DIR__.'/fixtures/update_validator/zips/bar.zip';
|
||||
$this->assertEquals('bar', $codeman->get_plugin_zip_root_dir($zipfilepath));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -2383,7 +2383,7 @@ function check_upgrade_key($upgradekeyhash) {
|
||||
* @param moodle_url|string|null $continue URL to proceed with installation at the validation screen
|
||||
* @param moodle_url|string|null $return URL to go back on cancelling at the validation screen
|
||||
*/
|
||||
function upgrade_install_remote_plugins(array $installable, $confirmed, $heading='', $continue=null, $return=null) {
|
||||
function upgrade_install_plugins(array $installable, $confirmed, $heading='', $continue=null, $return=null) {
|
||||
global $PAGE;
|
||||
|
||||
if (empty($return)) {
|
||||
@@ -2398,8 +2398,8 @@ function upgrade_install_remote_plugins(array $installable, $confirmed, $heading
|
||||
|
||||
if ($confirmed) {
|
||||
// Installation confirmed at the validation results page.
|
||||
if (!$pluginman->install_remote_plugins($installable, true, true)) {
|
||||
throw new moodle_exception('install_remote_plugins_failed', 'core_plugin', $return);
|
||||
if (!$pluginman->install_plugins($installable, true, true)) {
|
||||
throw new moodle_exception('install_plugins_failed', 'core_plugin', $return);
|
||||
}
|
||||
// Always redirect to admin/index.php to perform the database upgrade.
|
||||
redirect(new moodle_url('/admin/index.php?cache=0'));
|
||||
@@ -2411,12 +2411,12 @@ function upgrade_install_remote_plugins(array $installable, $confirmed, $heading
|
||||
echo $output->heading($heading, 3);
|
||||
}
|
||||
echo html_writer::start_tag('pre', array('class' => 'plugin-install-console'));
|
||||
$validated = $pluginman->install_remote_plugins($installable, false, false);
|
||||
$validated = $pluginman->install_plugins($installable, false, false);
|
||||
echo html_writer::end_tag('pre');
|
||||
if ($validated) {
|
||||
echo $output->install_remote_plugins_buttons($continue, null, $return);
|
||||
echo $output->install_plugins_buttons($continue, null, $return);
|
||||
} else {
|
||||
echo $output->install_remote_plugins_buttons(null, null, $return);
|
||||
echo $output->install_plugins_buttons(null, null, $return);
|
||||
}
|
||||
echo $output->footer();
|
||||
die();
|
||||
|
||||
Reference in New Issue
Block a user