forked from vergnet/site-accueil-insa
395 lines
13 KiB
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()
|
|
]))
|
|
);
|
|
}
|
|
}
|