2013-10-24 13:59:39 -04:00
< ? php
2024-05-24 13:43:47 -04:00
2013-10-24 13:59:39 -04:00
/**
2024-05-24 13:43:47 -04: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 11:07:28 -04:00
use OC\Console\TimestampFormatter ;
2022-08-22 10:56:01 -04:00
use OC\DB\MigratorExecuteSqlEvent ;
2022-08-22 11:59:26 -04: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 ;
2023-11-23 04:22:34 -05:00
use OCP\EventDispatcher\Event ;
use OCP\EventDispatcher\IEventDispatcher ;
use OCP\IConfig ;
use OCP\Util ;
2013-10-24 13:59:39 -04:00
use Symfony\Component\Console\Command\Command ;
2016-03-30 17:38:26 -04: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 10:54:27 -04: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 05:59:13 -04:00
2023-06-12 11:50:14 -04:00
public function __construct (
2024-01-11 11:32:58 -05:00
private IConfig $config
2023-06-12 11:50:14 -04:00
) {
2014-11-03 07:53:59 -05:00
parent :: __construct ();
2014-09-22 06:04:48 -04:00
}
2013-10-24 13:59:39 -04:00
protected function configure () {
$this
-> setName ( 'upgrade' )
2018-01-19 08:00:27 -05: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 05:48:07 -04:00
/**
* Execute the upgrade command
*
* @ param InputInterface $input input interface
* @ param OutputInterface $output output interface
*/
2020-06-26 08:54:51 -04:00
protected function execute ( InputInterface $input , OutputInterface $output ) : int {
2020-04-10 08:19:56 -04:00
if ( Util :: needUpgrade ()) {
2024-03-28 11:13:19 -04:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2015-06-23 11:07:28 -04:00
// Prepend each line with a little timestamp
$timestampFormatter = new TimestampFormatter ( $this -> config , $output -> getFormatter ());
$output -> setFormatter ( $timestampFormatter );
}
2014-09-22 05:59:13 -04:00
$self = $this ;
2024-01-11 11:32:58 -05:00
$updater = \OCP\Server :: get ( Updater :: class );
2021-11-30 10:45:51 -05:00
$incompatibleOverwrites = $this -> config -> getSystemValue ( 'app_install_overwrite' , []);
2013-10-28 10:15:56 -04:00
2022-08-22 11:59:26 -04:00
/** @var IEventDispatcher $dispatcher */
$dispatcher = \OC :: $server -> get ( IEventDispatcher :: class );
2016-03-30 17:38:26 -04:00
$progress = new ProgressBar ( $output );
2016-04-04 10:20:53 -04:00
$progress -> setFormat ( " %message% \n %current%/%max% [%bar%] %percent:3s%% " );
2022-08-23 08:57:00 -04:00
$listener = function ( MigratorExecuteSqlEvent $event ) use ( $progress , $output ) : void {
2022-08-22 10:56:01 -04:00
$message = $event -> getSql ();
2024-03-28 11:13:19 -04:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 10:56:01 -04: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 17:38:26 -04:00
}
}
2016-04-04 10:20:53 -04:00
};
2022-08-23 08:57:00 -04:00
$repairListener = function ( Event $event ) use ( $progress , $output ) : void {
2022-08-22 11:59:26 -04: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 10:26:31 -04:00
$progress -> advance ( $event -> getIncrement ());
2022-08-22 11:59:26 -04:00
} elseif ( $event instanceof RepairFinishEvent ) {
$progress -> setMessage ( 'Done' );
$progress -> finish ();
$output -> writeln ( '' );
} elseif ( $event instanceof RepairStepEvent ) {
2024-03-28 11:13:19 -04:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 11:59:26 -04:00
$output -> writeln ( '<info>Repair step: ' . $event -> getStepName () . '</info>' );
}
} elseif ( $event instanceof RepairInfoEvent ) {
2024-03-28 11:13:19 -04:00
if ( $output -> getVerbosity () > OutputInterface :: VERBOSITY_NORMAL ) {
2022-08-22 11:59:26 -04: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 07:19:00 -04:00
}
};
2022-08-22 11:59:26 -04: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 11:08:41 -05:00
2014-06-05 10:19:24 -04:00
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'maintenanceEnabled' , function () use ( $output ) {
2013-10-28 17:26:44 -04:00
$output -> writeln ( '<info>Turned on maintenance mode</info>' );
2013-10-28 10:15:56 -04:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'maintenanceDisabled' , function () use ( $output ) {
2015-05-19 04:27:53 -04:00
$output -> writeln ( '<info>Turned off maintenance mode</info>' );
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'maintenanceActive' , function () use ( $output ) {
2015-05-19 04:27:53 -04:00
$output -> writeln ( '<info>Maintenance mode is kept active</info>' );
});
$updater -> listen ( '\OC\Updater' , 'updateEnd' ,
2020-04-09 07:53:40 -04:00
function ( $success ) use ( $output , $self ) {
2015-06-23 11:07:28 -04:00
if ( $success ) {
2025-04-27 08:38:18 -04:00
$message = '<info>Update successful</info>' ;
2015-06-23 11:07:28 -04:00
} else {
2025-04-27 08:38:18 -04:00
$message = '<error>Update failed</error>' ;
2015-06-23 11:07:28 -04:00
}
2014-09-22 05:59:13 -04:00
$output -> writeln ( $message );
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'dbUpgradeBefore' , function () use ( $output ) {
2015-10-21 03:17:38 -04:00
$output -> writeln ( '<info>Updating database schema</info>' );
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'dbUpgrade' , function () use ( $output ) {
2013-10-28 17:26:44 -04:00
$output -> writeln ( '<info>Updated database</info>' );
2013-10-28 10:15:56 -04:00
});
2021-11-30 10:45:51 -05:00
$updater -> listen ( '\OC\Updater' , 'incompatibleAppDisabled' , function ( $app ) use ( $output , & $incompatibleOverwrites ) {
if ( ! in_array ( $app , $incompatibleOverwrites )) {
$output -> writeln ( '<comment>Disabled incompatible app: ' . $app . '</comment>' );
}
2015-02-17 06:00:39 -05:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'upgradeAppStoreApp' , function ( $app ) use ( $output ) {
2021-05-21 09:45:54 -04:00
$output -> writeln ( '<info>Update app ' . $app . ' from App Store</info>' );
2017-05-11 14:35:17 -04:00
});
2015-10-21 03:17:38 -04:00
$updater -> listen ( '\OC\Updater' , 'appSimulateUpdate' , function ( $app ) use ( $output ) {
$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> " );
});
2015-06-23 04:43:45 -04:00
$updater -> listen ( '\OC\Updater' , 'appUpgradeStarted' , function ( $app , $version ) use ( $output ) {
$output -> writeln ( " <info>Updating < $app > ...</info> " );
});
2015-02-24 06:52:16 -05:00
$updater -> listen ( '\OC\Updater' , 'appUpgrade' , function ( $app , $version ) use ( $output ) {
$output -> writeln ( " <info>Updated < $app > to $version </info> " );
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'failure' , function ( $message ) use ( $output , $self ) {
2014-09-22 05:59:13 -04:00
$output -> writeln ( " <error> $message </error> " );
2013-10-28 10:15:56 -04:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'setDebugLogLevel' , function ( $logLevel , $logLevelName ) use ( $output ) {
2025-04-27 08:38:18 -04:00
$output -> writeln ( '<info>Setting log level to debug</info>' );
2015-09-29 08:35:32 -04:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'resetLogLevel' , function ( $logLevel , $logLevelName ) use ( $output ) {
2025-04-27 08:38:18 -04:00
$output -> writeln ( '<info>Resetting log level</info>' );
2015-09-29 08:35:32 -04:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'startCheckCodeIntegrity' , function () use ( $output ) {
2025-04-27 08:38:18 -04:00
$output -> writeln ( '<info>Starting code integrity check...</info>' );
2016-01-22 07:18:00 -05:00
});
2020-04-09 07:53:40 -04:00
$updater -> listen ( '\OC\Updater' , 'finishedCheckCodeIntegrity' , function () use ( $output ) {
2025-04-27 08:38:18 -04:00
$output -> writeln ( '<info>Finished code integrity check</info>' );
2016-01-22 07:18:00 -05:00
});
2013-10-28 10:15:56 -04:00
2015-06-23 04:03:27 -04:00
$success = $updater -> upgrade ();
2014-03-14 05:48:07 -04:00
$this -> postUpgradeCheck ( $input , $output );
2020-04-10 08:19:56 -04:00
if ( ! $success ) {
2015-06-23 04:03:27 -04:00
return self :: ERROR_FAILURE ;
}
2013-10-28 16:50:28 -04:00
return self :: ERROR_SUCCESS ;
2020-04-10 08:19:56 -04:00
} elseif ( $this -> config -> getSystemValueBool ( 'maintenance' )) {
2016-07-30 09:39:32 -04:00
//Possible scenario: Nextcloud core is updated but an app failed
2021-01-15 10:38:25 -05:00
$output -> writeln ( '<comment>Nextcloud is in maintenance mode</comment>' );
2013-10-28 17:26:44 -04:00
$output -> write ( '<comment>Maybe an upgrade is already in process. Please check the '
2016-07-04 05:50:32 -04:00
. 'logfile (data/nextcloud.log). If you want to re-run the '
2013-10-28 17:19:15 -04:00
. 'upgrade procedure, remove the "maintenance mode" from '
2022-01-12 14:44:38 -05:00
. 'config.php and call this script again.</comment>' , true );
2013-10-28 17:19:15 -04:00
return self :: ERROR_MAINTENANCE_MODE ;
2013-10-28 10:15:56 -04:00
} else {
2016-07-30 09:39:32 -04:00
$output -> writeln ( '<info>Nextcloud is already latest version</info>' );
2013-10-28 17:19:15 -04: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 05:48:07 -04: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 04:30:18 -04:00
$trustedDomains = $this -> config -> getSystemValue ( 'trusted_domains' , []);
2014-03-14 05:48:07 -04: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
}