Skip to content

Commit

Permalink
MDL-49329 admin: Support plugins installation during upgrade
Browse files Browse the repository at this point in the history
The plugins check screen (displayed during core upgrade and/or plugins
upgrade) now supports installation of remote plugins. This includes
installation of missing dependencies (both single and bulk mode) and
installation of available updates (both single and bulk mode).

All the HTTP query parameters supported by admin/index.php are now
explicitly enlisted. Previously, the \core\update\deployer used
its own additional parameters (and was source of some serious problems
in the past).

The implementation uses the plugin manager as the controller and
provides an unified interface for installing any remote plugin or
plugins (be it available update or missing dependency).

As a side effect, we now validate available updates which was not
happening before.
  • Loading branch information
mudrd8mz committed Oct 9, 2015
1 parent c948b81 commit 531381f
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 37 deletions.
150 changes: 113 additions & 37 deletions admin/index.php
Expand Up @@ -98,18 +98,24 @@
require_once($CFG->libdir.'/adminlib.php'); // various admin-only functions
require_once($CFG->libdir.'/upgradelib.php'); // general upgrade/install related functions

$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL);
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL);
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL);
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL);
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW);
$upgradekeyhash = optional_param('upgradekeyhash', null, PARAM_ALPHANUM);
$installdep = optional_param('installdep', null, PARAM_COMPONENT);
$installdepx = optional_param('installdepx', false, PARAM_BOOL);
$abortinstall = optional_param('abortinstall', null, PARAM_COMPONENT);
$abortinstallx = optional_param('abortinstallx', null, PARAM_BOOL);
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL); // Core upgrade confirmed?
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL); // Core release info and server checks confirmed?
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL); // Plugins check page confirmed?
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL); // Show all plugins on the plugins check page?
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL); // GPL license confirmed for installation?
$fetchupdates = optional_param('fetchremote', 0, PARAM_BOOL); // Should check for available updates?
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW); // Plugin installation requested at moodle.org/plugins.
$upgradekeyhash = optional_param('upgradekeyhash', null, PARAM_ALPHANUM); // Hash of provided upgrade key.
$installdep = optional_param('installdep', null, PARAM_COMPONENT); // Install given missing dependency (required plugin).
$installdepx = optional_param('installdepx', false, PARAM_BOOL); // Install all missing dependencies.
$confirminstalldep = optional_param('confirminstalldep', false, PARAM_BOOL); // Installing dependencies confirmed.
$abortinstall = optional_param('abortinstall', null, PARAM_COMPONENT); // Cancel installation of the given new plugin.
$abortinstallx = optional_param('abortinstallx', null, PARAM_BOOL); // Cancel installation of all new plugins.
$confirmabortinstall = optional_param('confirmabortinstall', false, PARAM_BOOL); // Installation cancel confirmed.
$installupdate = optional_param('installupdate', null, PARAM_COMPONENT); // Install given available update.
$installupdateversion = optional_param('installupdateversion', null, PARAM_INT); // Version of the available update to install.
$installupdatex = optional_param('installupdatex', false, PARAM_BOOL); // Install all available plugin updates.
$confirminstallupdate = optional_param('confirminstallupdate', false, PARAM_BOOL); // Available update(s) install confirmed?
// Set up PAGE.
$url = new moodle_url('/admin/index.php');
Expand Down Expand Up @@ -337,8 +343,6 @@
die();

} else if (empty($confirmplugins)) {
// No sesskey support guaranteed here, because sessions might not work yet.

$strplugincheck = get_string('plugincheck');

$PAGE->navbar->add($strplugincheck);
Expand All @@ -349,36 +353,73 @@
$pluginman = core_plugin_manager::instance();

if ($abortinstallx) {
// No sesskey support guaranteed here, because sessions might not work yet.
$pluginman->cancel_all_plugin_installations();
redirect($PAGE->url);
}

if ($abortinstall) {
// No sesskey support guaranteed here, because sessions might not work yet.
$pluginman->cancel_plugin_installation($abortinstall);
redirect($PAGE->url);
}

// Install all available missing dependencies.
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,
get_string('dependencyinstallhead', 'core_plugin'),
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
);
}

// Install single available missing dependency.
if ($installdep) {
// No sesskey support guaranteed here, because sessions might not work yet.
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
if (!empty($installable[$installdep])) {
$installable = array($installable[$installdep]);
upgrade_install_remote_plugins($installable, $confirminstalldep,
get_string('dependencyinstallhead', 'core_plugin'),
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
);
}
}

// Install all avilable updates.
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,
get_string('updateavailableinstallallhead', 'core_admin'),
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
);
}

// Install single available update.
if ($installupdate and $installupdateversion) {
// 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,
get_string('updateavailableinstallallhead', 'core_admin'),
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
)
);
}
}

if ($fetchupdates) {
// No sesskey support guaranteed here, because sessions might not work yet.
$updateschecker = \core\update\checker::instance();
if ($updateschecker->enabled()) {
$updateschecker->fetch();
}
redirect($PAGE->url);
}

$deployer = \core\update\deployer::instance();
if ($deployer->enabled()) {
$deployer->initialize($PAGE->url, $PAGE->url);

$deploydata = $deployer->submitted_data();
if (!empty($deploydata)) {
// No sesskey support guaranteed here, because sessions might not work yet.
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
die();
}
}

echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
die();
Expand Down Expand Up @@ -417,9 +458,9 @@

if (!$PAGE->headerprinted) {
// means core upgrade or installation was not already done
$pluginman = core_plugin_manager::instance();

if (!$confirmplugins) {
$pluginman = core_plugin_manager::instance();
$strplugincheck = get_string('plugincheck');

$PAGE->navbar->add($strplugincheck);
Expand Down Expand Up @@ -448,21 +489,56 @@
redirect($PAGE->url);
}

/** @var core_admin_renderer $output */
$output = $PAGE->get_renderer('core', 'admin');
// Install all available missing dependencies.
if ($installdepx) {
require_sesskey();
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
upgrade_install_remote_plugins($installable, $confirminstalldep,
get_string('dependencyinstallhead', 'core_plugin'),
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
);
}

// Install single available missing dependency.
if ($installdep) {
require_sesskey();
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
if (!empty($installable[$installdep])) {
$installable = array($installable[$installdep]);
upgrade_install_remote_plugins($installable, $confirminstalldep,
get_string('dependencyinstallhead', 'core_plugin'),
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
);
}
}

$deployer = \core\update\deployer::instance();
if ($deployer->enabled()) {
$deployer->initialize($PAGE->url, $PAGE->url);
// Install all available updates.
if ($installupdatex) {
require_sesskey();
$installable = $pluginman->filter_installable($pluginman->available_updates());
upgrade_install_remote_plugins($installable, $confirminstallupdate,
get_string('updateavailableinstallallhead', 'core_admin'),
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
);
}

$deploydata = $deployer->submitted_data();
if (!empty($deploydata)) {
require_sesskey();
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
die();
// Install single available update.
if ($installupdate and $installupdateversion) {
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,
get_string('updateavailableinstallallhead', 'core_admin'),
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
)
);
}
}

/** @var core_admin_renderer $output */
$output = $PAGE->get_renderer('core', 'admin');

// Show plugins info.
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
$version, $showallplugins,
Expand Down
1 change: 1 addition & 0 deletions lang/en/plugin.php
Expand Up @@ -35,6 +35,7 @@
$string['dependencyavailable'] = 'Available';
$string['dependencyfails'] = 'Fails';
$string['dependencyinstall'] = 'Install';
$string['dependencyinstallhead'] = 'Installing missing dependencies';
$string['dependencyinstallmissing'] = 'Install missing dependencies ({$a})';
$string['dependencymissing'] = 'Missing';
$string['dependencyunavailable'] = 'Unavailable';
Expand Down
50 changes: 50 additions & 0 deletions lib/upgradelib.php
Expand Up @@ -2371,3 +2371,53 @@ function check_upgrade_key($upgradekeyhash) {
}
}
}

/**
* Helper procedure/macro for installing remote plugins at admin/index.php
*
* Does not return, always redirects or exits.
*
* @param array $installable list of \core\update\remote_info
* @param bool $confirmed false: display the validation screen, true: proceed installation
* @param string $heading validation screen heading
* @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 successful finish or cancel)
*/
function upgrade_install_remote_plugins(array $installable, $confirmed, $heading='', $continue=null, $return=null) {
global $PAGE;

if (empty($return)) {
$return = $PAGE->url;
}

if (empty($installable)) {
redirect($return);
}

$pluginman = core_plugin_manager::instance();

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);
}
redirect($return);

} else {
$output = $PAGE->get_renderer('core', 'admin');
echo $output->header();
if ($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);
echo html_writer::end_tag('pre');
if ($validated) {
echo $output->install_remote_plugins_buttons($continue, null, $return);
} else {
echo $output->install_remote_plugins_buttons(null, null, $return);
}
echo $output->footer();
die();
}
}

0 comments on commit 531381f

Please sign in to comment.