site-accueil-insa/matomo/plugins/CoreUpdater/Commands/Update.php

395 lines
13 KiB
PHP

<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\CoreUpdater\Commands;
use Piwik\Filechecks;
use Piwik\SettingsServer;
use Piwik\Version;
use Piwik\Config;
use Piwik\DbHelper;
use Piwik\Filesystem;
use Piwik\Piwik;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Plugins\CoreUpdater\Commands\Update\CliUpdateObserver;
use Piwik\Plugins\CoreUpdater\NoUpdatesFoundException;
use Piwik\Updater;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* @package CoreUpdater
*/
class Update extends ConsoleCommand
{
/**
* @var string[]
*/
private $migrationQueries;
protected function configure()
{
$this->setName('core:update');
$this->setDescription(Piwik::translate('CoreUpdater_ConsoleCommandDescription'));
$this->addOption('yes', null, InputOption::VALUE_NONE, Piwik::translate('CoreUpdater_ConsoleParameterDescription'));
$this->addOption('skip-cache-clear', null, InputOption::VALUE_NONE, Piwik::translate('CoreUpdater_SkipCacheClearDesc'));
}
/**
* Execute command like: ./console core:update --yes
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$skipCacheClear = $input->getOption('skip-cache-clear');
try {
if ($skipCacheClear) {
$output->writeln(Piwik::translate('CoreUpdater_SkipCacheClear'));
Filesystem::$skipCacheClearOnUpdate = true;
}
$this->executeClearCaches();
$yes = $input->getOption('yes');
try {
$this->makeUpdate($input, $output, true);
if (!$yes) {
$yes = $this->askForUpdateConfirmation($input, $output);
}
if ($yes) {
$output->writeln("\n" . Piwik::translate('CoreUpdater_ConsoleStartingDbUpgrade'));
$this->makeUpdate($input, $output, false);
$this->writeSuccessMessage($output, array(Piwik::translate('CoreUpdater_PiwikHasBeenSuccessfullyUpgraded')));
} else {
$this->writeSuccessMessage($output, array(Piwik::translate('CoreUpdater_DbUpgradeNotExecuted')));
}
$this->writeAlertMessageWhenCommandExecutedWithUnexpectedUser($output);
} catch (NoUpdatesFoundException $e) {
// Do not fail if no updates were found
$this->writeSuccessMessage($output, array($e->getMessage()));
}
} finally {
Filesystem::$skipCacheClearOnUpdate = false;
}
}
private function askForUpdateConfirmation(InputInterface $input, OutputInterface $output)
{
$helper = $this->getHelper('question');
$question = new ConfirmationQuestion('<comment>'.Piwik::translate('CoreUpdater_ExecuteDbUpgrade').' (y/N) </comment>', false);
return $helper->ask($input, $output, $question);
}
protected function executeClearCaches()
{
Filesystem::deleteAllCacheOnUpdate();
}
protected function makeUpdate(InputInterface $input, OutputInterface $output, $doDryRun)
{
$this->checkAllRequiredOptionsAreNotEmpty($input);
$updater = $this->makeUpdaterInstance($output);
$componentsWithUpdateFile = $updater->getComponentUpdates();
if (empty($componentsWithUpdateFile)) {
throw new NoUpdatesFoundException(Piwik::translate('CoreUpdater_AlreadyUpToDate'));
}
$output->writeln(array(
"",
" *** " . Piwik::translate('CoreUpdater_UpdateTitle') . " ***"
));
// handle case of existing database with no tables
if (!DbHelper::isInstalled()) {
$this->handleCoreError($output, Piwik::translate('CoreUpdater_EmptyDatabaseError', Config::getInstance()->database['dbname']));
return;
}
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_DatabaseUpgradeRequired'),
"",
" " . Piwik::translate('CoreUpdater_YourDatabaseIsOutOfDate')
));
if ($this->isUpdatingCore($componentsWithUpdateFile)) {
$currentVersion = $this->getCurrentVersionForCore($updater);
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_PiwikWillBeUpgradedFromVersionXToVersionY', array($currentVersion, Version::VERSION))
));
}
$pluginsToUpdate = $this->getPluginsToUpdate($componentsWithUpdateFile);
if (!empty($pluginsToUpdate)) {
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_TheFollowingPluginsWillBeUpgradedX', implode(', ', $pluginsToUpdate))
));
}
$dimensionsToUpdate = $this->getDimensionsToUpdate($componentsWithUpdateFile);
if (!empty($dimensionsToUpdate)) {
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_TheFollowingDimensionsWillBeUpgradedX', implode(', ', $dimensionsToUpdate))
));
}
$output->writeln("");
if ($doDryRun) {
$this->doDryRun($updater, $output);
} else {
$this->doRealUpdate($updater, $componentsWithUpdateFile, $output);
}
}
private function doDryRun(Updater $updater, OutputInterface $output)
{
$migrationQueries = $this->getMigrationQueriesToExecute($updater);
if(empty($migrationQueries)) {
$output->writeln(array(" *** ".Piwik::translate('CoreUpdater_ConsoleUpdateNoSqlQueries')." ***", ""));
return;
}
if ($updater->hasMajorDbUpdate()) {
$output->writeln(array(
"",
sprintf("<comment>%s \n</comment>", Piwik::translate('CoreUpdater_MajorUpdateWarning1'))
));
}
$output->writeln(array(" *** ".Piwik::translate('CoreUpdater_DryRun')." ***", ""));
foreach ($migrationQueries as $query) {
$result = $query->__toString();
if (!empty($result)) {
$output->writeln(" " . $result);
}
}
$output->writeln(array("", " *** " . Piwik::translate('CoreUpdater_DryRunEnd') . " ***", ""));
}
private function doRealUpdate(Updater $updater, $componentsWithUpdateFile, OutputInterface $output)
{
$output->writeln(array(" " . Piwik::translate('CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient'), ""));
$updaterResult = $updater->updateComponents($componentsWithUpdateFile);
if (@$updaterResult['coreError']) {
$this->handleCoreError($output, $updaterResult['errors'], $includeDiyHelp = true);
return;
}
if (!empty($updaterResult['warnings'])) {
$this->outputUpdaterWarnings($output, $updaterResult['warnings']);
}
if (!empty($updaterResult['errors'])) {
$this->outputUpdaterErrors($output, $updaterResult['errors'], $updaterResult['deactivatedPlugins']);
}
if (!empty($updaterResult['warnings'])
|| !empty($updaterResult['errors'])
) {
$output->writeln(array(
" " . Piwik::translate('CoreUpdater_HelpMessageIntroductionWhenWarning'),
"",
" * " . $this->getUpdateHelpMessage()
));
}
}
private function handleCoreError(OutputInterface $output, $errors, $includeDiyHelp = false)
{
if (!is_array($errors)) {
$errors = array($errors);
}
$output->writeln(array(
"",
" [X] " . Piwik::translate('CoreUpdater_CriticalErrorDuringTheUpgradeProcess'),
"",
));
foreach ($errors as $errorMessage) {
$errorMessage = trim($errorMessage);
$errorMessage = str_replace("\n", "\n ", $errorMessage);
$output->writeln(" * $errorMessage");
}
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_HelpMessageIntroductionWhenError'),
"",
" * " . $this->getUpdateHelpMessage()
));
if ($includeDiyHelp) {
$output->writeln(array(
"",
" " . Piwik::translate('CoreUpdater_ErrorDIYHelp'),
"",
" * " . Piwik::translate('CoreUpdater_ErrorDIYHelp_1'),
" * " . Piwik::translate('CoreUpdater_ErrorDIYHelp_2'),
" * " . Piwik::translate('CoreUpdater_ErrorDIYHelp_3'),
" * " . Piwik::translate('CoreUpdater_ErrorDIYHelp_4'),
" * " . Piwik::translate('CoreUpdater_ErrorDIYHelp_5')
));
}
throw new \RuntimeException(Piwik::translate('CoreUpdater_ConsoleUpdateFailure'));
}
private function outputUpdaterWarnings(OutputInterface $output, $warnings)
{
$output->writeln(array(
"",
" [!] " . Piwik::translate('CoreUpdater_WarningMessages'),
""
));
foreach ($warnings as $message) {
$output->writeln(" * $message");
}
}
private function outputUpdaterErrors(OutputInterface $output, $errors, $deactivatedPlugins)
{
$output->writeln(array(
"",
" [X] " . Piwik::translate('CoreUpdater_ErrorDuringPluginsUpdates'),
""
));
foreach ($errors as $message) {
$output->writeln(" * $message");
}
if (!empty($deactivatedPlugins)) {
$output->writeln(array(
"",
" [!] " . Piwik::translate('CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins', implode(', ', $deactivatedPlugins))
));
}
}
private function getUpdateHelpMessage()
{
return Piwik::translate('CoreUpdater_HelpMessageContent', array('[',']',"\n *"));
}
private function isUpdatingCore($componentsWithUpdateFile)
{
foreach ($componentsWithUpdateFile as $componentName => $updates) {
if ($componentName == 'core') {
return true;
}
}
return false;
}
private function getCurrentVersionForCore(Updater $updater)
{
$currentVersion = $updater->getCurrentComponentVersion('core');
if ($currentVersion === false) {
$currentVersion = "<= 0.2.9";
}
return $currentVersion;
}
private function getPluginsToUpdate($componentsWithUpdateFile)
{
$plugins = array();
foreach ($componentsWithUpdateFile as $componentName => $updates) {
if ($componentName !== 'core'
&& 0 !== strpos($componentName, 'log_')
) {
$plugins[] = $componentName;
}
}
return $plugins;
}
private function getDimensionsToUpdate($componentsWithUpdateFile)
{
$dimensions = array();
foreach ($componentsWithUpdateFile as $componentName => $updates) {
if (0 === strpos($componentName, 'log_')) {
$dimensions[] = $componentName;
}
}
sort($dimensions);
return $dimensions;
}
private function getMigrationQueriesToExecute(Updater $updater)
{
if (empty($this->migrationQueries)) {
$this->migrationQueries = $updater->getSqlQueriesToExecute();
}
return $this->migrationQueries;
}
private function makeUpdaterInstance(OutputInterface $output)
{
$updater = new Updater();
$migrationQueryCount = count($this->getMigrationQueriesToExecute($updater));
$updater->addUpdateObserver(new CliUpdateObserver($output, $migrationQueryCount));
return $updater;
}
/**
* @param OutputInterface $output
*/
protected function writeAlertMessageWhenCommandExecutedWithUnexpectedUser(OutputInterface $output)
{
if (SettingsServer::isWindows()) {
// does not work on windows
return;
}
$processUserAndGroup = Filechecks::getUserAndGroup();
$fileOwnerUserAndGroup = Filechecks::getOwnerOfPiwikFiles();
if (!$fileOwnerUserAndGroup || $processUserAndGroup == $fileOwnerUserAndGroup) {
// current process user/group appear to be same as the Matomo filesystem user/group -> OK
return;
}
$output->writeln(
sprintf("<comment>%s</comment>", Piwik::translate('CoreUpdater_ConsoleUpdateUnexpectedUserWarning', [
$processUserAndGroup,
$fileOwnerUserAndGroup,
Filechecks::getCommandToChangeOwnerOfPiwikFiles()
]))
);
}
}