/** * Perform the installation of plugins. * * 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. * * 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_plugins(array $plugins, $confirmed, $silent) { global $CFG, $OUTPUT; if (!empty($CFG->disableupdateautodeploy)) { return false; } if (empty($plugins)) { return false; } $ok = get_string('ok', 'core'); // Let admins know they can expect more verbose output. $silent or $this->mtrace(get_string('packagesdebug', 'core_plugin'), PHP_EOL, DEBUG_NORMAL); // Download all ZIP packages if we do not have them yet. $zips = array(); foreach ($plugins as $plugin) { 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); } } // Validate all downloaded packages. foreach ($plugins as $plugin) { $zipfile = $zips[$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); if (empty($zipcontents)) { $silent or $this->mtrace(get_string('error')); $silent or $this->mtrace('Unable to unzip ' . $zipfile, PHP_EOL, DEBUG_DEVELOPER); return false; } $validator = \core\update\validator::instance($tmp, $zipcontents); $validator->assert_plugin_type($plugintype); $validator->assert_moodle_version($CFG->version); // TODO Check for missing dependencies during validation. $result = $validator->execute(); if (!$silent) { $result ? $this->mtrace($ok) : $this->mtrace(get_string('error')); foreach ($validator->get_messages() as $message) { if ($message->level === $validator::INFO) { // Display [OK] validation messages only if debugging mode is DEBUG_NORMAL. $level = DEBUG_NORMAL; } else { if ($message->level === $validator::DEBUG) { // Display [Debug] validation messages only if debugging mode is DEBUG_ALL. $level = DEBUG_ALL; } else { // Display [Warning] and [Error] always. $level = null; } } if ($message->level === $validator::WARNING and !CLI_SCRIPT) { $this->mtrace(' <strong>[' . $validator->message_level_name($message->level) . ']</strong>', ' ', $level); } else { $this->mtrace(' [' . $validator->message_level_name($message->level) . ']', ' ', $level); } $this->mtrace($validator->message_code_name($message->msgcode), ' ', $level); $info = $validator->message_code_info($message->msgcode, $message->addinfo); if ($info) { $this->mtrace('[' . s($info) . ']', ' ', $level); } else { if (is_string($message->addinfo)) { $this->mtrace('[' . s($message->addinfo, true) . ']', ' ', $level); } else { $this->mtrace('[' . s(json_encode($message->addinfo, true)) . ']', ' ', $level); } } if ($icon = $validator->message_help_icon($message->msgcode)) { if (CLI_SCRIPT) { $this->mtrace(PHP_EOL . ' ^^^ ' . get_string('help') . ': ' . get_string($icon->identifier . '_help', $icon->component), '', $level); } else { $this->mtrace($OUTPUT->render($icon), ' ', $level); } } $this->mtrace(PHP_EOL, '', $level); } } if (!$result) { $silent or $this->mtrace(get_string('packagesvalidatingfailed', 'core_plugin')); return false; } } $silent or $this->mtrace(PHP_EOL . get_string('packagesvalidatingok', 'core_plugin')); if (!$confirmed) { return true; } // Extract all ZIP packs do the dirroot. foreach ($plugins as $plugin) { $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); if (file_exists($target . '/' . $pluginname)) { $this->remove_plugin_folder($this->get_plugin_info($plugin->component)); } if (!$this->unzip_plugin_file($zipfile, $target, $pluginname)) { $silent or $this->mtrace(get_string('error')); $silent or $this->mtrace('Unable to unzip ' . $zipfile, PHP_EOL, DEBUG_DEVELOPER); if (function_exists('opcache_reset')) { opcache_reset(); } return false; } $silent or $this->mtrace($ok); } if (function_exists('opcache_reset')) { opcache_reset(); } return true; }
public function testable_parse_version_php($fullpath) { return parent::parse_version_php($fullpath); }