2013-10-24 13:59:39 -04:00
< ? php
2024-05-24 19:43:47 +02:00
2013-10-24 13:59:39 -04:00
/**
2024-05-24 19:43:47 +02:00
* SPDX - FileCopyrightText : 2016 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2013-10-24 13:59:39 -04:00
*/
namespace OC\Core\Command ;
2015-06-23 17:07:28 +02:00
use OC\Console\TimestampFormatter ;
2022-08-22 16:56:01 +02:00
use OC\DB\MigratorExecuteSqlEvent ;
2022-08-22 17:59:26 +02:00
use OC\Repair\Events\RepairAdvanceEvent ;
use OC\Repair\Events\RepairErrorEvent ;
use OC\Repair\Events\RepairFinishEvent ;
use OC\Repair\Events\RepairInfoEvent ;
use OC\Repair\Events\RepairStartEvent ;
use OC\Repair\Events\RepairStepEvent ;
use OC\Repair\Events\RepairWarningEvent ;
2013-10-28 10:15:56 -04:00
use OC\Updater ;
2022-08-22 17:59:26 +02:00
use OCP\EventDispatcher\Event ;
2022-08-22 16:56:01 +02:00
use OCP\EventDispatcher\IEventDispatcher ;
use OCP\IConfig ;
2024-12-18 15:52:23 +01:00
use OCP\IURLGenerator ;
2025-05-14 15:51:42 +02:00
use OCP\Server ;
2022-08-22 16:56:01 +02:00
use OCP\Util ;
2013-10-24 13:59:39 -04:00
use Symfony\Component\Console\Command\Command ;
2016-03-30 23:38:26 +02:00
use Symfony\Component\Console\Helper\ProgressBar ;
2013-10-24 13:59:39 -04:00
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Output\OutputInterface ;
class Upgrade extends Command {
2020-04-10 16:54:27 +02:00
public const ERROR_SUCCESS = 0 ;
public const ERROR_NOT_INSTALLED = 1 ;
public const ERROR_MAINTENANCE_MODE = 2 ;
public const ERROR_UP_TO_DATE = 0 ;
public const ERROR_INVALID_ARGUMENTS = 4 ;
public const ERROR_FAILURE = 5 ;
2014-09-22 11:59:13 +02:00
2023-06-12 19:20:14 +03:30
public function __construct (
2024-01-11 15:32:58 -01:00
private IConfig $config ,
2024-12-18 15:52:23 +01:00
private IURLGenerator $urlGenerator ,
2023-06-12 19:20:14 +03:30
) {
2014-11-03 13:53:59 +01:00
parent :: __construct ();
2014-09-22 12:04:48 +02:00
}
2013-10-24 13:59:39 -04:00
protected function configure () {
$this
-> setName ( 'upgrade' )
2018-01-19 14:00:27 +01:00
-> setDescription ( 'run upgrade routines after installation of a new release. The release has to be installed before.' );
2013-10-24 13:59:39 -04:00
}
2014-03-14 10:48:07 +01:00
/**
* Execute the upgrade command
*
* @ param InputInterface $input input interface
* @ param OutputInterface $output output interface
*/
2020-06-26 14:54:51 +02:00
protected function execute ( InputInterface $input , OutputInterface $output ) : int {
2017-11-30 16:00:19 +01:00
if ( Util :: needUpgrade ()) {
2024-03-28 16:13:19 +01:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2015-06-23 17:07:28 +02:00
// Prepend each line with a little timestamp
$timestampFormatter = new TimestampFormatter ( $this -> config , $output -> getFormatter ());
$output -> setFormatter ( $timestampFormatter );
}
2014-09-22 11:59:13 +02:00
$self = $this ;
2025-05-14 15:51:42 +02:00
$updater = Server :: get ( Updater :: class );
2021-11-30 16:45:51 +01:00
$incompatibleOverwrites = $this -> config -> getSystemValue ( 'app_install_overwrite' , []);
2013-10-28 10:15:56 -04:00
2022-08-22 17:59:26 +02:00
/** @var IEventDispatcher $dispatcher */
2025-05-14 15:51:42 +02:00
$dispatcher = Server :: get ( IEventDispatcher :: class );
2016-03-30 23:38:26 +02:00
$progress = new ProgressBar ( $output );
2016-04-04 16:20:53 +02:00
$progress -> setFormat ( " %message% \n %current%/%max% [%bar%] %percent:3s%% " );
2022-08-23 14:57:00 +02:00
$listener = function ( MigratorExecuteSqlEvent $event ) use ( $progress , $output ) : void {
2022-08-22 16:56:01 +02:00
$message = $event -> getSql ();
2024-03-28 16:13:19 +01:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 16:56:01 +02:00
$output -> writeln ( ' Executing SQL ' . $message );
} else {
if ( strlen ( $message ) > 60 ) {
$message = substr ( $message , 0 , 57 ) . '...' ;
}
$progress -> setMessage ( $message );
if ( $event -> getCurrentStep () === 1 ) {
$output -> writeln ( '' );
$progress -> start ( $event -> getMaxStep ());
}
$progress -> setProgress ( $event -> getCurrentStep ());
if ( $event -> getCurrentStep () === $event -> getMaxStep ()) {
$progress -> setMessage ( 'Done' );
$progress -> finish ();
$output -> writeln ( '' );
2016-03-30 23:38:26 +02:00
}
}
2016-04-04 16:20:53 +02:00
};
2022-08-23 14:57:00 +02:00
$repairListener = function ( Event $event ) use ( $progress , $output ) : void {
2022-08-22 17:59:26 +02:00
if ( $event instanceof RepairStartEvent ) {
$progress -> setMessage ( 'Starting ...' );
$output -> writeln ( $event -> getCurrentStepName ());
$output -> writeln ( '' );
$progress -> start ( $event -> getMaxStep ());
} elseif ( $event instanceof RepairAdvanceEvent ) {
$desc = $event -> getDescription ();
if ( ! empty ( $desc )) {
$progress -> setMessage ( $desc );
}
2022-08-25 16:26:31 +02:00
$progress -> advance ( $event -> getIncrement ());
2022-08-22 17:59:26 +02:00
} elseif ( $event instanceof RepairFinishEvent ) {
$progress -> setMessage ( 'Done' );
$progress -> finish ();
$output -> writeln ( '' );
} elseif ( $event instanceof RepairStepEvent ) {
2024-03-28 16:13:19 +01:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 17:59:26 +02:00
$output -> writeln ( '<info>Repair step: ' . $event -> getStepName () . '</info>' );
}
} elseif ( $event instanceof RepairInfoEvent ) {
2024-03-28 16:13:19 +01:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 17:59:26 +02:00
$output -> writeln ( '<info>Repair info: ' . $event -> getMessage () . '</info>' );
}
} elseif ( $event instanceof RepairWarningEvent ) {
$output -> writeln ( '<error>Repair warning: ' . $event -> getMessage () . '</error>' );
} elseif ( $event instanceof RepairErrorEvent ) {
$output -> writeln ( '<error>Repair error: ' . $event -> getMessage () . '</error>' );
2016-04-27 13:19:00 +02:00
}
};
2022-08-22 17:59:26 +02:00
$dispatcher -> addListener ( MigratorExecuteSqlEvent :: class , $listener );
$dispatcher -> addListener ( RepairStartEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairAdvanceEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairFinishEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairStepEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairInfoEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairWarningEvent :: class , $repairListener );
$dispatcher -> addListener ( RepairErrorEvent :: class , $repairListener );
2019-02-06 17:08:41 +01:00
2014-06-05 16:19:24 +02:00
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'maintenanceEnabled' , function () use ( $output ) : void {
2013-10-28 22:26:44 +01:00
$output -> writeln ( '<info>Turned on maintenance mode</info>' );
2013-10-28 10:15:56 -04:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'maintenanceDisabled' , function () use ( $output ) : void {
2015-05-19 10:27:53 +02:00
$output -> writeln ( '<info>Turned off maintenance mode</info>' );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'maintenanceActive' , function () use ( $output ) : void {
2015-05-19 10:27:53 +02:00
$output -> writeln ( '<info>Maintenance mode is kept active</info>' );
});
$updater -> listen ( '\OC\Updater' , 'updateEnd' ,
2025-05-14 15:51:42 +02:00
function ( $success ) use ( $output , $self ) : void {
2015-06-23 17:07:28 +02:00
if ( $success ) {
2016-09-21 15:12:00 +02:00
$message = '<info>Update successful</info>' ;
2015-06-23 17:07:28 +02:00
} else {
2016-09-21 15:12:00 +02:00
$message = '<error>Update failed</error>' ;
2015-06-23 17:07:28 +02:00
}
2014-09-22 11:59:13 +02:00
$output -> writeln ( $message );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'dbUpgradeBefore' , function () use ( $output ) : void {
2015-10-21 09:17:38 +02:00
$output -> writeln ( '<info>Updating database schema</info>' );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'dbUpgrade' , function () use ( $output ) : void {
2013-10-28 22:26:44 +01:00
$output -> writeln ( '<info>Updated database</info>' );
2013-10-28 10:15:56 -04:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'incompatibleAppDisabled' , function ( $app ) use ( $output , & $incompatibleOverwrites ) : void {
2021-11-30 16:45:51 +01:00
if ( ! in_array ( $app , $incompatibleOverwrites )) {
$output -> writeln ( '<comment>Disabled incompatible app: ' . $app . '</comment>' );
}
2015-02-17 12:00:39 +01:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'upgradeAppStoreApp' , function ( $app ) use ( $output ) : void {
2021-05-21 15:45:54 +02:00
$output -> writeln ( '<info>Update app ' . $app . ' from App Store</info>' );
2017-05-11 13:35:17 -05:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'appSimulateUpdate' , function ( $app ) use ( $output ) : void {
2015-10-21 09:17:38 +02:00
$output -> writeln ( " <info>Checking whether the database schema for < $app > can be updated (this can take a long time depending on the database size)</info> " );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'appUpgradeStarted' , function ( $app , $version ) use ( $output ) : void {
2015-06-23 10:43:45 +02:00
$output -> writeln ( " <info>Updating < $app > ...</info> " );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'appUpgrade' , function ( $app , $version ) use ( $output ) : void {
2015-02-24 12:52:16 +01:00
$output -> writeln ( " <info>Updated < $app > to $version </info> " );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'failure' , function ( $message ) use ( $output , $self ) : void {
2014-09-22 11:59:13 +02:00
$output -> writeln ( " <error> $message </error> " );
2013-10-28 10:15:56 -04:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'setDebugLogLevel' , function ( $logLevel , $logLevelName ) use ( $output ) : void {
2020-09-10 15:17:59 +02:00
$output -> writeln ( '<info>Setting log level to debug</info>' );
2015-09-29 14:35:32 +02:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'resetLogLevel' , function ( $logLevel , $logLevelName ) use ( $output ) : void {
2020-09-10 15:17:59 +02:00
$output -> writeln ( '<info>Resetting log level</info>' );
2015-09-29 14:35:32 +02:00
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'startCheckCodeIntegrity' , function () use ( $output ) : void {
2016-01-22 13:18:00 +01:00
$output -> writeln ( '<info>Starting code integrity check...</info>' );
});
2025-05-14 15:51:42 +02:00
$updater -> listen ( '\OC\Updater' , 'finishedCheckCodeIntegrity' , function () use ( $output ) : void {
2016-01-22 13:18:00 +01:00
$output -> writeln ( '<info>Finished code integrity check</info>' );
});
2013-10-28 10:15:56 -04:00
2015-06-23 10:03:27 +02:00
$success = $updater -> upgrade ();
2014-03-14 10:48:07 +01:00
$this -> postUpgradeCheck ( $input , $output );
2015-06-23 10:03:27 +02:00
if ( ! $success ) {
return self :: ERROR_FAILURE ;
}
2013-10-28 16:50:28 -04:00
return self :: ERROR_SUCCESS ;
2020-04-10 10:35:09 +02:00
} elseif ( $this -> config -> getSystemValueBool ( 'maintenance' )) {
2016-07-30 15:39:32 +02:00
//Possible scenario: Nextcloud core is updated but an app failed
2021-01-15 16:38:25 +01:00
$output -> writeln ( '<comment>Nextcloud is in maintenance mode</comment>' );
2013-10-28 22:26:44 +01:00
$output -> write ( '<comment>Maybe an upgrade is already in process. Please check the '
2016-07-04 11:50:32 +02:00
. 'logfile (data/nextcloud.log). If you want to re-run the '
2013-10-28 22:19:15 +01:00
. 'upgrade procedure, remove the "maintenance mode" from '
2022-01-12 20:44:38 +01:00
. 'config.php and call this script again.</comment>' , true );
2013-10-28 22:19:15 +01:00
return self :: ERROR_MAINTENANCE_MODE ;
2013-10-28 10:15:56 -04:00
} else {
2024-12-18 15:52:23 +01:00
$output -> writeln ( '<info>No upgrade required.</info>' );
$output -> writeln ( '' );
$output -> writeln ( 'Note: This command triggers the upgrade actions associated with a new version. The new version\'s updated source files must be deployed in advance.' );
$doc = $this -> urlGenerator -> linkToDocs ( 'admin-update' );
$output -> writeln ( 'See the upgrade documentation: ' . $doc . ' for more information.' );
2013-10-28 22:19:15 +01:00
return self :: ERROR_UP_TO_DATE ;
2013-10-28 10:15:56 -04:00
}
2013-10-24 13:59:39 -04:00
}
2014-03-14 10:48:07 +01:00
/**
* Perform a post upgrade check ( specific to the command line tool )
*
* @ param InputInterface $input input interface
* @ param OutputInterface $output output interface
*/
protected function postUpgradeCheck ( InputInterface $input , OutputInterface $output ) {
2020-03-26 09:30:18 +01:00
$trustedDomains = $this -> config -> getSystemValue ( 'trusted_domains' , []);
2014-03-14 10:48:07 +01:00
if ( empty ( $trustedDomains )) {
$output -> write (
'<warning>The setting "trusted_domains" could not be ' .
'set automatically by the upgrade script, ' .
'please set it manually</warning>'
);
}
}
2013-10-24 13:59:39 -04:00
}