Completed
Push — master ( 879e11...10930c )
by Lukas
20:02 queued 06:34
created

Updater::doCoreUpgrade()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 * @copyright Copyright (c) 2016, Lukas Reschke <[email protected]>
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Frank Karlitschek <[email protected]>
8
 * @author Joas Schilling <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Steffen Lindner <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 * @author Victor Dubiniuk <[email protected]>
15
 * @author Vincent Petry <[email protected]>
16
 *
17
 * @license AGPL-3.0
18
 *
19
 * This code is free software: you can redistribute it and/or modify
20
 * it under the terms of the GNU Affero General Public License, version 3,
21
 * as published by the Free Software Foundation.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License, version 3,
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
30
 *
31
 */
32
33
namespace OC;
34
35
use OC\Hooks\BasicEmitter;
36
use OC\IntegrityCheck\Checker;
37
use OC_App;
38
use OCP\IConfig;
39
use OCP\ILogger;
40
use OCP\Util;
41
use Symfony\Component\EventDispatcher\GenericEvent;
42
43
/**
44
 * Class that handles autoupdating of ownCloud
45
 *
46
 * Hooks provided in scope \OC\Updater
47
 *  - maintenanceStart()
48
 *  - maintenanceEnd()
49
 *  - dbUpgrade()
50
 *  - failure(string $message)
51
 */
52
class Updater extends BasicEmitter {
53
54
	/** @var ILogger $log */
55
	private $log;
56
57
	/** @var IConfig */
58
	private $config;
59
60
	/** @var Checker */
61
	private $checker;
62
63
	/** @var bool */
64
	private $skip3rdPartyAppsDisable;
65
66
	private $logLevelNames = [
67
		0 => 'Debug',
68
		1 => 'Info',
69
		2 => 'Warning',
70
		3 => 'Error',
71
		4 => 'Fatal',
72
	];
73
74
	/**
75
	 * @param IConfig $config
76
	 * @param Checker $checker
77
	 * @param ILogger $log
78
	 */
79
	public function __construct(IConfig $config,
80
								Checker $checker,
81
								ILogger $log = null) {
82
		$this->log = $log;
83
		$this->config = $config;
84
		$this->checker = $checker;
85
86
		// If at least PHP 7.0.0 is used we don't need to disable apps as we catch
87
		// fatal errors and exceptions and disable the app just instead.
88
		if(version_compare(phpversion(), '7.0.0', '>=')) {
89
			$this->skip3rdPartyAppsDisable = true;
90
		}
91
	}
92
93
	/**
94
	 * Sets whether the update disables 3rd party apps.
95
	 * This can be set to true to skip the disable.
96
	 *
97
	 * @param bool $flag false to not disable, true otherwise
98
	 */
99
	public function setSkip3rdPartyAppsDisable($flag) {
100
		$this->skip3rdPartyAppsDisable = $flag;
101
	}
102
103
	/**
104
	 * runs the update actions in maintenance mode, does not upgrade the source files
105
	 * except the main .htaccess file
106
	 *
107
	 * @return bool true if the operation succeeded, false otherwise
108
	 */
109
	public function upgrade() {
110
		$this->emitRepairEvents();
111
		$this->logAllEvents();
112
113
		$logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
114
		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
115
		$this->config->setSystemValue('loglevel', Util::DEBUG);
116
117
		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
118
119
		if(!$wasMaintenanceModeEnabled) {
120
			$this->config->setSystemValue('maintenance', true);
121
			$this->emit('\OC\Updater', 'maintenanceEnabled');
122
		}
123
124
		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
125
		$currentVersion = implode('.', \OCP\Util::getVersion());
126
		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
127
128
		$success = true;
129
		try {
130
			$this->doUpgrade($currentVersion, $installedVersion);
131
		} catch (HintException $exception) {
132
			$this->log->logException($exception, ['app' => 'core']);
133
			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
134
			$success = false;
135
		} catch (\Exception $exception) {
136
			$this->log->logException($exception, ['app' => 'core']);
137
			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
138
			$success = false;
139
		}
140
141
		$this->emit('\OC\Updater', 'updateEnd', array($success));
142
143
		if(!$wasMaintenanceModeEnabled && $success) {
144
			$this->config->setSystemValue('maintenance', false);
145
			$this->emit('\OC\Updater', 'maintenanceDisabled');
146
		} else {
147
			$this->emit('\OC\Updater', 'maintenanceActive');
148
		}
149
150
		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
151
		$this->config->setSystemValue('loglevel', $logLevel);
152
		$this->config->setSystemValue('installed', true);
153
154
		return $success;
155
	}
156
157
	/**
158
	 * Return version from which this version is allowed to upgrade from
159
	 *
160
	 * @return array allowed previous versions per vendor
161
	 */
162
	private function getAllowedPreviousVersions() {
163
		// this should really be a JSON file
164
		require \OC::$SERVERROOT . '/version.php';
165
		/** @var array $OC_VersionCanBeUpgradedFrom */
166
		return $OC_VersionCanBeUpgradedFrom;
0 ignored issues
show
Bug introduced by
The variable $OC_VersionCanBeUpgradedFrom does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
167
	}
168
169
	/**
170
	 * Return vendor from which this version was published
171
	 *
172
	 * @return string Get the vendor
173
	 */
174
	private function getVendor() {
175
		// this should really be a JSON file
176
		require \OC::$SERVERROOT . '/version.php';
177
		/** @var string $vendor */
178
		return (string) $vendor;
0 ignored issues
show
Bug introduced by
The variable $vendor does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
179
	}
180
181
	/**
182
	 * Whether an upgrade to a specified version is possible
183
	 * @param string $oldVersion
184
	 * @param string $newVersion
185
	 * @param array $allowedPreviousVersions
186
	 * @return bool
187
	 */
188
	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
189
		$version = explode('.', $oldVersion);
190
		$majorMinor = $version[0] . '.' . $version[1];
191
192
		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
193
194
		// Vendor was not set correctly on install, so we have to white-list known versions
195
		if ($currentVendor === '') {
196
			if (in_array($oldVersion, [
197
				'11.0.2.7',
198
				'11.0.1.2',
199
				'11.0.0.10',
200
			], true)) {
201
				$currentVendor = 'nextcloud';
202
			} else if (in_array($oldVersion, [
203
					'10.0.0.12',
204
				], true)) {
205
				$currentVendor = 'owncloud';
206
			}
207
		}
208
209
		if ($currentVendor === 'nextcloud') {
210
			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
211
				&& (version_compare($oldVersion, $newVersion, '<=') ||
212
					$this->config->getSystemValue('debug', false));
213
		}
214
215
		// Check if the instance can be migrated
216
		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
217
			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
218
	}
219
220
	/**
221
	 * runs the update actions in maintenance mode, does not upgrade the source files
222
	 * except the main .htaccess file
223
	 *
224
	 * @param string $currentVersion current version to upgrade to
225
	 * @param string $installedVersion previous version from which to upgrade from
226
	 *
227
	 * @throws \Exception
228
	 */
229
	private function doUpgrade($currentVersion, $installedVersion) {
230
		// Stop update if the update is over several major versions
231
		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
232
		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
233
			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
234
		}
235
236
		// Update .htaccess files
237
		try {
238
			Setup::updateHtaccess();
239
			Setup::protectDataDirectory();
240
		} catch (\Exception $e) {
241
			throw new \Exception($e->getMessage());
242
		}
243
244
		// create empty file in data dir, so we can later find
245
		// out that this is indeed an ownCloud data directory
246
		// (in case it didn't exist before)
247
		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
248
249
		// pre-upgrade repairs
250
		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
251
		$repair->run();
252
253
		$this->doCoreUpgrade();
254
255
		try {
256
			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
257
			Setup::installBackgroundJobs();
258
		} catch (\Exception $e) {
259
			throw new \Exception($e->getMessage());
260
		}
261
262
		// update all shipped apps
263
		$this->checkAppsRequirements();
264
		$this->doAppUpgrade();
265
266
		// Update the appfetchers version so it downloads the correct list from the appstore
267
		\OC::$server->getAppFetcher()->setVersion($currentVersion);
268
269
		// upgrade appstore apps
270
		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
271
272
		// install new shipped apps on upgrade
273
		OC_App::loadApps('authentication');
274
		$errors = Installer::installShippedApps(true);
275
		foreach ($errors as $appId => $exception) {
276
			/** @var \Exception $exception */
277
			$this->log->logException($exception, ['app' => $appId]);
278
			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
279
		}
280
281
		// post-upgrade repairs
282
		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
283
		$repair->run();
284
285
		//Invalidate update feed
286
		$this->config->setAppValue('core', 'lastupdatedat', 0);
287
288
		// Check for code integrity if not disabled
289
		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
290
			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
291
			$this->checker->runInstanceVerification();
292
			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
293
		}
294
295
		// only set the final version if everything went well
296
		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
297
		$this->config->setAppValue('core', 'vendor', $this->getVendor());
298
	}
299
300
	protected function doCoreUpgrade() {
301
		$this->emit('\OC\Updater', 'dbUpgradeBefore');
302
303
		// do the real upgrade
304
		\OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml');
305
306
		$this->emit('\OC\Updater', 'dbUpgrade');
307
	}
308
309
	/**
310
	 * @param string $version the oc version to check app compatibility with
311
	 */
312
	protected function checkAppUpgrade($version) {
313
		$apps = \OC_App::getEnabledApps();
314
		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
315
316
		foreach ($apps as $appId) {
317
			$info = \OC_App::getAppInfo($appId);
318
			$compatible = \OC_App::isAppCompatible($version, $info);
0 ignored issues
show
Bug introduced by
It seems like $info defined by \OC_App::getAppInfo($appId) on line 317 can also be of type null; however, OC_App::isAppCompatible() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
319
			$isShipped = \OC_App::isShipped($appId);
320
321
			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
322
				/**
323
				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
324
				 * are not possible anymore within it. - Consider this when touching the code.
325
				 * @link https://github.com/owncloud/core/issues/10980
326
				 * @see \OC_App::updateApp
327
				 */
328
				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
329
					$this->includePreUpdate($appId);
330
				}
331
				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
332
					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
333
					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
0 ignored issues
show
Bug introduced by
The method simulateUpdateDbFromStructure() does not exist on OC_DB. Did you maybe mean updateDbFromStructure()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
334
				}
335
			}
336
		}
337
338
		$this->emit('\OC\Updater', 'appUpgradeCheck');
339
	}
340
341
	/**
342
	 * Includes the pre-update file. Done here to prevent namespace mixups.
343
	 * @param string $appId
344
	 */
345
	private function includePreUpdate($appId) {
346
		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
347
	}
348
349
	/**
350
	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
351
	 * (types authentication, filesystem, logging, in that order) afterwards.
352
	 *
353
	 * @throws NeedsUpdateException
354
	 */
355
	protected function doAppUpgrade() {
356
		$apps = \OC_App::getEnabledApps();
357
		$priorityTypes = array('authentication', 'filesystem', 'logging');
358
		$pseudoOtherType = 'other';
359
		$stacks = array($pseudoOtherType => array());
360
361
		foreach ($apps as $appId) {
362
			$priorityType = false;
363
			foreach ($priorityTypes as $type) {
364
				if(!isset($stacks[$type])) {
365
					$stacks[$type] = array();
366
				}
367
				if (\OC_App::isType($appId, $type)) {
368
					$stacks[$type][] = $appId;
369
					$priorityType = true;
370
					break;
371
				}
372
			}
373
			if (!$priorityType) {
374
				$stacks[$pseudoOtherType][] = $appId;
375
			}
376
		}
377
		foreach ($stacks as $type => $stack) {
378
			foreach ($stack as $appId) {
379
				if (\OC_App::shouldUpgrade($appId)) {
380
					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
381
					\OC_App::updateApp($appId);
382
					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
383
				}
384
				if($type !== $pseudoOtherType) {
385
					// load authentication, filesystem and logging apps after
386
					// upgrading them. Other apps my need to rely on modifying
387
					// user and/or filesystem aspects.
388
					\OC_App::loadApp($appId);
389
				}
390
			}
391
		}
392
	}
393
394
	/**
395
	 * check if the current enabled apps are compatible with the current
396
	 * ownCloud version. disable them if not.
397
	 * This is important if you upgrade ownCloud and have non ported 3rd
398
	 * party apps installed.
399
	 *
400
	 * @return array
401
	 * @throws \Exception
402
	 */
403
	private function checkAppsRequirements() {
404
		$isCoreUpgrade = $this->isCodeUpgrade();
405
		$apps = OC_App::getEnabledApps();
406
		$version = Util::getVersion();
407
		$disabledApps = [];
408
		foreach ($apps as $app) {
409
			// check if the app is compatible with this version of ownCloud
410
			$info = OC_App::getAppInfo($app);
411
			if(!OC_App::isAppCompatible($version, $info)) {
0 ignored issues
show
Documentation introduced by
$version is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $info defined by \OC_App::getAppInfo($app) on line 410 can also be of type null; however, OC_App::isAppCompatible() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
412
				if (OC_App::isShipped($app)) {
413
					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
414
				}
415
				OC_App::disable($app);
416
				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
417
			}
418
			// no need to disable any app in case this is a non-core upgrade
419
			if (!$isCoreUpgrade) {
420
				continue;
421
			}
422
			// shipped apps will remain enabled
423
			if (OC_App::isShipped($app)) {
424
				continue;
425
			}
426
			// authentication and session apps will remain enabled as well
427
			if (OC_App::isType($app, ['session', 'authentication'])) {
428
				continue;
429
			}
430
431
			// disable any other 3rd party apps if not overriden
432
			if(!$this->skip3rdPartyAppsDisable) {
433
				\OC_App::disable($app);
434
				$disabledApps[]= $app;
435
				$this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
436
			};
437
		}
438
		return $disabledApps;
439
	}
440
441
	/**
442
	 * @return bool
443
	 */
444
	private function isCodeUpgrade() {
445
		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
446
		$currentVersion = implode('.', Util::getVersion());
447
		if (version_compare($currentVersion, $installedVersion, '>')) {
448
			return true;
449
		}
450
		return false;
451
	}
452
453
	/**
454
	 * @param array $disabledApps
455
	 * @throws \Exception
456
	 */
457
	private function upgradeAppStoreApps(array $disabledApps) {
458
		foreach($disabledApps as $app) {
459
			try {
460
				$installer = new Installer(
461
					\OC::$server->getAppFetcher(),
462
					\OC::$server->getHTTPClientService(),
463
					\OC::$server->getTempManager(),
464
					$this->log,
465
					\OC::$server->getConfig()
466
				);
467
				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
468
				if (Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \OC\Installer::isUpdateA...erver->getAppFetcher()) of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
469
					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
470
					$installer->updateAppstoreApp($app);
471
				}
472
				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
473
			} catch (\Exception $ex) {
474
				$this->log->logException($ex, ['app' => 'core']);
475
			}
476
		}
477
	}
478
479
	/**
480
	 * Forward messages emitted by the repair routine
481
	 */
482
	private function emitRepairEvents() {
483
		$dispatcher = \OC::$server->getEventDispatcher();
484
		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
485
			if ($event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
486
				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
487
			}
488
		});
489
		$dispatcher->addListener('\OC\Repair::error', function ($event) {
490
			if ($event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
491
				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
492
			}
493
		});
494
		$dispatcher->addListener('\OC\Repair::info', function ($event) {
495
			if ($event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
496
				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
497
			}
498
		});
499
		$dispatcher->addListener('\OC\Repair::step', function ($event) {
500
			if ($event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
501
				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
502
			}
503
		});
504
	}
505
506
	private function logAllEvents() {
507
		$log = $this->log;
508
509
		$dispatcher = \OC::$server->getEventDispatcher();
510 View Code Duplication
		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
511
			if (!$event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
512
				return;
513
			}
514
			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
515
		});
516 View Code Duplication
		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
517
			if (!$event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
518
				return;
519
			}
520
			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
521
		});
522
523
		$repairListener = function($event) use ($log) {
524
			if (!$event instanceof GenericEvent) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\EventDispatcher\GenericEvent does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
525
				return;
526
			}
527
			switch ($event->getSubject()) {
528
				case '\OC\Repair::startProgress':
529
					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
530
					break;
531
				case '\OC\Repair::advance':
532
					$desc = $event->getArgument(1);
533
					if (empty($desc)) {
534
						$desc = '';
535
					}
536
					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
537
538
					break;
539
				case '\OC\Repair::finishProgress':
540
					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
541
					break;
542
				case '\OC\Repair::step':
543
					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
544
					break;
545
				case '\OC\Repair::info':
546
					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
547
					break;
548
				case '\OC\Repair::warning':
549
					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
550
					break;
551
				case '\OC\Repair::error':
552
					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
553
					break;
554
			}
555
		};
556
557
		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
558
		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
559
		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
560
		$dispatcher->addListener('\OC\Repair::step', $repairListener);
561
		$dispatcher->addListener('\OC\Repair::info', $repairListener);
562
		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
563
		$dispatcher->addListener('\OC\Repair::error', $repairListener);
564
565
566
		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
567
			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
568
		});
569
		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
570
			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
571
		});
572
		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
573
			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
574
		});
575
		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
576
			if ($success) {
577
				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
578
			} else {
579
				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
580
			}
581
		});
582
		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
583
			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
584
		});
585
		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
586
			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
587
		});
588
		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
589
			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
590
		});
591
		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
592
			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
593
		});
594
		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
595
			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
596
		});
597
		$this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) {
598
			$log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']);
599
		});
600
		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
601
			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
602
		});
603
		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
604
			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
605
		});
606
		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
607
			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
608
		});
609
		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
610
			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
611
		});
612
		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
613
			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
614
		});
615
		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
616
			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
617
		});
618
		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
619
			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
620
		});
621
		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
622
			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
623
		});
624
		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
625
			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
626
		});
627
		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
628
			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
629
		});
630
		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
631
			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
632
		});
633
		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
634
			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
635
		});
636
		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
637
			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
638
		});
639
640
	}
641
642
}
643
644