Completed
Push — master ( ed4633...4a5a36 )
by Lukas
08:56
created

Updater::getAllowedPreviousVersions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
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 implode('.', $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
		if ($currentVendor === 'nextcloud') {
194
			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
195
				&& (version_compare($oldVersion, $newVersion, '<=') ||
196
					$this->config->getSystemValue('debug', false));
197
		}
198
199
		// Check if the instance can be migrated
200
		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]);
201
	}
202
203
	/**
204
	 * runs the update actions in maintenance mode, does not upgrade the source files
205
	 * except the main .htaccess file
206
	 *
207
	 * @param string $currentVersion current version to upgrade to
208
	 * @param string $installedVersion previous version from which to upgrade from
209
	 *
210
	 * @throws \Exception
211
	 */
212
	private function doUpgrade($currentVersion, $installedVersion) {
213
		// Stop update if the update is over several major versions
214
		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
215
		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
0 ignored issues
show
Documentation introduced by
$allowedPreviousVersions is of type string, but the function expects a array.

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...
216
			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
217
		}
218
219
		// Update .htaccess files
220
		try {
221
			Setup::updateHtaccess();
222
			Setup::protectDataDirectory();
223
		} catch (\Exception $e) {
224
			throw new \Exception($e->getMessage());
225
		}
226
227
		// create empty file in data dir, so we can later find
228
		// out that this is indeed an ownCloud data directory
229
		// (in case it didn't exist before)
230
		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
231
232
		// pre-upgrade repairs
233
		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
234
		$repair->run();
235
236
		$this->doCoreUpgrade();
237
238
		try {
239
			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
240
			Setup::installBackgroundJobs();
241
		} catch (\Exception $e) {
242
			throw new \Exception($e->getMessage());
243
		}
244
245
		// update all shipped apps
246
		$disabledApps = $this->checkAppsRequirements();
247
		$this->doAppUpgrade();
248
249
		// upgrade appstore apps
250
		$this->upgradeAppStoreApps($disabledApps);
251
252
		// install new shipped apps on upgrade
253
		OC_App::loadApps('authentication');
254
		$errors = Installer::installShippedApps(true);
255
		foreach ($errors as $appId => $exception) {
256
			/** @var \Exception $exception */
257
			$this->log->logException($exception, ['app' => $appId]);
258
			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
259
		}
260
261
		// post-upgrade repairs
262
		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
263
		$repair->run();
264
265
		//Invalidate update feed
266
		$this->config->setAppValue('core', 'lastupdatedat', 0);
267
268
		// Check for code integrity if not disabled
269
		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
270
			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
271
			$this->checker->runInstanceVerification();
272
			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
273
		}
274
275
		// only set the final version if everything went well
276
		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
277
		$this->config->setAppValue('core', 'vendor', $this->getVendor());
278
	}
279
280
	protected function doCoreUpgrade() {
281
		$this->emit('\OC\Updater', 'dbUpgradeBefore');
282
283
		// do the real upgrade
284
		\OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml');
285
286
		$this->emit('\OC\Updater', 'dbUpgrade');
287
	}
288
289
	/**
290
	 * @param string $version the oc version to check app compatibility with
291
	 */
292
	protected function checkAppUpgrade($version) {
293
		$apps = \OC_App::getEnabledApps();
294
		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
295
296
		foreach ($apps as $appId) {
297
			$info = \OC_App::getAppInfo($appId);
298
			$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 297 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...
299
			$isShipped = \OC_App::isShipped($appId);
300
301
			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
302
				/**
303
				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
304
				 * are not possible anymore within it. - Consider this when touching the code.
305
				 * @link https://github.com/owncloud/core/issues/10980
306
				 * @see \OC_App::updateApp
307
				 */
308
				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
309
					$this->includePreUpdate($appId);
310
				}
311
				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
312
					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
313
					\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...
314
				}
315
			}
316
		}
317
318
		$this->emit('\OC\Updater', 'appUpgradeCheck');
319
	}
320
321
	/**
322
	 * Includes the pre-update file. Done here to prevent namespace mixups.
323
	 * @param string $appId
324
	 */
325
	private function includePreUpdate($appId) {
326
		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
327
	}
328
329
	/**
330
	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
331
	 * (types authentication, filesystem, logging, in that order) afterwards.
332
	 *
333
	 * @throws NeedsUpdateException
334
	 */
335
	protected function doAppUpgrade() {
336
		$apps = \OC_App::getEnabledApps();
337
		$priorityTypes = array('authentication', 'filesystem', 'logging');
338
		$pseudoOtherType = 'other';
339
		$stacks = array($pseudoOtherType => array());
340
341
		foreach ($apps as $appId) {
342
			$priorityType = false;
343
			foreach ($priorityTypes as $type) {
344
				if(!isset($stacks[$type])) {
345
					$stacks[$type] = array();
346
				}
347
				if (\OC_App::isType($appId, $type)) {
348
					$stacks[$type][] = $appId;
349
					$priorityType = true;
350
					break;
351
				}
352
			}
353
			if (!$priorityType) {
354
				$stacks[$pseudoOtherType][] = $appId;
355
			}
356
		}
357
		foreach ($stacks as $type => $stack) {
358
			foreach ($stack as $appId) {
359
				if (\OC_App::shouldUpgrade($appId)) {
360
					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
361
					\OC_App::updateApp($appId);
362
					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
363
				}
364
				if($type !== $pseudoOtherType) {
365
					// load authentication, filesystem and logging apps after
366
					// upgrading them. Other apps my need to rely on modifying
367
					// user and/or filesystem aspects.
368
					\OC_App::loadApp($appId, false);
369
				}
370
			}
371
		}
372
	}
373
374
	/**
375
	 * check if the current enabled apps are compatible with the current
376
	 * ownCloud version. disable them if not.
377
	 * This is important if you upgrade ownCloud and have non ported 3rd
378
	 * party apps installed.
379
	 *
380
	 * @return array
381
	 * @throws \Exception
382
	 */
383
	private function checkAppsRequirements() {
384
		$isCoreUpgrade = $this->isCodeUpgrade();
385
		$apps = OC_App::getEnabledApps();
386
		$version = Util::getVersion();
387
		$disabledApps = [];
388
		foreach ($apps as $app) {
389
			// check if the app is compatible with this version of ownCloud
390
			$info = OC_App::getAppInfo($app);
391
			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 390 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...
392
				if (OC_App::isShipped($app)) {
393
					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
394
				}
395
				OC_App::disable($app);
396
				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
397
			}
398
			// no need to disable any app in case this is a non-core upgrade
399
			if (!$isCoreUpgrade) {
400
				continue;
401
			}
402
			// shipped apps will remain enabled
403
			if (OC_App::isShipped($app)) {
404
				continue;
405
			}
406
			// authentication and session apps will remain enabled as well
407
			if (OC_App::isType($app, ['session', 'authentication'])) {
408
				continue;
409
			}
410
411
			// disable any other 3rd party apps if not overriden
412
			if(!$this->skip3rdPartyAppsDisable) {
413
				\OC_App::disable($app);
414
				$disabledApps[]= $app;
415
				$this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
416
			};
417
		}
418
		return $disabledApps;
419
	}
420
421
	/**
422
	 * @return bool
423
	 */
424
	private function isCodeUpgrade() {
425
		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
426
		$currentVersion = implode('.', Util::getVersion());
427
		if (version_compare($currentVersion, $installedVersion, '>')) {
428
			return true;
429
		}
430
		return false;
431
	}
432
433
	/**
434
	 * @param array $disabledApps
435
	 * @throws \Exception
436
	 */
437
	private function upgradeAppStoreApps(array $disabledApps) {
438
		foreach($disabledApps as $app) {
439
			try {
440
				$installer = new Installer(
441
					\OC::$server->getAppFetcher(),
442
					\OC::$server->getHTTPClientService(),
443
					\OC::$server->getTempManager(),
444
					$this->log
445
				);
446
				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...
447
					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
448
					$installer->updateAppstoreApp($app);
449
				}
450
			} catch (\Exception $ex) {
451
				$this->log->logException($ex, ['app' => 'core']);
452
			}
453
		}
454
	}
455
456
	/**
457
	 * Forward messages emitted by the repair routine
458
	 */
459
	private function emitRepairEvents() {
460
		$dispatcher = \OC::$server->getEventDispatcher();
461
		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
462
			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...
463
				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
464
			}
465
		});
466
		$dispatcher->addListener('\OC\Repair::error', function ($event) {
467
			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...
468
				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
469
			}
470
		});
471
		$dispatcher->addListener('\OC\Repair::info', function ($event) {
472
			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...
473
				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
474
			}
475
		});
476
		$dispatcher->addListener('\OC\Repair::step', function ($event) {
477
			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...
478
				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
479
			}
480
		});
481
	}
482
483
	private function logAllEvents() {
484
		$log = $this->log;
485
486
		$dispatcher = \OC::$server->getEventDispatcher();
487 View Code Duplication
		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
			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...
489
				return;
490
			}
491
			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
492
		});
493 View Code Duplication
		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
494
			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...
495
				return;
496
			}
497
			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
498
		});
499
500
		$repairListener = function($event) use ($log) {
501
			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...
502
				return;
503
			}
504
			switch ($event->getSubject()) {
505
				case '\OC\Repair::startProgress':
506
					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
507
					break;
508
				case '\OC\Repair::advance':
509
					$desc = $event->getArgument(1);
510
					if (empty($desc)) {
511
						$desc = '';
512
					}
513
					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
514
515
					break;
516
				case '\OC\Repair::finishProgress':
517
					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
518
					break;
519
				case '\OC\Repair::step':
520
					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
521
					break;
522
				case '\OC\Repair::info':
523
					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
524
					break;
525
				case '\OC\Repair::warning':
526
					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
527
					break;
528
				case '\OC\Repair::error':
529
					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
530
					break;
531
			}
532
		};
533
534
		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
535
		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
536
		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
537
		$dispatcher->addListener('\OC\Repair::step', $repairListener);
538
		$dispatcher->addListener('\OC\Repair::info', $repairListener);
539
		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
540
		$dispatcher->addListener('\OC\Repair::error', $repairListener);
541
542
543
		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
544
			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
545
		});
546
		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
547
			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
548
		});
549
		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
550
			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
551
		});
552
		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
553
			if ($success) {
554
				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
555
			} else {
556
				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
557
			}
558
		});
559
		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
560
			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
561
		});
562
		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
563
			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
564
		});
565
		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
566
			$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']);
567
		});
568
		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
569
			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
570
		});
571
		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
572
			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
573
		});
574
		$this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) {
575
			$log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']);
576
		});
577
		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
578
			$log->info('\OC\Updater::upgradeAppStoreApp: Update 3rd-party app: ' . $app, ['app' => 'updater']);
579
		});
580
		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
581
			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
582
		});
583
		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
584
			$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']);
585
		});
586
		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
587
			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
588
		});
589
		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
590
			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
591
		});
592
		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
593
			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
594
		});
595
		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
596
			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
597
		});
598
		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
599
			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
600
		});
601
		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
602
			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
603
		});
604
		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
605
			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
606
		});
607
		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
608
			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
609
		});
610
611
	}
612
613
}
614
615