Completed
Push — master ( fb77ff...7eb741 )
by Morris
19:26
created
lib/private/legacy/app.php 2 patches
Indentation   +1038 added lines, -1038 removed lines patch added patch discarded remove patch
@@ -64,1042 +64,1042 @@
 block discarded – undo
64 64
  * upgrading and removing apps.
65 65
  */
66 66
 class OC_App {
67
-	static private $adminForms = [];
68
-	static private $personalForms = [];
69
-	static private $appTypes = [];
70
-	static private $loadedApps = [];
71
-	static private $altLogin = [];
72
-	static private $alreadyRegistered = [];
73
-	static public $autoDisabledApps = [];
74
-	const officialApp = 200;
75
-
76
-	/**
77
-	 * clean the appId
78
-	 *
79
-	 * @param string $app AppId that needs to be cleaned
80
-	 * @return string
81
-	 */
82
-	public static function cleanAppId(string $app): string {
83
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
84
-	}
85
-
86
-	/**
87
-	 * Check if an app is loaded
88
-	 *
89
-	 * @param string $app
90
-	 * @return bool
91
-	 */
92
-	public static function isAppLoaded(string $app): bool {
93
-		return in_array($app, self::$loadedApps, true);
94
-	}
95
-
96
-	/**
97
-	 * loads all apps
98
-	 *
99
-	 * @param string[] $types
100
-	 * @return bool
101
-	 *
102
-	 * This function walks through the ownCloud directory and loads all apps
103
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
104
-	 * exists.
105
-	 *
106
-	 * if $types is set to non-empty array, only apps of those types will be loaded
107
-	 */
108
-	public static function loadApps(array $types = []): bool {
109
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
110
-			return false;
111
-		}
112
-		// Load the enabled apps here
113
-		$apps = self::getEnabledApps();
114
-
115
-		// Add each apps' folder as allowed class path
116
-		foreach($apps as $app) {
117
-			$path = self::getAppPath($app);
118
-			if($path !== false) {
119
-				self::registerAutoloading($app, $path);
120
-			}
121
-		}
122
-
123
-		// prevent app.php from printing output
124
-		ob_start();
125
-		foreach ($apps as $app) {
126
-			if (($types === [] or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
127
-				self::loadApp($app);
128
-			}
129
-		}
130
-		ob_end_clean();
131
-
132
-		return true;
133
-	}
134
-
135
-	/**
136
-	 * load a single app
137
-	 *
138
-	 * @param string $app
139
-	 * @throws Exception
140
-	 */
141
-	public static function loadApp(string $app) {
142
-		self::$loadedApps[] = $app;
143
-		$appPath = self::getAppPath($app);
144
-		if($appPath === false) {
145
-			return;
146
-		}
147
-
148
-		// in case someone calls loadApp() directly
149
-		self::registerAutoloading($app, $appPath);
150
-
151
-		if (is_file($appPath . '/appinfo/app.php')) {
152
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
153
-			try {
154
-				self::requireAppFile($app);
155
-			} catch (Error $ex) {
156
-				\OC::$server->getLogger()->logException($ex);
157
-				if (!\OC::$server->getAppManager()->isShipped($app)) {
158
-					// Only disable apps which are not shipped
159
-					\OC::$server->getAppManager()->disableApp($app);
160
-					self::$autoDisabledApps[] = $app;
161
-				}
162
-			}
163
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
164
-		}
165
-
166
-		$info = self::getAppInfo($app);
167
-		if (!empty($info['activity']['filters'])) {
168
-			foreach ($info['activity']['filters'] as $filter) {
169
-				\OC::$server->getActivityManager()->registerFilter($filter);
170
-			}
171
-		}
172
-		if (!empty($info['activity']['settings'])) {
173
-			foreach ($info['activity']['settings'] as $setting) {
174
-				\OC::$server->getActivityManager()->registerSetting($setting);
175
-			}
176
-		}
177
-		if (!empty($info['activity']['providers'])) {
178
-			foreach ($info['activity']['providers'] as $provider) {
179
-				\OC::$server->getActivityManager()->registerProvider($provider);
180
-			}
181
-		}
182
-
183
-		if (!empty($info['settings']['admin'])) {
184
-			foreach ($info['settings']['admin'] as $setting) {
185
-				\OC::$server->getSettingsManager()->registerSetting('admin', $setting);
186
-			}
187
-		}
188
-		if (!empty($info['settings']['admin-section'])) {
189
-			foreach ($info['settings']['admin-section'] as $section) {
190
-				\OC::$server->getSettingsManager()->registerSection('admin', $section);
191
-			}
192
-		}
193
-		if (!empty($info['settings']['personal'])) {
194
-			foreach ($info['settings']['personal'] as $setting) {
195
-				\OC::$server->getSettingsManager()->registerSetting('personal', $setting);
196
-			}
197
-		}
198
-		if (!empty($info['settings']['personal-section'])) {
199
-			foreach ($info['settings']['personal-section'] as $section) {
200
-				\OC::$server->getSettingsManager()->registerSection('personal', $section);
201
-			}
202
-		}
203
-
204
-		if (!empty($info['collaboration']['plugins'])) {
205
-			// deal with one or many plugin entries
206
-			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
207
-				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
208
-			foreach ($plugins as $plugin) {
209
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
210
-					$pluginInfo = [
211
-						'shareType' => $plugin['@attributes']['share-type'],
212
-						'class' => $plugin['@value'],
213
-					];
214
-					\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
215
-				} else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
216
-					\OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
217
-				}
218
-			}
219
-		}
220
-	}
221
-
222
-	/**
223
-	 * @internal
224
-	 * @param string $app
225
-	 * @param string $path
226
-	 */
227
-	public static function registerAutoloading(string $app, string $path) {
228
-		$key = $app . '-' . $path;
229
-		if(isset(self::$alreadyRegistered[$key])) {
230
-			return;
231
-		}
232
-
233
-		self::$alreadyRegistered[$key] = true;
234
-
235
-		// Register on PSR-4 composer autoloader
236
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
237
-		\OC::$server->registerNamespace($app, $appNamespace);
238
-
239
-		if (file_exists($path . '/composer/autoload.php')) {
240
-			require_once $path . '/composer/autoload.php';
241
-		} else {
242
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
243
-			// Register on legacy autoloader
244
-			\OC::$loader->addValidRoot($path);
245
-		}
246
-
247
-		// Register Test namespace only when testing
248
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
249
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
250
-		}
251
-	}
252
-
253
-	/**
254
-	 * Load app.php from the given app
255
-	 *
256
-	 * @param string $app app name
257
-	 * @throws Error
258
-	 */
259
-	private static function requireAppFile(string $app) {
260
-		// encapsulated here to avoid variable scope conflicts
261
-		require_once $app . '/appinfo/app.php';
262
-	}
263
-
264
-	/**
265
-	 * check if an app is of a specific type
266
-	 *
267
-	 * @param string $app
268
-	 * @param array $types
269
-	 * @return bool
270
-	 */
271
-	public static function isType(string $app, array $types): bool {
272
-		$appTypes = self::getAppTypes($app);
273
-		foreach ($types as $type) {
274
-			if (array_search($type, $appTypes) !== false) {
275
-				return true;
276
-			}
277
-		}
278
-		return false;
279
-	}
280
-
281
-	/**
282
-	 * get the types of an app
283
-	 *
284
-	 * @param string $app
285
-	 * @return array
286
-	 */
287
-	private static function getAppTypes(string $app): array {
288
-		//load the cache
289
-		if (count(self::$appTypes) == 0) {
290
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
291
-		}
292
-
293
-		if (isset(self::$appTypes[$app])) {
294
-			return explode(',', self::$appTypes[$app]);
295
-		}
296
-
297
-		return [];
298
-	}
299
-
300
-	/**
301
-	 * read app types from info.xml and cache them in the database
302
-	 */
303
-	public static function setAppTypes(string $app) {
304
-		$appManager = \OC::$server->getAppManager();
305
-		$appData = $appManager->getAppInfo($app);
306
-		if(!is_array($appData)) {
307
-			return;
308
-		}
309
-
310
-		if (isset($appData['types'])) {
311
-			$appTypes = implode(',', $appData['types']);
312
-		} else {
313
-			$appTypes = '';
314
-			$appData['types'] = [];
315
-		}
316
-
317
-		$config = \OC::$server->getConfig();
318
-		$config->setAppValue($app, 'types', $appTypes);
319
-
320
-		if ($appManager->hasProtectedAppType($appData['types'])) {
321
-			$enabled = $config->getAppValue($app, 'enabled', 'yes');
322
-			if ($enabled !== 'yes' && $enabled !== 'no') {
323
-				$config->setAppValue($app, 'enabled', 'yes');
324
-			}
325
-		}
326
-	}
327
-
328
-	/**
329
-	 * Returns apps enabled for the current user.
330
-	 *
331
-	 * @param bool $forceRefresh whether to refresh the cache
332
-	 * @param bool $all whether to return apps for all users, not only the
333
-	 * currently logged in one
334
-	 * @return string[]
335
-	 */
336
-	public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
337
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
338
-			return [];
339
-		}
340
-		// in incognito mode or when logged out, $user will be false,
341
-		// which is also the case during an upgrade
342
-		$appManager = \OC::$server->getAppManager();
343
-		if ($all) {
344
-			$user = null;
345
-		} else {
346
-			$user = \OC::$server->getUserSession()->getUser();
347
-		}
348
-
349
-		if (is_null($user)) {
350
-			$apps = $appManager->getInstalledApps();
351
-		} else {
352
-			$apps = $appManager->getEnabledAppsForUser($user);
353
-		}
354
-		$apps = array_filter($apps, function ($app) {
355
-			return $app !== 'files';//we add this manually
356
-		});
357
-		sort($apps);
358
-		array_unshift($apps, 'files');
359
-		return $apps;
360
-	}
361
-
362
-	/**
363
-	 * checks whether or not an app is enabled
364
-	 *
365
-	 * @param string $app app
366
-	 * @return bool
367
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
368
-	 *
369
-	 * This function checks whether or not an app is enabled.
370
-	 */
371
-	public static function isEnabled(string $app): bool {
372
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
373
-	}
374
-
375
-	/**
376
-	 * enables an app
377
-	 *
378
-	 * @param string $appId
379
-	 * @param array $groups (optional) when set, only these groups will have access to the app
380
-	 * @throws \Exception
381
-	 * @return void
382
-	 *
383
-	 * This function set an app as enabled in appconfig.
384
-	 */
385
-	public function enable(string $appId,
386
-						   array $groups = []) {
387
-
388
-		// Check if app is already downloaded
389
-		/** @var Installer $installer */
390
-		$installer = \OC::$server->query(Installer::class);
391
-		$isDownloaded = $installer->isDownloaded($appId);
392
-
393
-		if(!$isDownloaded) {
394
-			$installer->downloadApp($appId);
395
-		}
396
-
397
-		$installer->installApp($appId);
398
-
399
-		$appManager = \OC::$server->getAppManager();
400
-		if ($groups !== []) {
401
-			$groupManager = \OC::$server->getGroupManager();
402
-			$groupsList = [];
403
-			foreach ($groups as $group) {
404
-				$groupItem = $groupManager->get($group);
405
-				if ($groupItem instanceof \OCP\IGroup) {
406
-					$groupsList[] = $groupManager->get($group);
407
-				}
408
-			}
409
-			$appManager->enableAppForGroups($appId, $groupsList);
410
-		} else {
411
-			$appManager->enableApp($appId);
412
-		}
413
-	}
414
-
415
-	/**
416
-	 * Get the path where to install apps
417
-	 *
418
-	 * @return string|false
419
-	 */
420
-	public static function getInstallPath() {
421
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
422
-			return false;
423
-		}
424
-
425
-		foreach (OC::$APPSROOTS as $dir) {
426
-			if (isset($dir['writable']) && $dir['writable'] === true) {
427
-				return $dir['path'];
428
-			}
429
-		}
430
-
431
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR);
432
-		return null;
433
-	}
434
-
435
-
436
-	/**
437
-	 * search for an app in all app-directories
438
-	 *
439
-	 * @param string $appId
440
-	 * @return false|string
441
-	 */
442
-	public static function findAppInDirectories(string $appId) {
443
-		$sanitizedAppId = self::cleanAppId($appId);
444
-		if($sanitizedAppId !== $appId) {
445
-			return false;
446
-		}
447
-		static $app_dir = [];
448
-
449
-		if (isset($app_dir[$appId])) {
450
-			return $app_dir[$appId];
451
-		}
452
-
453
-		$possibleApps = [];
454
-		foreach (OC::$APPSROOTS as $dir) {
455
-			if (file_exists($dir['path'] . '/' . $appId)) {
456
-				$possibleApps[] = $dir;
457
-			}
458
-		}
459
-
460
-		if (empty($possibleApps)) {
461
-			return false;
462
-		} elseif (count($possibleApps) === 1) {
463
-			$dir = array_shift($possibleApps);
464
-			$app_dir[$appId] = $dir;
465
-			return $dir;
466
-		} else {
467
-			$versionToLoad = [];
468
-			foreach ($possibleApps as $possibleApp) {
469
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
470
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
471
-					$versionToLoad = array(
472
-						'dir' => $possibleApp,
473
-						'version' => $version,
474
-					);
475
-				}
476
-			}
477
-			$app_dir[$appId] = $versionToLoad['dir'];
478
-			return $versionToLoad['dir'];
479
-			//TODO - write test
480
-		}
481
-	}
482
-
483
-	/**
484
-	 * Get the directory for the given app.
485
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
486
-	 *
487
-	 * @param string $appId
488
-	 * @return string|false
489
-	 */
490
-	public static function getAppPath(string $appId) {
491
-		if ($appId === null || trim($appId) === '') {
492
-			return false;
493
-		}
494
-
495
-		if (($dir = self::findAppInDirectories($appId)) != false) {
496
-			return $dir['path'] . '/' . $appId;
497
-		}
498
-		return false;
499
-	}
500
-
501
-	/**
502
-	 * Get the path for the given app on the access
503
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
504
-	 *
505
-	 * @param string $appId
506
-	 * @return string|false
507
-	 */
508
-	public static function getAppWebPath(string $appId) {
509
-		if (($dir = self::findAppInDirectories($appId)) != false) {
510
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
511
-		}
512
-		return false;
513
-	}
514
-
515
-	/**
516
-	 * get the last version of the app from appinfo/info.xml
517
-	 *
518
-	 * @param string $appId
519
-	 * @param bool $useCache
520
-	 * @return string
521
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
522
-	 */
523
-	public static function getAppVersion(string $appId, bool $useCache = true): string {
524
-		return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
525
-	}
526
-
527
-	/**
528
-	 * get app's version based on it's path
529
-	 *
530
-	 * @param string $path
531
-	 * @return string
532
-	 */
533
-	public static function getAppVersionByPath(string $path): string {
534
-		$infoFile = $path . '/appinfo/info.xml';
535
-		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
536
-		return isset($appData['version']) ? $appData['version'] : '';
537
-	}
538
-
539
-
540
-	/**
541
-	 * Read all app metadata from the info.xml file
542
-	 *
543
-	 * @param string $appId id of the app or the path of the info.xml file
544
-	 * @param bool $path
545
-	 * @param string $lang
546
-	 * @return array|null
547
-	 * @note all data is read from info.xml, not just pre-defined fields
548
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
549
-	 */
550
-	public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
551
-		return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
552
-	}
553
-
554
-	/**
555
-	 * Returns the navigation
556
-	 *
557
-	 * @return array
558
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
559
-	 *
560
-	 * This function returns an array containing all entries added. The
561
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
562
-	 * given for each app the following keys exist:
563
-	 *   - active: boolean, signals if the user is on this navigation entry
564
-	 */
565
-	public static function getNavigation(): array {
566
-		return OC::$server->getNavigationManager()->getAll();
567
-	}
568
-
569
-	/**
570
-	 * Returns the Settings Navigation
571
-	 *
572
-	 * @return string[]
573
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
574
-	 *
575
-	 * This function returns an array containing all settings pages added. The
576
-	 * entries are sorted by the key 'order' ascending.
577
-	 */
578
-	public static function getSettingsNavigation(): array {
579
-		return OC::$server->getNavigationManager()->getAll('settings');
580
-	}
581
-
582
-	/**
583
-	 * get the id of loaded app
584
-	 *
585
-	 * @return string
586
-	 */
587
-	public static function getCurrentApp(): string {
588
-		$request = \OC::$server->getRequest();
589
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
590
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
591
-		if (empty($topFolder)) {
592
-			$path_info = $request->getPathInfo();
593
-			if ($path_info) {
594
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
595
-			}
596
-		}
597
-		if ($topFolder == 'apps') {
598
-			$length = strlen($topFolder);
599
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
600
-		} else {
601
-			return $topFolder;
602
-		}
603
-	}
604
-
605
-	/**
606
-	 * @param string $type
607
-	 * @return array
608
-	 */
609
-	public static function getForms(string $type): array {
610
-		$forms = [];
611
-		switch ($type) {
612
-			case 'admin':
613
-				$source = self::$adminForms;
614
-				break;
615
-			case 'personal':
616
-				$source = self::$personalForms;
617
-				break;
618
-			default:
619
-				return [];
620
-		}
621
-		foreach ($source as $form) {
622
-			$forms[] = include $form;
623
-		}
624
-		return $forms;
625
-	}
626
-
627
-	/**
628
-	 * register an admin form to be shown
629
-	 *
630
-	 * @param string $app
631
-	 * @param string $page
632
-	 */
633
-	public static function registerAdmin(string $app, string $page) {
634
-		self::$adminForms[] = $app . '/' . $page . '.php';
635
-	}
636
-
637
-	/**
638
-	 * register a personal form to be shown
639
-	 * @param string $app
640
-	 * @param string $page
641
-	 */
642
-	public static function registerPersonal(string $app, string $page) {
643
-		self::$personalForms[] = $app . '/' . $page . '.php';
644
-	}
645
-
646
-	/**
647
-	 * @param array $entry
648
-	 */
649
-	public static function registerLogIn(array $entry) {
650
-		self::$altLogin[] = $entry;
651
-	}
652
-
653
-	/**
654
-	 * @return array
655
-	 */
656
-	public static function getAlternativeLogIns(): array {
657
-		return self::$altLogin;
658
-	}
659
-
660
-	/**
661
-	 * get a list of all apps in the apps folder
662
-	 *
663
-	 * @return array an array of app names (string IDs)
664
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
665
-	 */
666
-	public static function getAllApps(): array {
667
-
668
-		$apps = [];
669
-
670
-		foreach (OC::$APPSROOTS as $apps_dir) {
671
-			if (!is_readable($apps_dir['path'])) {
672
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
673
-				continue;
674
-			}
675
-			$dh = opendir($apps_dir['path']);
676
-
677
-			if (is_resource($dh)) {
678
-				while (($file = readdir($dh)) !== false) {
679
-
680
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
681
-
682
-						$apps[] = $file;
683
-					}
684
-				}
685
-			}
686
-		}
687
-
688
-		$apps = array_unique($apps);
689
-
690
-		return $apps;
691
-	}
692
-
693
-	/**
694
-	 * List all apps, this is used in apps.php
695
-	 *
696
-	 * @return array
697
-	 */
698
-	public function listAllApps(): array {
699
-		$installedApps = OC_App::getAllApps();
700
-
701
-		$appManager = \OC::$server->getAppManager();
702
-		//we don't want to show configuration for these
703
-		$blacklist = $appManager->getAlwaysEnabledApps();
704
-		$appList = [];
705
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
706
-		$urlGenerator = \OC::$server->getURLGenerator();
707
-
708
-		foreach ($installedApps as $app) {
709
-			if (array_search($app, $blacklist) === false) {
710
-
711
-				$info = OC_App::getAppInfo($app, false, $langCode);
712
-				if (!is_array($info)) {
713
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
714
-					continue;
715
-				}
716
-
717
-				if (!isset($info['name'])) {
718
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
719
-					continue;
720
-				}
721
-
722
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
723
-				$info['groups'] = null;
724
-				if ($enabled === 'yes') {
725
-					$active = true;
726
-				} else if ($enabled === 'no') {
727
-					$active = false;
728
-				} else {
729
-					$active = true;
730
-					$info['groups'] = $enabled;
731
-				}
732
-
733
-				$info['active'] = $active;
734
-
735
-				if ($appManager->isShipped($app)) {
736
-					$info['internal'] = true;
737
-					$info['level'] = self::officialApp;
738
-					$info['removable'] = false;
739
-				} else {
740
-					$info['internal'] = false;
741
-					$info['removable'] = true;
742
-				}
743
-
744
-				$appPath = self::getAppPath($app);
745
-				if($appPath !== false) {
746
-					$appIcon = $appPath . '/img/' . $app . '.svg';
747
-					if (file_exists($appIcon)) {
748
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
749
-						$info['previewAsIcon'] = true;
750
-					} else {
751
-						$appIcon = $appPath . '/img/app.svg';
752
-						if (file_exists($appIcon)) {
753
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
754
-							$info['previewAsIcon'] = true;
755
-						}
756
-					}
757
-				}
758
-				// fix documentation
759
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
760
-					foreach ($info['documentation'] as $key => $url) {
761
-						// If it is not an absolute URL we assume it is a key
762
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
763
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
764
-							$url = $urlGenerator->linkToDocs($url);
765
-						}
766
-
767
-						$info['documentation'][$key] = $url;
768
-					}
769
-				}
770
-
771
-				$info['version'] = OC_App::getAppVersion($app);
772
-				$appList[] = $info;
773
-			}
774
-		}
775
-
776
-		return $appList;
777
-	}
778
-
779
-	public static function shouldUpgrade(string $app): bool {
780
-		$versions = self::getAppVersions();
781
-		$currentVersion = OC_App::getAppVersion($app);
782
-		if ($currentVersion && isset($versions[$app])) {
783
-			$installedVersion = $versions[$app];
784
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
785
-				return true;
786
-			}
787
-		}
788
-		return false;
789
-	}
790
-
791
-	/**
792
-	 * Adjust the number of version parts of $version1 to match
793
-	 * the number of version parts of $version2.
794
-	 *
795
-	 * @param string $version1 version to adjust
796
-	 * @param string $version2 version to take the number of parts from
797
-	 * @return string shortened $version1
798
-	 */
799
-	private static function adjustVersionParts(string $version1, string $version2): string {
800
-		$version1 = explode('.', $version1);
801
-		$version2 = explode('.', $version2);
802
-		// reduce $version1 to match the number of parts in $version2
803
-		while (count($version1) > count($version2)) {
804
-			array_pop($version1);
805
-		}
806
-		// if $version1 does not have enough parts, add some
807
-		while (count($version1) < count($version2)) {
808
-			$version1[] = '0';
809
-		}
810
-		return implode('.', $version1);
811
-	}
812
-
813
-	/**
814
-	 * Check whether the current ownCloud version matches the given
815
-	 * application's version requirements.
816
-	 *
817
-	 * The comparison is made based on the number of parts that the
818
-	 * app info version has. For example for ownCloud 6.0.3 if the
819
-	 * app info version is expecting version 6.0, the comparison is
820
-	 * made on the first two parts of the ownCloud version.
821
-	 * This means that it's possible to specify "requiremin" => 6
822
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
823
-	 *
824
-	 * @param string $ocVersion ownCloud version to check against
825
-	 * @param array $appInfo app info (from xml)
826
-	 *
827
-	 * @return boolean true if compatible, otherwise false
828
-	 */
829
-	public static function isAppCompatible(string $ocVersion, array $appInfo): bool {
830
-		$requireMin = '';
831
-		$requireMax = '';
832
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
833
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
834
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
835
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
836
-		} else if (isset($appInfo['requiremin'])) {
837
-			$requireMin = $appInfo['requiremin'];
838
-		} else if (isset($appInfo['require'])) {
839
-			$requireMin = $appInfo['require'];
840
-		}
841
-
842
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
843
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
844
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
845
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
846
-		} else if (isset($appInfo['requiremax'])) {
847
-			$requireMax = $appInfo['requiremax'];
848
-		}
849
-
850
-		if (!empty($requireMin)
851
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
852
-		) {
853
-
854
-			return false;
855
-		}
856
-
857
-		if (!empty($requireMax)
858
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
859
-		) {
860
-			return false;
861
-		}
862
-
863
-		return true;
864
-	}
865
-
866
-	/**
867
-	 * get the installed version of all apps
868
-	 */
869
-	public static function getAppVersions() {
870
-		static $versions;
871
-
872
-		if(!$versions) {
873
-			$appConfig = \OC::$server->getAppConfig();
874
-			$versions = $appConfig->getValues(false, 'installed_version');
875
-		}
876
-		return $versions;
877
-	}
878
-
879
-	/**
880
-	 * update the database for the app and call the update script
881
-	 *
882
-	 * @param string $appId
883
-	 * @return bool
884
-	 */
885
-	public static function updateApp(string $appId): bool {
886
-		$appPath = self::getAppPath($appId);
887
-		if($appPath === false) {
888
-			return false;
889
-		}
890
-		self::registerAutoloading($appId, $appPath);
891
-
892
-		\OC::$server->getAppManager()->clearAppsCache();
893
-		$appData = self::getAppInfo($appId);
894
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
895
-
896
-		if (file_exists($appPath . '/appinfo/database.xml')) {
897
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
898
-		} else {
899
-			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
900
-			$ms->migrate();
901
-		}
902
-
903
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
904
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
905
-		// update appversion in app manager
906
-		\OC::$server->getAppManager()->clearAppsCache();
907
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
908
-
909
-		// run upgrade code
910
-		if (file_exists($appPath . '/appinfo/update.php')) {
911
-			self::loadApp($appId);
912
-			include $appPath . '/appinfo/update.php';
913
-		}
914
-		self::setupBackgroundJobs($appData['background-jobs']);
915
-
916
-		//set remote/public handlers
917
-		if (array_key_exists('ocsid', $appData)) {
918
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
919
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
920
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
921
-		}
922
-		foreach ($appData['remote'] as $name => $path) {
923
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
924
-		}
925
-		foreach ($appData['public'] as $name => $path) {
926
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
927
-		}
928
-
929
-		self::setAppTypes($appId);
930
-
931
-		$version = \OC_App::getAppVersion($appId);
932
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
933
-
934
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
935
-			ManagerEvent::EVENT_APP_UPDATE, $appId
936
-		));
937
-
938
-		return true;
939
-	}
940
-
941
-	/**
942
-	 * @param string $appId
943
-	 * @param string[] $steps
944
-	 * @throws \OC\NeedsUpdateException
945
-	 */
946
-	public static function executeRepairSteps(string $appId, array $steps) {
947
-		if (empty($steps)) {
948
-			return;
949
-		}
950
-		// load the app
951
-		self::loadApp($appId);
952
-
953
-		$dispatcher = OC::$server->getEventDispatcher();
954
-
955
-		// load the steps
956
-		$r = new Repair([], $dispatcher);
957
-		foreach ($steps as $step) {
958
-			try {
959
-				$r->addStep($step);
960
-			} catch (Exception $ex) {
961
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
962
-				\OC::$server->getLogger()->logException($ex);
963
-			}
964
-		}
965
-		// run the steps
966
-		$r->run();
967
-	}
968
-
969
-	public static function setupBackgroundJobs(array $jobs) {
970
-		$queue = \OC::$server->getJobList();
971
-		foreach ($jobs as $job) {
972
-			$queue->add($job);
973
-		}
974
-	}
975
-
976
-	/**
977
-	 * @param string $appId
978
-	 * @param string[] $steps
979
-	 */
980
-	private static function setupLiveMigrations(string $appId, array $steps) {
981
-		$queue = \OC::$server->getJobList();
982
-		foreach ($steps as $step) {
983
-			$queue->add('OC\Migration\BackgroundRepair', [
984
-				'app' => $appId,
985
-				'step' => $step]);
986
-		}
987
-	}
988
-
989
-	/**
990
-	 * @param string $appId
991
-	 * @return \OC\Files\View|false
992
-	 */
993
-	public static function getStorage(string $appId) {
994
-		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
995
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
996
-				$view = new \OC\Files\View('/' . OC_User::getUser());
997
-				if (!$view->file_exists($appId)) {
998
-					$view->mkdir($appId);
999
-				}
1000
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1001
-			} else {
1002
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1003
-				return false;
1004
-			}
1005
-		} else {
1006
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1007
-			return false;
1008
-		}
1009
-	}
1010
-
1011
-	protected static function findBestL10NOption(array $options, string $lang): string {
1012
-		// only a single option
1013
-		if (isset($options['@value'])) {
1014
-			return $options['@value'];
1015
-		}
1016
-
1017
-		$fallback = $similarLangFallback = $englishFallback = false;
1018
-
1019
-		$lang = strtolower($lang);
1020
-		$similarLang = $lang;
1021
-		if (strpos($similarLang, '_')) {
1022
-			// For "de_DE" we want to find "de" and the other way around
1023
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1024
-		}
1025
-
1026
-		foreach ($options as $option) {
1027
-			if (is_array($option)) {
1028
-				if ($fallback === false) {
1029
-					$fallback = $option['@value'];
1030
-				}
1031
-
1032
-				if (!isset($option['@attributes']['lang'])) {
1033
-					continue;
1034
-				}
1035
-
1036
-				$attributeLang = strtolower($option['@attributes']['lang']);
1037
-				if ($attributeLang === $lang) {
1038
-					return $option['@value'];
1039
-				}
1040
-
1041
-				if ($attributeLang === $similarLang) {
1042
-					$similarLangFallback = $option['@value'];
1043
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1044
-					if ($similarLangFallback === false) {
1045
-						$similarLangFallback =  $option['@value'];
1046
-					}
1047
-				}
1048
-			} else {
1049
-				$englishFallback = $option;
1050
-			}
1051
-		}
1052
-
1053
-		if ($similarLangFallback !== false) {
1054
-			return $similarLangFallback;
1055
-		} else if ($englishFallback !== false) {
1056
-			return $englishFallback;
1057
-		}
1058
-		return (string) $fallback;
1059
-	}
1060
-
1061
-	/**
1062
-	 * parses the app data array and enhanced the 'description' value
1063
-	 *
1064
-	 * @param array $data the app data
1065
-	 * @param string $lang
1066
-	 * @return array improved app data
1067
-	 */
1068
-	public static function parseAppInfo(array $data, $lang = null): array {
1069
-
1070
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1071
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1072
-		}
1073
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1074
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1075
-		}
1076
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1077
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1078
-		} else if (isset($data['description']) && is_string($data['description'])) {
1079
-			$data['description'] = trim($data['description']);
1080
-		} else  {
1081
-			$data['description'] = '';
1082
-		}
1083
-
1084
-		return $data;
1085
-	}
1086
-
1087
-	/**
1088
-	 * @param \OCP\IConfig $config
1089
-	 * @param \OCP\IL10N $l
1090
-	 * @param array $info
1091
-	 * @throws \Exception
1092
-	 */
1093
-	public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info) {
1094
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1095
-		$missing = $dependencyAnalyzer->analyze($info);
1096
-		if (!empty($missing)) {
1097
-			$missingMsg = implode(PHP_EOL, $missing);
1098
-			throw new \Exception(
1099
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1100
-					[$info['name'], $missingMsg]
1101
-				)
1102
-			);
1103
-		}
1104
-	}
67
+    static private $adminForms = [];
68
+    static private $personalForms = [];
69
+    static private $appTypes = [];
70
+    static private $loadedApps = [];
71
+    static private $altLogin = [];
72
+    static private $alreadyRegistered = [];
73
+    static public $autoDisabledApps = [];
74
+    const officialApp = 200;
75
+
76
+    /**
77
+     * clean the appId
78
+     *
79
+     * @param string $app AppId that needs to be cleaned
80
+     * @return string
81
+     */
82
+    public static function cleanAppId(string $app): string {
83
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
84
+    }
85
+
86
+    /**
87
+     * Check if an app is loaded
88
+     *
89
+     * @param string $app
90
+     * @return bool
91
+     */
92
+    public static function isAppLoaded(string $app): bool {
93
+        return in_array($app, self::$loadedApps, true);
94
+    }
95
+
96
+    /**
97
+     * loads all apps
98
+     *
99
+     * @param string[] $types
100
+     * @return bool
101
+     *
102
+     * This function walks through the ownCloud directory and loads all apps
103
+     * it can find. A directory contains an app if the file /appinfo/info.xml
104
+     * exists.
105
+     *
106
+     * if $types is set to non-empty array, only apps of those types will be loaded
107
+     */
108
+    public static function loadApps(array $types = []): bool {
109
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
110
+            return false;
111
+        }
112
+        // Load the enabled apps here
113
+        $apps = self::getEnabledApps();
114
+
115
+        // Add each apps' folder as allowed class path
116
+        foreach($apps as $app) {
117
+            $path = self::getAppPath($app);
118
+            if($path !== false) {
119
+                self::registerAutoloading($app, $path);
120
+            }
121
+        }
122
+
123
+        // prevent app.php from printing output
124
+        ob_start();
125
+        foreach ($apps as $app) {
126
+            if (($types === [] or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
127
+                self::loadApp($app);
128
+            }
129
+        }
130
+        ob_end_clean();
131
+
132
+        return true;
133
+    }
134
+
135
+    /**
136
+     * load a single app
137
+     *
138
+     * @param string $app
139
+     * @throws Exception
140
+     */
141
+    public static function loadApp(string $app) {
142
+        self::$loadedApps[] = $app;
143
+        $appPath = self::getAppPath($app);
144
+        if($appPath === false) {
145
+            return;
146
+        }
147
+
148
+        // in case someone calls loadApp() directly
149
+        self::registerAutoloading($app, $appPath);
150
+
151
+        if (is_file($appPath . '/appinfo/app.php')) {
152
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
153
+            try {
154
+                self::requireAppFile($app);
155
+            } catch (Error $ex) {
156
+                \OC::$server->getLogger()->logException($ex);
157
+                if (!\OC::$server->getAppManager()->isShipped($app)) {
158
+                    // Only disable apps which are not shipped
159
+                    \OC::$server->getAppManager()->disableApp($app);
160
+                    self::$autoDisabledApps[] = $app;
161
+                }
162
+            }
163
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
164
+        }
165
+
166
+        $info = self::getAppInfo($app);
167
+        if (!empty($info['activity']['filters'])) {
168
+            foreach ($info['activity']['filters'] as $filter) {
169
+                \OC::$server->getActivityManager()->registerFilter($filter);
170
+            }
171
+        }
172
+        if (!empty($info['activity']['settings'])) {
173
+            foreach ($info['activity']['settings'] as $setting) {
174
+                \OC::$server->getActivityManager()->registerSetting($setting);
175
+            }
176
+        }
177
+        if (!empty($info['activity']['providers'])) {
178
+            foreach ($info['activity']['providers'] as $provider) {
179
+                \OC::$server->getActivityManager()->registerProvider($provider);
180
+            }
181
+        }
182
+
183
+        if (!empty($info['settings']['admin'])) {
184
+            foreach ($info['settings']['admin'] as $setting) {
185
+                \OC::$server->getSettingsManager()->registerSetting('admin', $setting);
186
+            }
187
+        }
188
+        if (!empty($info['settings']['admin-section'])) {
189
+            foreach ($info['settings']['admin-section'] as $section) {
190
+                \OC::$server->getSettingsManager()->registerSection('admin', $section);
191
+            }
192
+        }
193
+        if (!empty($info['settings']['personal'])) {
194
+            foreach ($info['settings']['personal'] as $setting) {
195
+                \OC::$server->getSettingsManager()->registerSetting('personal', $setting);
196
+            }
197
+        }
198
+        if (!empty($info['settings']['personal-section'])) {
199
+            foreach ($info['settings']['personal-section'] as $section) {
200
+                \OC::$server->getSettingsManager()->registerSection('personal', $section);
201
+            }
202
+        }
203
+
204
+        if (!empty($info['collaboration']['plugins'])) {
205
+            // deal with one or many plugin entries
206
+            $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
207
+                [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
208
+            foreach ($plugins as $plugin) {
209
+                if($plugin['@attributes']['type'] === 'collaborator-search') {
210
+                    $pluginInfo = [
211
+                        'shareType' => $plugin['@attributes']['share-type'],
212
+                        'class' => $plugin['@value'],
213
+                    ];
214
+                    \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
215
+                } else if ($plugin['@attributes']['type'] === 'autocomplete-sort') {
216
+                    \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
217
+                }
218
+            }
219
+        }
220
+    }
221
+
222
+    /**
223
+     * @internal
224
+     * @param string $app
225
+     * @param string $path
226
+     */
227
+    public static function registerAutoloading(string $app, string $path) {
228
+        $key = $app . '-' . $path;
229
+        if(isset(self::$alreadyRegistered[$key])) {
230
+            return;
231
+        }
232
+
233
+        self::$alreadyRegistered[$key] = true;
234
+
235
+        // Register on PSR-4 composer autoloader
236
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
237
+        \OC::$server->registerNamespace($app, $appNamespace);
238
+
239
+        if (file_exists($path . '/composer/autoload.php')) {
240
+            require_once $path . '/composer/autoload.php';
241
+        } else {
242
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
243
+            // Register on legacy autoloader
244
+            \OC::$loader->addValidRoot($path);
245
+        }
246
+
247
+        // Register Test namespace only when testing
248
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
249
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
250
+        }
251
+    }
252
+
253
+    /**
254
+     * Load app.php from the given app
255
+     *
256
+     * @param string $app app name
257
+     * @throws Error
258
+     */
259
+    private static function requireAppFile(string $app) {
260
+        // encapsulated here to avoid variable scope conflicts
261
+        require_once $app . '/appinfo/app.php';
262
+    }
263
+
264
+    /**
265
+     * check if an app is of a specific type
266
+     *
267
+     * @param string $app
268
+     * @param array $types
269
+     * @return bool
270
+     */
271
+    public static function isType(string $app, array $types): bool {
272
+        $appTypes = self::getAppTypes($app);
273
+        foreach ($types as $type) {
274
+            if (array_search($type, $appTypes) !== false) {
275
+                return true;
276
+            }
277
+        }
278
+        return false;
279
+    }
280
+
281
+    /**
282
+     * get the types of an app
283
+     *
284
+     * @param string $app
285
+     * @return array
286
+     */
287
+    private static function getAppTypes(string $app): array {
288
+        //load the cache
289
+        if (count(self::$appTypes) == 0) {
290
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
291
+        }
292
+
293
+        if (isset(self::$appTypes[$app])) {
294
+            return explode(',', self::$appTypes[$app]);
295
+        }
296
+
297
+        return [];
298
+    }
299
+
300
+    /**
301
+     * read app types from info.xml and cache them in the database
302
+     */
303
+    public static function setAppTypes(string $app) {
304
+        $appManager = \OC::$server->getAppManager();
305
+        $appData = $appManager->getAppInfo($app);
306
+        if(!is_array($appData)) {
307
+            return;
308
+        }
309
+
310
+        if (isset($appData['types'])) {
311
+            $appTypes = implode(',', $appData['types']);
312
+        } else {
313
+            $appTypes = '';
314
+            $appData['types'] = [];
315
+        }
316
+
317
+        $config = \OC::$server->getConfig();
318
+        $config->setAppValue($app, 'types', $appTypes);
319
+
320
+        if ($appManager->hasProtectedAppType($appData['types'])) {
321
+            $enabled = $config->getAppValue($app, 'enabled', 'yes');
322
+            if ($enabled !== 'yes' && $enabled !== 'no') {
323
+                $config->setAppValue($app, 'enabled', 'yes');
324
+            }
325
+        }
326
+    }
327
+
328
+    /**
329
+     * Returns apps enabled for the current user.
330
+     *
331
+     * @param bool $forceRefresh whether to refresh the cache
332
+     * @param bool $all whether to return apps for all users, not only the
333
+     * currently logged in one
334
+     * @return string[]
335
+     */
336
+    public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
337
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
338
+            return [];
339
+        }
340
+        // in incognito mode or when logged out, $user will be false,
341
+        // which is also the case during an upgrade
342
+        $appManager = \OC::$server->getAppManager();
343
+        if ($all) {
344
+            $user = null;
345
+        } else {
346
+            $user = \OC::$server->getUserSession()->getUser();
347
+        }
348
+
349
+        if (is_null($user)) {
350
+            $apps = $appManager->getInstalledApps();
351
+        } else {
352
+            $apps = $appManager->getEnabledAppsForUser($user);
353
+        }
354
+        $apps = array_filter($apps, function ($app) {
355
+            return $app !== 'files';//we add this manually
356
+        });
357
+        sort($apps);
358
+        array_unshift($apps, 'files');
359
+        return $apps;
360
+    }
361
+
362
+    /**
363
+     * checks whether or not an app is enabled
364
+     *
365
+     * @param string $app app
366
+     * @return bool
367
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
368
+     *
369
+     * This function checks whether or not an app is enabled.
370
+     */
371
+    public static function isEnabled(string $app): bool {
372
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
373
+    }
374
+
375
+    /**
376
+     * enables an app
377
+     *
378
+     * @param string $appId
379
+     * @param array $groups (optional) when set, only these groups will have access to the app
380
+     * @throws \Exception
381
+     * @return void
382
+     *
383
+     * This function set an app as enabled in appconfig.
384
+     */
385
+    public function enable(string $appId,
386
+                            array $groups = []) {
387
+
388
+        // Check if app is already downloaded
389
+        /** @var Installer $installer */
390
+        $installer = \OC::$server->query(Installer::class);
391
+        $isDownloaded = $installer->isDownloaded($appId);
392
+
393
+        if(!$isDownloaded) {
394
+            $installer->downloadApp($appId);
395
+        }
396
+
397
+        $installer->installApp($appId);
398
+
399
+        $appManager = \OC::$server->getAppManager();
400
+        if ($groups !== []) {
401
+            $groupManager = \OC::$server->getGroupManager();
402
+            $groupsList = [];
403
+            foreach ($groups as $group) {
404
+                $groupItem = $groupManager->get($group);
405
+                if ($groupItem instanceof \OCP\IGroup) {
406
+                    $groupsList[] = $groupManager->get($group);
407
+                }
408
+            }
409
+            $appManager->enableAppForGroups($appId, $groupsList);
410
+        } else {
411
+            $appManager->enableApp($appId);
412
+        }
413
+    }
414
+
415
+    /**
416
+     * Get the path where to install apps
417
+     *
418
+     * @return string|false
419
+     */
420
+    public static function getInstallPath() {
421
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
422
+            return false;
423
+        }
424
+
425
+        foreach (OC::$APPSROOTS as $dir) {
426
+            if (isset($dir['writable']) && $dir['writable'] === true) {
427
+                return $dir['path'];
428
+            }
429
+        }
430
+
431
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR);
432
+        return null;
433
+    }
434
+
435
+
436
+    /**
437
+     * search for an app in all app-directories
438
+     *
439
+     * @param string $appId
440
+     * @return false|string
441
+     */
442
+    public static function findAppInDirectories(string $appId) {
443
+        $sanitizedAppId = self::cleanAppId($appId);
444
+        if($sanitizedAppId !== $appId) {
445
+            return false;
446
+        }
447
+        static $app_dir = [];
448
+
449
+        if (isset($app_dir[$appId])) {
450
+            return $app_dir[$appId];
451
+        }
452
+
453
+        $possibleApps = [];
454
+        foreach (OC::$APPSROOTS as $dir) {
455
+            if (file_exists($dir['path'] . '/' . $appId)) {
456
+                $possibleApps[] = $dir;
457
+            }
458
+        }
459
+
460
+        if (empty($possibleApps)) {
461
+            return false;
462
+        } elseif (count($possibleApps) === 1) {
463
+            $dir = array_shift($possibleApps);
464
+            $app_dir[$appId] = $dir;
465
+            return $dir;
466
+        } else {
467
+            $versionToLoad = [];
468
+            foreach ($possibleApps as $possibleApp) {
469
+                $version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
470
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
471
+                    $versionToLoad = array(
472
+                        'dir' => $possibleApp,
473
+                        'version' => $version,
474
+                    );
475
+                }
476
+            }
477
+            $app_dir[$appId] = $versionToLoad['dir'];
478
+            return $versionToLoad['dir'];
479
+            //TODO - write test
480
+        }
481
+    }
482
+
483
+    /**
484
+     * Get the directory for the given app.
485
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
486
+     *
487
+     * @param string $appId
488
+     * @return string|false
489
+     */
490
+    public static function getAppPath(string $appId) {
491
+        if ($appId === null || trim($appId) === '') {
492
+            return false;
493
+        }
494
+
495
+        if (($dir = self::findAppInDirectories($appId)) != false) {
496
+            return $dir['path'] . '/' . $appId;
497
+        }
498
+        return false;
499
+    }
500
+
501
+    /**
502
+     * Get the path for the given app on the access
503
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
504
+     *
505
+     * @param string $appId
506
+     * @return string|false
507
+     */
508
+    public static function getAppWebPath(string $appId) {
509
+        if (($dir = self::findAppInDirectories($appId)) != false) {
510
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
511
+        }
512
+        return false;
513
+    }
514
+
515
+    /**
516
+     * get the last version of the app from appinfo/info.xml
517
+     *
518
+     * @param string $appId
519
+     * @param bool $useCache
520
+     * @return string
521
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
522
+     */
523
+    public static function getAppVersion(string $appId, bool $useCache = true): string {
524
+        return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
525
+    }
526
+
527
+    /**
528
+     * get app's version based on it's path
529
+     *
530
+     * @param string $path
531
+     * @return string
532
+     */
533
+    public static function getAppVersionByPath(string $path): string {
534
+        $infoFile = $path . '/appinfo/info.xml';
535
+        $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
536
+        return isset($appData['version']) ? $appData['version'] : '';
537
+    }
538
+
539
+
540
+    /**
541
+     * Read all app metadata from the info.xml file
542
+     *
543
+     * @param string $appId id of the app or the path of the info.xml file
544
+     * @param bool $path
545
+     * @param string $lang
546
+     * @return array|null
547
+     * @note all data is read from info.xml, not just pre-defined fields
548
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
549
+     */
550
+    public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
551
+        return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
552
+    }
553
+
554
+    /**
555
+     * Returns the navigation
556
+     *
557
+     * @return array
558
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
559
+     *
560
+     * This function returns an array containing all entries added. The
561
+     * entries are sorted by the key 'order' ascending. Additional to the keys
562
+     * given for each app the following keys exist:
563
+     *   - active: boolean, signals if the user is on this navigation entry
564
+     */
565
+    public static function getNavigation(): array {
566
+        return OC::$server->getNavigationManager()->getAll();
567
+    }
568
+
569
+    /**
570
+     * Returns the Settings Navigation
571
+     *
572
+     * @return string[]
573
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
574
+     *
575
+     * This function returns an array containing all settings pages added. The
576
+     * entries are sorted by the key 'order' ascending.
577
+     */
578
+    public static function getSettingsNavigation(): array {
579
+        return OC::$server->getNavigationManager()->getAll('settings');
580
+    }
581
+
582
+    /**
583
+     * get the id of loaded app
584
+     *
585
+     * @return string
586
+     */
587
+    public static function getCurrentApp(): string {
588
+        $request = \OC::$server->getRequest();
589
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
590
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
591
+        if (empty($topFolder)) {
592
+            $path_info = $request->getPathInfo();
593
+            if ($path_info) {
594
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
595
+            }
596
+        }
597
+        if ($topFolder == 'apps') {
598
+            $length = strlen($topFolder);
599
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
600
+        } else {
601
+            return $topFolder;
602
+        }
603
+    }
604
+
605
+    /**
606
+     * @param string $type
607
+     * @return array
608
+     */
609
+    public static function getForms(string $type): array {
610
+        $forms = [];
611
+        switch ($type) {
612
+            case 'admin':
613
+                $source = self::$adminForms;
614
+                break;
615
+            case 'personal':
616
+                $source = self::$personalForms;
617
+                break;
618
+            default:
619
+                return [];
620
+        }
621
+        foreach ($source as $form) {
622
+            $forms[] = include $form;
623
+        }
624
+        return $forms;
625
+    }
626
+
627
+    /**
628
+     * register an admin form to be shown
629
+     *
630
+     * @param string $app
631
+     * @param string $page
632
+     */
633
+    public static function registerAdmin(string $app, string $page) {
634
+        self::$adminForms[] = $app . '/' . $page . '.php';
635
+    }
636
+
637
+    /**
638
+     * register a personal form to be shown
639
+     * @param string $app
640
+     * @param string $page
641
+     */
642
+    public static function registerPersonal(string $app, string $page) {
643
+        self::$personalForms[] = $app . '/' . $page . '.php';
644
+    }
645
+
646
+    /**
647
+     * @param array $entry
648
+     */
649
+    public static function registerLogIn(array $entry) {
650
+        self::$altLogin[] = $entry;
651
+    }
652
+
653
+    /**
654
+     * @return array
655
+     */
656
+    public static function getAlternativeLogIns(): array {
657
+        return self::$altLogin;
658
+    }
659
+
660
+    /**
661
+     * get a list of all apps in the apps folder
662
+     *
663
+     * @return array an array of app names (string IDs)
664
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
665
+     */
666
+    public static function getAllApps(): array {
667
+
668
+        $apps = [];
669
+
670
+        foreach (OC::$APPSROOTS as $apps_dir) {
671
+            if (!is_readable($apps_dir['path'])) {
672
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
673
+                continue;
674
+            }
675
+            $dh = opendir($apps_dir['path']);
676
+
677
+            if (is_resource($dh)) {
678
+                while (($file = readdir($dh)) !== false) {
679
+
680
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
681
+
682
+                        $apps[] = $file;
683
+                    }
684
+                }
685
+            }
686
+        }
687
+
688
+        $apps = array_unique($apps);
689
+
690
+        return $apps;
691
+    }
692
+
693
+    /**
694
+     * List all apps, this is used in apps.php
695
+     *
696
+     * @return array
697
+     */
698
+    public function listAllApps(): array {
699
+        $installedApps = OC_App::getAllApps();
700
+
701
+        $appManager = \OC::$server->getAppManager();
702
+        //we don't want to show configuration for these
703
+        $blacklist = $appManager->getAlwaysEnabledApps();
704
+        $appList = [];
705
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
706
+        $urlGenerator = \OC::$server->getURLGenerator();
707
+
708
+        foreach ($installedApps as $app) {
709
+            if (array_search($app, $blacklist) === false) {
710
+
711
+                $info = OC_App::getAppInfo($app, false, $langCode);
712
+                if (!is_array($info)) {
713
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
714
+                    continue;
715
+                }
716
+
717
+                if (!isset($info['name'])) {
718
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
719
+                    continue;
720
+                }
721
+
722
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
723
+                $info['groups'] = null;
724
+                if ($enabled === 'yes') {
725
+                    $active = true;
726
+                } else if ($enabled === 'no') {
727
+                    $active = false;
728
+                } else {
729
+                    $active = true;
730
+                    $info['groups'] = $enabled;
731
+                }
732
+
733
+                $info['active'] = $active;
734
+
735
+                if ($appManager->isShipped($app)) {
736
+                    $info['internal'] = true;
737
+                    $info['level'] = self::officialApp;
738
+                    $info['removable'] = false;
739
+                } else {
740
+                    $info['internal'] = false;
741
+                    $info['removable'] = true;
742
+                }
743
+
744
+                $appPath = self::getAppPath($app);
745
+                if($appPath !== false) {
746
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
747
+                    if (file_exists($appIcon)) {
748
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
749
+                        $info['previewAsIcon'] = true;
750
+                    } else {
751
+                        $appIcon = $appPath . '/img/app.svg';
752
+                        if (file_exists($appIcon)) {
753
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
754
+                            $info['previewAsIcon'] = true;
755
+                        }
756
+                    }
757
+                }
758
+                // fix documentation
759
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
760
+                    foreach ($info['documentation'] as $key => $url) {
761
+                        // If it is not an absolute URL we assume it is a key
762
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
763
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
764
+                            $url = $urlGenerator->linkToDocs($url);
765
+                        }
766
+
767
+                        $info['documentation'][$key] = $url;
768
+                    }
769
+                }
770
+
771
+                $info['version'] = OC_App::getAppVersion($app);
772
+                $appList[] = $info;
773
+            }
774
+        }
775
+
776
+        return $appList;
777
+    }
778
+
779
+    public static function shouldUpgrade(string $app): bool {
780
+        $versions = self::getAppVersions();
781
+        $currentVersion = OC_App::getAppVersion($app);
782
+        if ($currentVersion && isset($versions[$app])) {
783
+            $installedVersion = $versions[$app];
784
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
785
+                return true;
786
+            }
787
+        }
788
+        return false;
789
+    }
790
+
791
+    /**
792
+     * Adjust the number of version parts of $version1 to match
793
+     * the number of version parts of $version2.
794
+     *
795
+     * @param string $version1 version to adjust
796
+     * @param string $version2 version to take the number of parts from
797
+     * @return string shortened $version1
798
+     */
799
+    private static function adjustVersionParts(string $version1, string $version2): string {
800
+        $version1 = explode('.', $version1);
801
+        $version2 = explode('.', $version2);
802
+        // reduce $version1 to match the number of parts in $version2
803
+        while (count($version1) > count($version2)) {
804
+            array_pop($version1);
805
+        }
806
+        // if $version1 does not have enough parts, add some
807
+        while (count($version1) < count($version2)) {
808
+            $version1[] = '0';
809
+        }
810
+        return implode('.', $version1);
811
+    }
812
+
813
+    /**
814
+     * Check whether the current ownCloud version matches the given
815
+     * application's version requirements.
816
+     *
817
+     * The comparison is made based on the number of parts that the
818
+     * app info version has. For example for ownCloud 6.0.3 if the
819
+     * app info version is expecting version 6.0, the comparison is
820
+     * made on the first two parts of the ownCloud version.
821
+     * This means that it's possible to specify "requiremin" => 6
822
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
823
+     *
824
+     * @param string $ocVersion ownCloud version to check against
825
+     * @param array $appInfo app info (from xml)
826
+     *
827
+     * @return boolean true if compatible, otherwise false
828
+     */
829
+    public static function isAppCompatible(string $ocVersion, array $appInfo): bool {
830
+        $requireMin = '';
831
+        $requireMax = '';
832
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
833
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
834
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
835
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
836
+        } else if (isset($appInfo['requiremin'])) {
837
+            $requireMin = $appInfo['requiremin'];
838
+        } else if (isset($appInfo['require'])) {
839
+            $requireMin = $appInfo['require'];
840
+        }
841
+
842
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
843
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
844
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
845
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
846
+        } else if (isset($appInfo['requiremax'])) {
847
+            $requireMax = $appInfo['requiremax'];
848
+        }
849
+
850
+        if (!empty($requireMin)
851
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
852
+        ) {
853
+
854
+            return false;
855
+        }
856
+
857
+        if (!empty($requireMax)
858
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
859
+        ) {
860
+            return false;
861
+        }
862
+
863
+        return true;
864
+    }
865
+
866
+    /**
867
+     * get the installed version of all apps
868
+     */
869
+    public static function getAppVersions() {
870
+        static $versions;
871
+
872
+        if(!$versions) {
873
+            $appConfig = \OC::$server->getAppConfig();
874
+            $versions = $appConfig->getValues(false, 'installed_version');
875
+        }
876
+        return $versions;
877
+    }
878
+
879
+    /**
880
+     * update the database for the app and call the update script
881
+     *
882
+     * @param string $appId
883
+     * @return bool
884
+     */
885
+    public static function updateApp(string $appId): bool {
886
+        $appPath = self::getAppPath($appId);
887
+        if($appPath === false) {
888
+            return false;
889
+        }
890
+        self::registerAutoloading($appId, $appPath);
891
+
892
+        \OC::$server->getAppManager()->clearAppsCache();
893
+        $appData = self::getAppInfo($appId);
894
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
895
+
896
+        if (file_exists($appPath . '/appinfo/database.xml')) {
897
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
898
+        } else {
899
+            $ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
900
+            $ms->migrate();
901
+        }
902
+
903
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
904
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
905
+        // update appversion in app manager
906
+        \OC::$server->getAppManager()->clearAppsCache();
907
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
908
+
909
+        // run upgrade code
910
+        if (file_exists($appPath . '/appinfo/update.php')) {
911
+            self::loadApp($appId);
912
+            include $appPath . '/appinfo/update.php';
913
+        }
914
+        self::setupBackgroundJobs($appData['background-jobs']);
915
+
916
+        //set remote/public handlers
917
+        if (array_key_exists('ocsid', $appData)) {
918
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
919
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
920
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
921
+        }
922
+        foreach ($appData['remote'] as $name => $path) {
923
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
924
+        }
925
+        foreach ($appData['public'] as $name => $path) {
926
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
927
+        }
928
+
929
+        self::setAppTypes($appId);
930
+
931
+        $version = \OC_App::getAppVersion($appId);
932
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
933
+
934
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
935
+            ManagerEvent::EVENT_APP_UPDATE, $appId
936
+        ));
937
+
938
+        return true;
939
+    }
940
+
941
+    /**
942
+     * @param string $appId
943
+     * @param string[] $steps
944
+     * @throws \OC\NeedsUpdateException
945
+     */
946
+    public static function executeRepairSteps(string $appId, array $steps) {
947
+        if (empty($steps)) {
948
+            return;
949
+        }
950
+        // load the app
951
+        self::loadApp($appId);
952
+
953
+        $dispatcher = OC::$server->getEventDispatcher();
954
+
955
+        // load the steps
956
+        $r = new Repair([], $dispatcher);
957
+        foreach ($steps as $step) {
958
+            try {
959
+                $r->addStep($step);
960
+            } catch (Exception $ex) {
961
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
962
+                \OC::$server->getLogger()->logException($ex);
963
+            }
964
+        }
965
+        // run the steps
966
+        $r->run();
967
+    }
968
+
969
+    public static function setupBackgroundJobs(array $jobs) {
970
+        $queue = \OC::$server->getJobList();
971
+        foreach ($jobs as $job) {
972
+            $queue->add($job);
973
+        }
974
+    }
975
+
976
+    /**
977
+     * @param string $appId
978
+     * @param string[] $steps
979
+     */
980
+    private static function setupLiveMigrations(string $appId, array $steps) {
981
+        $queue = \OC::$server->getJobList();
982
+        foreach ($steps as $step) {
983
+            $queue->add('OC\Migration\BackgroundRepair', [
984
+                'app' => $appId,
985
+                'step' => $step]);
986
+        }
987
+    }
988
+
989
+    /**
990
+     * @param string $appId
991
+     * @return \OC\Files\View|false
992
+     */
993
+    public static function getStorage(string $appId) {
994
+        if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
995
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
996
+                $view = new \OC\Files\View('/' . OC_User::getUser());
997
+                if (!$view->file_exists($appId)) {
998
+                    $view->mkdir($appId);
999
+                }
1000
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1001
+            } else {
1002
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1003
+                return false;
1004
+            }
1005
+        } else {
1006
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1007
+            return false;
1008
+        }
1009
+    }
1010
+
1011
+    protected static function findBestL10NOption(array $options, string $lang): string {
1012
+        // only a single option
1013
+        if (isset($options['@value'])) {
1014
+            return $options['@value'];
1015
+        }
1016
+
1017
+        $fallback = $similarLangFallback = $englishFallback = false;
1018
+
1019
+        $lang = strtolower($lang);
1020
+        $similarLang = $lang;
1021
+        if (strpos($similarLang, '_')) {
1022
+            // For "de_DE" we want to find "de" and the other way around
1023
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1024
+        }
1025
+
1026
+        foreach ($options as $option) {
1027
+            if (is_array($option)) {
1028
+                if ($fallback === false) {
1029
+                    $fallback = $option['@value'];
1030
+                }
1031
+
1032
+                if (!isset($option['@attributes']['lang'])) {
1033
+                    continue;
1034
+                }
1035
+
1036
+                $attributeLang = strtolower($option['@attributes']['lang']);
1037
+                if ($attributeLang === $lang) {
1038
+                    return $option['@value'];
1039
+                }
1040
+
1041
+                if ($attributeLang === $similarLang) {
1042
+                    $similarLangFallback = $option['@value'];
1043
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1044
+                    if ($similarLangFallback === false) {
1045
+                        $similarLangFallback =  $option['@value'];
1046
+                    }
1047
+                }
1048
+            } else {
1049
+                $englishFallback = $option;
1050
+            }
1051
+        }
1052
+
1053
+        if ($similarLangFallback !== false) {
1054
+            return $similarLangFallback;
1055
+        } else if ($englishFallback !== false) {
1056
+            return $englishFallback;
1057
+        }
1058
+        return (string) $fallback;
1059
+    }
1060
+
1061
+    /**
1062
+     * parses the app data array and enhanced the 'description' value
1063
+     *
1064
+     * @param array $data the app data
1065
+     * @param string $lang
1066
+     * @return array improved app data
1067
+     */
1068
+    public static function parseAppInfo(array $data, $lang = null): array {
1069
+
1070
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1071
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1072
+        }
1073
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1074
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1075
+        }
1076
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1077
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1078
+        } else if (isset($data['description']) && is_string($data['description'])) {
1079
+            $data['description'] = trim($data['description']);
1080
+        } else  {
1081
+            $data['description'] = '';
1082
+        }
1083
+
1084
+        return $data;
1085
+    }
1086
+
1087
+    /**
1088
+     * @param \OCP\IConfig $config
1089
+     * @param \OCP\IL10N $l
1090
+     * @param array $info
1091
+     * @throws \Exception
1092
+     */
1093
+    public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info) {
1094
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1095
+        $missing = $dependencyAnalyzer->analyze($info);
1096
+        if (!empty($missing)) {
1097
+            $missingMsg = implode(PHP_EOL, $missing);
1098
+            throw new \Exception(
1099
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1100
+                    [$info['name'], $missingMsg]
1101
+                )
1102
+            );
1103
+        }
1104
+    }
1105 1105
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -113,9 +113,9 @@  discard block
 block discarded – undo
113 113
 		$apps = self::getEnabledApps();
114 114
 
115 115
 		// Add each apps' folder as allowed class path
116
-		foreach($apps as $app) {
116
+		foreach ($apps as $app) {
117 117
 			$path = self::getAppPath($app);
118
-			if($path !== false) {
118
+			if ($path !== false) {
119 119
 				self::registerAutoloading($app, $path);
120 120
 			}
121 121
 		}
@@ -141,15 +141,15 @@  discard block
 block discarded – undo
141 141
 	public static function loadApp(string $app) {
142 142
 		self::$loadedApps[] = $app;
143 143
 		$appPath = self::getAppPath($app);
144
-		if($appPath === false) {
144
+		if ($appPath === false) {
145 145
 			return;
146 146
 		}
147 147
 
148 148
 		// in case someone calls loadApp() directly
149 149
 		self::registerAutoloading($app, $appPath);
150 150
 
151
-		if (is_file($appPath . '/appinfo/app.php')) {
152
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
151
+		if (is_file($appPath.'/appinfo/app.php')) {
152
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
153 153
 			try {
154 154
 				self::requireAppFile($app);
155 155
 			} catch (Error $ex) {
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 					self::$autoDisabledApps[] = $app;
161 161
 				}
162 162
 			}
163
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
163
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
164 164
 		}
165 165
 
166 166
 		$info = self::getAppInfo($app);
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
207 207
 				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
208 208
 			foreach ($plugins as $plugin) {
209
-				if($plugin['@attributes']['type'] === 'collaborator-search') {
209
+				if ($plugin['@attributes']['type'] === 'collaborator-search') {
210 210
 					$pluginInfo = [
211 211
 						'shareType' => $plugin['@attributes']['share-type'],
212 212
 						'class' => $plugin['@value'],
@@ -225,8 +225,8 @@  discard block
 block discarded – undo
225 225
 	 * @param string $path
226 226
 	 */
227 227
 	public static function registerAutoloading(string $app, string $path) {
228
-		$key = $app . '-' . $path;
229
-		if(isset(self::$alreadyRegistered[$key])) {
228
+		$key = $app.'-'.$path;
229
+		if (isset(self::$alreadyRegistered[$key])) {
230 230
 			return;
231 231
 		}
232 232
 
@@ -236,17 +236,17 @@  discard block
 block discarded – undo
236 236
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
237 237
 		\OC::$server->registerNamespace($app, $appNamespace);
238 238
 
239
-		if (file_exists($path . '/composer/autoload.php')) {
240
-			require_once $path . '/composer/autoload.php';
239
+		if (file_exists($path.'/composer/autoload.php')) {
240
+			require_once $path.'/composer/autoload.php';
241 241
 		} else {
242
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
242
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
243 243
 			// Register on legacy autoloader
244 244
 			\OC::$loader->addValidRoot($path);
245 245
 		}
246 246
 
247 247
 		// Register Test namespace only when testing
248 248
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
249
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
249
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
250 250
 		}
251 251
 	}
252 252
 
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
 	 */
259 259
 	private static function requireAppFile(string $app) {
260 260
 		// encapsulated here to avoid variable scope conflicts
261
-		require_once $app . '/appinfo/app.php';
261
+		require_once $app.'/appinfo/app.php';
262 262
 	}
263 263
 
264 264
 	/**
@@ -303,7 +303,7 @@  discard block
 block discarded – undo
303 303
 	public static function setAppTypes(string $app) {
304 304
 		$appManager = \OC::$server->getAppManager();
305 305
 		$appData = $appManager->getAppInfo($app);
306
-		if(!is_array($appData)) {
306
+		if (!is_array($appData)) {
307 307
 			return;
308 308
 		}
309 309
 
@@ -351,8 +351,8 @@  discard block
 block discarded – undo
351 351
 		} else {
352 352
 			$apps = $appManager->getEnabledAppsForUser($user);
353 353
 		}
354
-		$apps = array_filter($apps, function ($app) {
355
-			return $app !== 'files';//we add this manually
354
+		$apps = array_filter($apps, function($app) {
355
+			return $app !== 'files'; //we add this manually
356 356
 		});
357 357
 		sort($apps);
358 358
 		array_unshift($apps, 'files');
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 		$installer = \OC::$server->query(Installer::class);
391 391
 		$isDownloaded = $installer->isDownloaded($appId);
392 392
 
393
-		if(!$isDownloaded) {
393
+		if (!$isDownloaded) {
394 394
 			$installer->downloadApp($appId);
395 395
 		}
396 396
 
@@ -441,7 +441,7 @@  discard block
 block discarded – undo
441 441
 	 */
442 442
 	public static function findAppInDirectories(string $appId) {
443 443
 		$sanitizedAppId = self::cleanAppId($appId);
444
-		if($sanitizedAppId !== $appId) {
444
+		if ($sanitizedAppId !== $appId) {
445 445
 			return false;
446 446
 		}
447 447
 		static $app_dir = [];
@@ -452,7 +452,7 @@  discard block
 block discarded – undo
452 452
 
453 453
 		$possibleApps = [];
454 454
 		foreach (OC::$APPSROOTS as $dir) {
455
-			if (file_exists($dir['path'] . '/' . $appId)) {
455
+			if (file_exists($dir['path'].'/'.$appId)) {
456 456
 				$possibleApps[] = $dir;
457 457
 			}
458 458
 		}
@@ -466,7 +466,7 @@  discard block
 block discarded – undo
466 466
 		} else {
467 467
 			$versionToLoad = [];
468 468
 			foreach ($possibleApps as $possibleApp) {
469
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
469
+				$version = self::getAppVersionByPath($possibleApp['path'].'/'.$appId);
470 470
 				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
471 471
 					$versionToLoad = array(
472 472
 						'dir' => $possibleApp,
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
 		}
494 494
 
495 495
 		if (($dir = self::findAppInDirectories($appId)) != false) {
496
-			return $dir['path'] . '/' . $appId;
496
+			return $dir['path'].'/'.$appId;
497 497
 		}
498 498
 		return false;
499 499
 	}
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
 	 */
508 508
 	public static function getAppWebPath(string $appId) {
509 509
 		if (($dir = self::findAppInDirectories($appId)) != false) {
510
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
510
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
511 511
 		}
512 512
 		return false;
513 513
 	}
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
 	 * @return string
532 532
 	 */
533 533
 	public static function getAppVersionByPath(string $path): string {
534
-		$infoFile = $path . '/appinfo/info.xml';
534
+		$infoFile = $path.'/appinfo/info.xml';
535 535
 		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
536 536
 		return isset($appData['version']) ? $appData['version'] : '';
537 537
 	}
@@ -631,7 +631,7 @@  discard block
 block discarded – undo
631 631
 	 * @param string $page
632 632
 	 */
633 633
 	public static function registerAdmin(string $app, string $page) {
634
-		self::$adminForms[] = $app . '/' . $page . '.php';
634
+		self::$adminForms[] = $app.'/'.$page.'.php';
635 635
 	}
636 636
 
637 637
 	/**
@@ -640,7 +640,7 @@  discard block
 block discarded – undo
640 640
 	 * @param string $page
641 641
 	 */
642 642
 	public static function registerPersonal(string $app, string $page) {
643
-		self::$personalForms[] = $app . '/' . $page . '.php';
643
+		self::$personalForms[] = $app.'/'.$page.'.php';
644 644
 	}
645 645
 
646 646
 	/**
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
 
670 670
 		foreach (OC::$APPSROOTS as $apps_dir) {
671 671
 			if (!is_readable($apps_dir['path'])) {
672
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
672
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], ILogger::WARN);
673 673
 				continue;
674 674
 			}
675 675
 			$dh = opendir($apps_dir['path']);
@@ -677,7 +677,7 @@  discard block
 block discarded – undo
677 677
 			if (is_resource($dh)) {
678 678
 				while (($file = readdir($dh)) !== false) {
679 679
 
680
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
680
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
681 681
 
682 682
 						$apps[] = $file;
683 683
 					}
@@ -710,12 +710,12 @@  discard block
 block discarded – undo
710 710
 
711 711
 				$info = OC_App::getAppInfo($app, false, $langCode);
712 712
 				if (!is_array($info)) {
713
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
713
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', ILogger::ERROR);
714 714
 					continue;
715 715
 				}
716 716
 
717 717
 				if (!isset($info['name'])) {
718
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
718
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', ILogger::ERROR);
719 719
 					continue;
720 720
 				}
721 721
 
@@ -742,13 +742,13 @@  discard block
 block discarded – undo
742 742
 				}
743 743
 
744 744
 				$appPath = self::getAppPath($app);
745
-				if($appPath !== false) {
746
-					$appIcon = $appPath . '/img/' . $app . '.svg';
745
+				if ($appPath !== false) {
746
+					$appIcon = $appPath.'/img/'.$app.'.svg';
747 747
 					if (file_exists($appIcon)) {
748
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
748
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
749 749
 						$info['previewAsIcon'] = true;
750 750
 					} else {
751
-						$appIcon = $appPath . '/img/app.svg';
751
+						$appIcon = $appPath.'/img/app.svg';
752 752
 						if (file_exists($appIcon)) {
753 753
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
754 754
 							$info['previewAsIcon'] = true;
@@ -869,7 +869,7 @@  discard block
 block discarded – undo
869 869
 	public static function getAppVersions() {
870 870
 		static $versions;
871 871
 
872
-		if(!$versions) {
872
+		if (!$versions) {
873 873
 			$appConfig = \OC::$server->getAppConfig();
874 874
 			$versions = $appConfig->getValues(false, 'installed_version');
875 875
 		}
@@ -884,7 +884,7 @@  discard block
 block discarded – undo
884 884
 	 */
885 885
 	public static function updateApp(string $appId): bool {
886 886
 		$appPath = self::getAppPath($appId);
887
-		if($appPath === false) {
887
+		if ($appPath === false) {
888 888
 			return false;
889 889
 		}
890 890
 		self::registerAutoloading($appId, $appPath);
@@ -893,8 +893,8 @@  discard block
 block discarded – undo
893 893
 		$appData = self::getAppInfo($appId);
894 894
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
895 895
 
896
-		if (file_exists($appPath . '/appinfo/database.xml')) {
897
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
896
+		if (file_exists($appPath.'/appinfo/database.xml')) {
897
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
898 898
 		} else {
899 899
 			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
900 900
 			$ms->migrate();
@@ -907,23 +907,23 @@  discard block
 block discarded – undo
907 907
 		\OC::$server->getAppManager()->getAppVersion($appId, false);
908 908
 
909 909
 		// run upgrade code
910
-		if (file_exists($appPath . '/appinfo/update.php')) {
910
+		if (file_exists($appPath.'/appinfo/update.php')) {
911 911
 			self::loadApp($appId);
912
-			include $appPath . '/appinfo/update.php';
912
+			include $appPath.'/appinfo/update.php';
913 913
 		}
914 914
 		self::setupBackgroundJobs($appData['background-jobs']);
915 915
 
916 916
 		//set remote/public handlers
917 917
 		if (array_key_exists('ocsid', $appData)) {
918 918
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
919
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
919
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
920 920
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
921 921
 		}
922 922
 		foreach ($appData['remote'] as $name => $path) {
923
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
923
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
924 924
 		}
925 925
 		foreach ($appData['public'] as $name => $path) {
926
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
926
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
927 927
 		}
928 928
 
929 929
 		self::setAppTypes($appId);
@@ -993,17 +993,17 @@  discard block
 block discarded – undo
993 993
 	public static function getStorage(string $appId) {
994 994
 		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
995 995
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
996
-				$view = new \OC\Files\View('/' . OC_User::getUser());
996
+				$view = new \OC\Files\View('/'.OC_User::getUser());
997 997
 				if (!$view->file_exists($appId)) {
998 998
 					$view->mkdir($appId);
999 999
 				}
1000
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1000
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1001 1001
 			} else {
1002
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1002
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', ILogger::ERROR);
1003 1003
 				return false;
1004 1004
 			}
1005 1005
 		} else {
1006
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1006
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', ILogger::ERROR);
1007 1007
 			return false;
1008 1008
 		}
1009 1009
 	}
@@ -1040,9 +1040,9 @@  discard block
 block discarded – undo
1040 1040
 
1041 1041
 				if ($attributeLang === $similarLang) {
1042 1042
 					$similarLangFallback = $option['@value'];
1043
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1043
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1044 1044
 					if ($similarLangFallback === false) {
1045
-						$similarLangFallback =  $option['@value'];
1045
+						$similarLangFallback = $option['@value'];
1046 1046
 					}
1047 1047
 				}
1048 1048
 			} else {
@@ -1077,7 +1077,7 @@  discard block
 block discarded – undo
1077 1077
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1078 1078
 		} else if (isset($data['description']) && is_string($data['description'])) {
1079 1079
 			$data['description'] = trim($data['description']);
1080
-		} else  {
1080
+		} else {
1081 1081
 			$data['description'] = '';
1082 1082
 		}
1083 1083
 
Please login to merge, or discard this patch.
lib/private/Updater.php 2 patches
Indentation   +568 added lines, -568 removed lines patch added patch discarded remove patch
@@ -55,574 +55,574 @@
 block discarded – undo
55 55
  */
56 56
 class Updater extends BasicEmitter {
57 57
 
58
-	/** @var ILogger $log */
59
-	private $log;
60
-
61
-	/** @var IConfig */
62
-	private $config;
63
-
64
-	/** @var Checker */
65
-	private $checker;
66
-
67
-	/** @var Installer */
68
-	private $installer;
69
-
70
-	/** @var IJobList */
71
-	private $jobList;
72
-
73
-	private $logLevelNames = [
74
-		0 => 'Debug',
75
-		1 => 'Info',
76
-		2 => 'Warning',
77
-		3 => 'Error',
78
-		4 => 'Fatal',
79
-	];
80
-
81
-	public function __construct(IConfig $config,
82
-								Checker $checker,
83
-								ILogger $log,
84
-								Installer $installer,
85
-								IJobList $jobList) {
86
-		$this->log = $log;
87
-		$this->config = $config;
88
-		$this->checker = $checker;
89
-		$this->installer = $installer;
90
-		$this->jobList = $jobList;
91
-	}
92
-
93
-	/**
94
-	 * runs the update actions in maintenance mode, does not upgrade the source files
95
-	 * except the main .htaccess file
96
-	 *
97
-	 * @return bool true if the operation succeeded, false otherwise
98
-	 */
99
-	public function upgrade() {
100
-		$this->emitRepairEvents();
101
-		$this->logAllEvents();
102
-
103
-		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
104
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
105
-		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
106
-
107
-		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108
-
109
-		if(!$wasMaintenanceModeEnabled) {
110
-			$this->config->setSystemValue('maintenance', true);
111
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
112
-		}
113
-
114
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
115
-		$currentVersion = implode('.', \OCP\Util::getVersion());
116
-
117
-		// see https://github.com/nextcloud/server/issues/9992 for potential problem
118
-		if (version_compare($installedVersion, '14.0.0.9', '>=')) {
119
-			$this->waitForCronToFinish();
120
-		}
121
-
122
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
123
-
124
-		$success = true;
125
-		try {
126
-			$this->doUpgrade($currentVersion, $installedVersion);
127
-		} catch (HintException $exception) {
128
-			$this->log->logException($exception, ['app' => 'core']);
129
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
130
-			$success = false;
131
-		} catch (\Exception $exception) {
132
-			$this->log->logException($exception, ['app' => 'core']);
133
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
134
-			$success = false;
135
-		}
136
-
137
-		$this->emit('\OC\Updater', 'updateEnd', array($success));
138
-
139
-		if(!$wasMaintenanceModeEnabled && $success) {
140
-			$this->config->setSystemValue('maintenance', false);
141
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
142
-		} else {
143
-			$this->emit('\OC\Updater', 'maintenanceActive');
144
-		}
145
-
146
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
147
-		$this->config->setSystemValue('loglevel', $logLevel);
148
-		$this->config->setSystemValue('installed', true);
149
-
150
-		return $success;
151
-	}
152
-
153
-	/**
154
-	 * Return version from which this version is allowed to upgrade from
155
-	 *
156
-	 * @return array allowed previous versions per vendor
157
-	 */
158
-	private function getAllowedPreviousVersions() {
159
-		// this should really be a JSON file
160
-		require \OC::$SERVERROOT . '/version.php';
161
-		/** @var array $OC_VersionCanBeUpgradedFrom */
162
-		return $OC_VersionCanBeUpgradedFrom;
163
-	}
164
-
165
-	/**
166
-	 * Return vendor from which this version was published
167
-	 *
168
-	 * @return string Get the vendor
169
-	 */
170
-	private function getVendor() {
171
-		// this should really be a JSON file
172
-		require \OC::$SERVERROOT . '/version.php';
173
-		/** @var string $vendor */
174
-		return (string) $vendor;
175
-	}
176
-
177
-	/**
178
-	 * Whether an upgrade to a specified version is possible
179
-	 * @param string $oldVersion
180
-	 * @param string $newVersion
181
-	 * @param array $allowedPreviousVersions
182
-	 * @return bool
183
-	 */
184
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
185
-		$version = explode('.', $oldVersion);
186
-		$majorMinor = $version[0] . '.' . $version[1];
187
-
188
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
189
-
190
-		// Vendor was not set correctly on install, so we have to white-list known versions
191
-		if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
192
-			$currentVendor = 'owncloud';
193
-		}
194
-
195
-		if ($currentVendor === 'nextcloud') {
196
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
197
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
198
-					$this->config->getSystemValue('debug', false));
199
-		}
200
-
201
-		// Check if the instance can be migrated
202
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
203
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
204
-	}
205
-
206
-	/**
207
-	 * runs the update actions in maintenance mode, does not upgrade the source files
208
-	 * except the main .htaccess file
209
-	 *
210
-	 * @param string $currentVersion current version to upgrade to
211
-	 * @param string $installedVersion previous version from which to upgrade from
212
-	 *
213
-	 * @throws \Exception
214
-	 */
215
-	private function doUpgrade($currentVersion, $installedVersion) {
216
-		// Stop update if the update is over several major versions
217
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
218
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
219
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
220
-		}
221
-
222
-		// Update .htaccess files
223
-		try {
224
-			Setup::updateHtaccess();
225
-			Setup::protectDataDirectory();
226
-		} catch (\Exception $e) {
227
-			throw new \Exception($e->getMessage());
228
-		}
229
-
230
-		// create empty file in data dir, so we can later find
231
-		// out that this is indeed an ownCloud data directory
232
-		// (in case it didn't exist before)
233
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
234
-
235
-		// pre-upgrade repairs
236
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
237
-		$repair->run();
238
-
239
-		$this->doCoreUpgrade();
240
-
241
-		try {
242
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
243
-			Setup::installBackgroundJobs();
244
-		} catch (\Exception $e) {
245
-			throw new \Exception($e->getMessage());
246
-		}
247
-
248
-		// update all shipped apps
249
-		$this->checkAppsRequirements();
250
-		$this->doAppUpgrade();
251
-
252
-		// Update the appfetchers version so it downloads the correct list from the appstore
253
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
254
-
255
-		// upgrade appstore apps
256
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
257
-		$this->upgradeAppStoreApps(\OC_App::$autoDisabledApps, true);
258
-
259
-		// install new shipped apps on upgrade
260
-		OC_App::loadApps(['authentication']);
261
-		$errors = Installer::installShippedApps(true);
262
-		foreach ($errors as $appId => $exception) {
263
-			/** @var \Exception $exception */
264
-			$this->log->logException($exception, ['app' => $appId]);
265
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
266
-		}
267
-
268
-		// post-upgrade repairs
269
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
270
-		$repair->run();
271
-
272
-		//Invalidate update feed
273
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
274
-
275
-		// Check for code integrity if not disabled
276
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
277
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
278
-			$this->checker->runInstanceVerification();
279
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
280
-		}
281
-
282
-		// only set the final version if everything went well
283
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
284
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
285
-	}
286
-
287
-	protected function doCoreUpgrade() {
288
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
289
-
290
-		// execute core migrations
291
-		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
292
-		$ms->migrate();
293
-
294
-		$this->emit('\OC\Updater', 'dbUpgrade');
295
-	}
296
-
297
-	/**
298
-	 * @param string $version the oc version to check app compatibility with
299
-	 */
300
-	protected function checkAppUpgrade($version) {
301
-		$apps = \OC_App::getEnabledApps();
302
-		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
303
-
304
-		$appManager = \OC::$server->getAppManager();
305
-		foreach ($apps as $appId) {
306
-			$info = \OC_App::getAppInfo($appId);
307
-			$compatible = \OC_App::isAppCompatible($version, $info);
308
-			$isShipped = $appManager->isShipped($appId);
309
-
310
-			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
311
-				/**
312
-				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
313
-				 * are not possible anymore within it. - Consider this when touching the code.
314
-				 * @link https://github.com/owncloud/core/issues/10980
315
-				 * @see \OC_App::updateApp
316
-				 */
317
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
318
-					$this->includePreUpdate($appId);
319
-				}
320
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
321
-					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
322
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
323
-				}
324
-			}
325
-		}
326
-
327
-		$this->emit('\OC\Updater', 'appUpgradeCheck');
328
-	}
329
-
330
-	/**
331
-	 * Includes the pre-update file. Done here to prevent namespace mixups.
332
-	 * @param string $appId
333
-	 */
334
-	private function includePreUpdate($appId) {
335
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
336
-	}
337
-
338
-	/**
339
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
340
-	 * (types authentication, filesystem, logging, in that order) afterwards.
341
-	 *
342
-	 * @throws NeedsUpdateException
343
-	 */
344
-	protected function doAppUpgrade() {
345
-		$apps = \OC_App::getEnabledApps();
346
-		$priorityTypes = array('authentication', 'filesystem', 'logging');
347
-		$pseudoOtherType = 'other';
348
-		$stacks = array($pseudoOtherType => array());
349
-
350
-		foreach ($apps as $appId) {
351
-			$priorityType = false;
352
-			foreach ($priorityTypes as $type) {
353
-				if(!isset($stacks[$type])) {
354
-					$stacks[$type] = array();
355
-				}
356
-				if (\OC_App::isType($appId, [$type])) {
357
-					$stacks[$type][] = $appId;
358
-					$priorityType = true;
359
-					break;
360
-				}
361
-			}
362
-			if (!$priorityType) {
363
-				$stacks[$pseudoOtherType][] = $appId;
364
-			}
365
-		}
366
-		foreach ($stacks as $type => $stack) {
367
-			foreach ($stack as $appId) {
368
-				if (\OC_App::shouldUpgrade($appId)) {
369
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
370
-					\OC_App::updateApp($appId);
371
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
372
-				}
373
-				if($type !== $pseudoOtherType) {
374
-					// load authentication, filesystem and logging apps after
375
-					// upgrading them. Other apps my need to rely on modifying
376
-					// user and/or filesystem aspects.
377
-					\OC_App::loadApp($appId);
378
-				}
379
-			}
380
-		}
381
-	}
382
-
383
-	/**
384
-	 * check if the current enabled apps are compatible with the current
385
-	 * ownCloud version. disable them if not.
386
-	 * This is important if you upgrade ownCloud and have non ported 3rd
387
-	 * party apps installed.
388
-	 *
389
-	 * @return array
390
-	 * @throws \Exception
391
-	 */
392
-	private function checkAppsRequirements() {
393
-		$isCoreUpgrade = $this->isCodeUpgrade();
394
-		$apps = OC_App::getEnabledApps();
395
-		$version = implode('.', Util::getVersion());
396
-		$disabledApps = [];
397
-		$appManager = \OC::$server->getAppManager();
398
-		foreach ($apps as $app) {
399
-			// check if the app is compatible with this version of ownCloud
400
-			$info = OC_App::getAppInfo($app);
401
-			if($info === null || !OC_App::isAppCompatible($version, $info)) {
402
-				if ($appManager->isShipped($app)) {
403
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
404
-				}
405
-				\OC::$server->getAppManager()->disableApp($app);
406
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
407
-			}
408
-			// no need to disable any app in case this is a non-core upgrade
409
-			if (!$isCoreUpgrade) {
410
-				continue;
411
-			}
412
-			// shipped apps will remain enabled
413
-			if ($appManager->isShipped($app)) {
414
-				continue;
415
-			}
416
-			// authentication and session apps will remain enabled as well
417
-			if (OC_App::isType($app, ['session', 'authentication'])) {
418
-				continue;
419
-			}
420
-		}
421
-		return $disabledApps;
422
-	}
423
-
424
-	/**
425
-	 * @return bool
426
-	 */
427
-	private function isCodeUpgrade() {
428
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
429
-		$currentVersion = implode('.', Util::getVersion());
430
-		if (version_compare($currentVersion, $installedVersion, '>')) {
431
-			return true;
432
-		}
433
-		return false;
434
-	}
435
-
436
-	/**
437
-	 * @param array $disabledApps
438
-	 * @param bool $reenable
439
-	 * @throws \Exception
440
-	 */
441
-	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
442
-		foreach($disabledApps as $app) {
443
-			try {
444
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
445
-				if ($this->installer->isUpdateAvailable($app)) {
446
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
447
-					$this->installer->updateAppstoreApp($app);
448
-				}
449
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
450
-
451
-				if ($reenable) {
452
-					$ocApp = new \OC_App();
453
-					$ocApp->enable($app);
454
-				}
455
-			} catch (\Exception $ex) {
456
-				$this->log->logException($ex, ['app' => 'core']);
457
-			}
458
-		}
459
-	}
460
-
461
-	/**
462
-	 * Forward messages emitted by the repair routine
463
-	 */
464
-	private function emitRepairEvents() {
465
-		$dispatcher = \OC::$server->getEventDispatcher();
466
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
467
-			if ($event instanceof GenericEvent) {
468
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
469
-			}
470
-		});
471
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
472
-			if ($event instanceof GenericEvent) {
473
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
474
-			}
475
-		});
476
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
477
-			if ($event instanceof GenericEvent) {
478
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
479
-			}
480
-		});
481
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
482
-			if ($event instanceof GenericEvent) {
483
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
484
-			}
485
-		});
486
-	}
487
-
488
-	private function logAllEvents() {
489
-		$log = $this->log;
490
-
491
-		$dispatcher = \OC::$server->getEventDispatcher();
492
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
493
-			if (!$event instanceof GenericEvent) {
494
-				return;
495
-			}
496
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
497
-		});
498
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
499
-			if (!$event instanceof GenericEvent) {
500
-				return;
501
-			}
502
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
503
-		});
504
-
505
-		$repairListener = function($event) use ($log) {
506
-			if (!$event instanceof GenericEvent) {
507
-				return;
508
-			}
509
-			switch ($event->getSubject()) {
510
-				case '\OC\Repair::startProgress':
511
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
512
-					break;
513
-				case '\OC\Repair::advance':
514
-					$desc = $event->getArgument(1);
515
-					if (empty($desc)) {
516
-						$desc = '';
517
-					}
518
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
519
-
520
-					break;
521
-				case '\OC\Repair::finishProgress':
522
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
523
-					break;
524
-				case '\OC\Repair::step':
525
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
526
-					break;
527
-				case '\OC\Repair::info':
528
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
529
-					break;
530
-				case '\OC\Repair::warning':
531
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
532
-					break;
533
-				case '\OC\Repair::error':
534
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
535
-					break;
536
-			}
537
-		};
538
-
539
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
540
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
541
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
542
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
543
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
544
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
545
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
546
-
547
-
548
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
549
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
550
-		});
551
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
552
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
553
-		});
554
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
555
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
556
-		});
557
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
558
-			if ($success) {
559
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
560
-			} else {
561
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
562
-			}
563
-		});
564
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
565
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
566
-		});
567
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
568
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
569
-		});
570
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
571
-			$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']);
572
-		});
573
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
574
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
575
-		});
576
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
577
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
578
-		});
579
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
580
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
581
-		});
582
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
583
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
584
-		});
585
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
586
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
587
-		});
588
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
589
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
590
-		});
591
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
592
-			$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']);
593
-		});
594
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
595
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
596
-		});
597
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
598
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
599
-		});
600
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
601
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
602
-		});
603
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
604
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
605
-		});
606
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
607
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
608
-		});
609
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
610
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
611
-		});
612
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
613
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
614
-		});
615
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
616
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
617
-		});
618
-
619
-	}
620
-	private function waitForCronToFinish() {
621
-		while ($this->jobList->isAnyJobRunning()) {
622
-			$this->emit('\OC\Updater', 'waitForCronToFinish');
623
-			sleep(5);
624
-		}
625
-	}
58
+    /** @var ILogger $log */
59
+    private $log;
60
+
61
+    /** @var IConfig */
62
+    private $config;
63
+
64
+    /** @var Checker */
65
+    private $checker;
66
+
67
+    /** @var Installer */
68
+    private $installer;
69
+
70
+    /** @var IJobList */
71
+    private $jobList;
72
+
73
+    private $logLevelNames = [
74
+        0 => 'Debug',
75
+        1 => 'Info',
76
+        2 => 'Warning',
77
+        3 => 'Error',
78
+        4 => 'Fatal',
79
+    ];
80
+
81
+    public function __construct(IConfig $config,
82
+                                Checker $checker,
83
+                                ILogger $log,
84
+                                Installer $installer,
85
+                                IJobList $jobList) {
86
+        $this->log = $log;
87
+        $this->config = $config;
88
+        $this->checker = $checker;
89
+        $this->installer = $installer;
90
+        $this->jobList = $jobList;
91
+    }
92
+
93
+    /**
94
+     * runs the update actions in maintenance mode, does not upgrade the source files
95
+     * except the main .htaccess file
96
+     *
97
+     * @return bool true if the operation succeeded, false otherwise
98
+     */
99
+    public function upgrade() {
100
+        $this->emitRepairEvents();
101
+        $this->logAllEvents();
102
+
103
+        $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
104
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
105
+        $this->config->setSystemValue('loglevel', ILogger::DEBUG);
106
+
107
+        $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108
+
109
+        if(!$wasMaintenanceModeEnabled) {
110
+            $this->config->setSystemValue('maintenance', true);
111
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
112
+        }
113
+
114
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
115
+        $currentVersion = implode('.', \OCP\Util::getVersion());
116
+
117
+        // see https://github.com/nextcloud/server/issues/9992 for potential problem
118
+        if (version_compare($installedVersion, '14.0.0.9', '>=')) {
119
+            $this->waitForCronToFinish();
120
+        }
121
+
122
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
123
+
124
+        $success = true;
125
+        try {
126
+            $this->doUpgrade($currentVersion, $installedVersion);
127
+        } catch (HintException $exception) {
128
+            $this->log->logException($exception, ['app' => 'core']);
129
+            $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
130
+            $success = false;
131
+        } catch (\Exception $exception) {
132
+            $this->log->logException($exception, ['app' => 'core']);
133
+            $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
134
+            $success = false;
135
+        }
136
+
137
+        $this->emit('\OC\Updater', 'updateEnd', array($success));
138
+
139
+        if(!$wasMaintenanceModeEnabled && $success) {
140
+            $this->config->setSystemValue('maintenance', false);
141
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
142
+        } else {
143
+            $this->emit('\OC\Updater', 'maintenanceActive');
144
+        }
145
+
146
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
147
+        $this->config->setSystemValue('loglevel', $logLevel);
148
+        $this->config->setSystemValue('installed', true);
149
+
150
+        return $success;
151
+    }
152
+
153
+    /**
154
+     * Return version from which this version is allowed to upgrade from
155
+     *
156
+     * @return array allowed previous versions per vendor
157
+     */
158
+    private function getAllowedPreviousVersions() {
159
+        // this should really be a JSON file
160
+        require \OC::$SERVERROOT . '/version.php';
161
+        /** @var array $OC_VersionCanBeUpgradedFrom */
162
+        return $OC_VersionCanBeUpgradedFrom;
163
+    }
164
+
165
+    /**
166
+     * Return vendor from which this version was published
167
+     *
168
+     * @return string Get the vendor
169
+     */
170
+    private function getVendor() {
171
+        // this should really be a JSON file
172
+        require \OC::$SERVERROOT . '/version.php';
173
+        /** @var string $vendor */
174
+        return (string) $vendor;
175
+    }
176
+
177
+    /**
178
+     * Whether an upgrade to a specified version is possible
179
+     * @param string $oldVersion
180
+     * @param string $newVersion
181
+     * @param array $allowedPreviousVersions
182
+     * @return bool
183
+     */
184
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
185
+        $version = explode('.', $oldVersion);
186
+        $majorMinor = $version[0] . '.' . $version[1];
187
+
188
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
189
+
190
+        // Vendor was not set correctly on install, so we have to white-list known versions
191
+        if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
192
+            $currentVendor = 'owncloud';
193
+        }
194
+
195
+        if ($currentVendor === 'nextcloud') {
196
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
197
+                && (version_compare($oldVersion, $newVersion, '<=') ||
198
+                    $this->config->getSystemValue('debug', false));
199
+        }
200
+
201
+        // Check if the instance can be migrated
202
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
203
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
204
+    }
205
+
206
+    /**
207
+     * runs the update actions in maintenance mode, does not upgrade the source files
208
+     * except the main .htaccess file
209
+     *
210
+     * @param string $currentVersion current version to upgrade to
211
+     * @param string $installedVersion previous version from which to upgrade from
212
+     *
213
+     * @throws \Exception
214
+     */
215
+    private function doUpgrade($currentVersion, $installedVersion) {
216
+        // Stop update if the update is over several major versions
217
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
218
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
219
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
220
+        }
221
+
222
+        // Update .htaccess files
223
+        try {
224
+            Setup::updateHtaccess();
225
+            Setup::protectDataDirectory();
226
+        } catch (\Exception $e) {
227
+            throw new \Exception($e->getMessage());
228
+        }
229
+
230
+        // create empty file in data dir, so we can later find
231
+        // out that this is indeed an ownCloud data directory
232
+        // (in case it didn't exist before)
233
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
234
+
235
+        // pre-upgrade repairs
236
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
237
+        $repair->run();
238
+
239
+        $this->doCoreUpgrade();
240
+
241
+        try {
242
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
243
+            Setup::installBackgroundJobs();
244
+        } catch (\Exception $e) {
245
+            throw new \Exception($e->getMessage());
246
+        }
247
+
248
+        // update all shipped apps
249
+        $this->checkAppsRequirements();
250
+        $this->doAppUpgrade();
251
+
252
+        // Update the appfetchers version so it downloads the correct list from the appstore
253
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
254
+
255
+        // upgrade appstore apps
256
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
257
+        $this->upgradeAppStoreApps(\OC_App::$autoDisabledApps, true);
258
+
259
+        // install new shipped apps on upgrade
260
+        OC_App::loadApps(['authentication']);
261
+        $errors = Installer::installShippedApps(true);
262
+        foreach ($errors as $appId => $exception) {
263
+            /** @var \Exception $exception */
264
+            $this->log->logException($exception, ['app' => $appId]);
265
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
266
+        }
267
+
268
+        // post-upgrade repairs
269
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
270
+        $repair->run();
271
+
272
+        //Invalidate update feed
273
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
274
+
275
+        // Check for code integrity if not disabled
276
+        if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
277
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
278
+            $this->checker->runInstanceVerification();
279
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
280
+        }
281
+
282
+        // only set the final version if everything went well
283
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
284
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
285
+    }
286
+
287
+    protected function doCoreUpgrade() {
288
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
289
+
290
+        // execute core migrations
291
+        $ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
292
+        $ms->migrate();
293
+
294
+        $this->emit('\OC\Updater', 'dbUpgrade');
295
+    }
296
+
297
+    /**
298
+     * @param string $version the oc version to check app compatibility with
299
+     */
300
+    protected function checkAppUpgrade($version) {
301
+        $apps = \OC_App::getEnabledApps();
302
+        $this->emit('\OC\Updater', 'appUpgradeCheckBefore');
303
+
304
+        $appManager = \OC::$server->getAppManager();
305
+        foreach ($apps as $appId) {
306
+            $info = \OC_App::getAppInfo($appId);
307
+            $compatible = \OC_App::isAppCompatible($version, $info);
308
+            $isShipped = $appManager->isShipped($appId);
309
+
310
+            if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
311
+                /**
312
+                 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
313
+                 * are not possible anymore within it. - Consider this when touching the code.
314
+                 * @link https://github.com/owncloud/core/issues/10980
315
+                 * @see \OC_App::updateApp
316
+                 */
317
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
318
+                    $this->includePreUpdate($appId);
319
+                }
320
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
321
+                    $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
322
+                    \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
323
+                }
324
+            }
325
+        }
326
+
327
+        $this->emit('\OC\Updater', 'appUpgradeCheck');
328
+    }
329
+
330
+    /**
331
+     * Includes the pre-update file. Done here to prevent namespace mixups.
332
+     * @param string $appId
333
+     */
334
+    private function includePreUpdate($appId) {
335
+        include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
336
+    }
337
+
338
+    /**
339
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
340
+     * (types authentication, filesystem, logging, in that order) afterwards.
341
+     *
342
+     * @throws NeedsUpdateException
343
+     */
344
+    protected function doAppUpgrade() {
345
+        $apps = \OC_App::getEnabledApps();
346
+        $priorityTypes = array('authentication', 'filesystem', 'logging');
347
+        $pseudoOtherType = 'other';
348
+        $stacks = array($pseudoOtherType => array());
349
+
350
+        foreach ($apps as $appId) {
351
+            $priorityType = false;
352
+            foreach ($priorityTypes as $type) {
353
+                if(!isset($stacks[$type])) {
354
+                    $stacks[$type] = array();
355
+                }
356
+                if (\OC_App::isType($appId, [$type])) {
357
+                    $stacks[$type][] = $appId;
358
+                    $priorityType = true;
359
+                    break;
360
+                }
361
+            }
362
+            if (!$priorityType) {
363
+                $stacks[$pseudoOtherType][] = $appId;
364
+            }
365
+        }
366
+        foreach ($stacks as $type => $stack) {
367
+            foreach ($stack as $appId) {
368
+                if (\OC_App::shouldUpgrade($appId)) {
369
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
370
+                    \OC_App::updateApp($appId);
371
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
372
+                }
373
+                if($type !== $pseudoOtherType) {
374
+                    // load authentication, filesystem and logging apps after
375
+                    // upgrading them. Other apps my need to rely on modifying
376
+                    // user and/or filesystem aspects.
377
+                    \OC_App::loadApp($appId);
378
+                }
379
+            }
380
+        }
381
+    }
382
+
383
+    /**
384
+     * check if the current enabled apps are compatible with the current
385
+     * ownCloud version. disable them if not.
386
+     * This is important if you upgrade ownCloud and have non ported 3rd
387
+     * party apps installed.
388
+     *
389
+     * @return array
390
+     * @throws \Exception
391
+     */
392
+    private function checkAppsRequirements() {
393
+        $isCoreUpgrade = $this->isCodeUpgrade();
394
+        $apps = OC_App::getEnabledApps();
395
+        $version = implode('.', Util::getVersion());
396
+        $disabledApps = [];
397
+        $appManager = \OC::$server->getAppManager();
398
+        foreach ($apps as $app) {
399
+            // check if the app is compatible with this version of ownCloud
400
+            $info = OC_App::getAppInfo($app);
401
+            if($info === null || !OC_App::isAppCompatible($version, $info)) {
402
+                if ($appManager->isShipped($app)) {
403
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
404
+                }
405
+                \OC::$server->getAppManager()->disableApp($app);
406
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
407
+            }
408
+            // no need to disable any app in case this is a non-core upgrade
409
+            if (!$isCoreUpgrade) {
410
+                continue;
411
+            }
412
+            // shipped apps will remain enabled
413
+            if ($appManager->isShipped($app)) {
414
+                continue;
415
+            }
416
+            // authentication and session apps will remain enabled as well
417
+            if (OC_App::isType($app, ['session', 'authentication'])) {
418
+                continue;
419
+            }
420
+        }
421
+        return $disabledApps;
422
+    }
423
+
424
+    /**
425
+     * @return bool
426
+     */
427
+    private function isCodeUpgrade() {
428
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
429
+        $currentVersion = implode('.', Util::getVersion());
430
+        if (version_compare($currentVersion, $installedVersion, '>')) {
431
+            return true;
432
+        }
433
+        return false;
434
+    }
435
+
436
+    /**
437
+     * @param array $disabledApps
438
+     * @param bool $reenable
439
+     * @throws \Exception
440
+     */
441
+    private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
442
+        foreach($disabledApps as $app) {
443
+            try {
444
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
445
+                if ($this->installer->isUpdateAvailable($app)) {
446
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
447
+                    $this->installer->updateAppstoreApp($app);
448
+                }
449
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
450
+
451
+                if ($reenable) {
452
+                    $ocApp = new \OC_App();
453
+                    $ocApp->enable($app);
454
+                }
455
+            } catch (\Exception $ex) {
456
+                $this->log->logException($ex, ['app' => 'core']);
457
+            }
458
+        }
459
+    }
460
+
461
+    /**
462
+     * Forward messages emitted by the repair routine
463
+     */
464
+    private function emitRepairEvents() {
465
+        $dispatcher = \OC::$server->getEventDispatcher();
466
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
467
+            if ($event instanceof GenericEvent) {
468
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
469
+            }
470
+        });
471
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
472
+            if ($event instanceof GenericEvent) {
473
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
474
+            }
475
+        });
476
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
477
+            if ($event instanceof GenericEvent) {
478
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
479
+            }
480
+        });
481
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
482
+            if ($event instanceof GenericEvent) {
483
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
484
+            }
485
+        });
486
+    }
487
+
488
+    private function logAllEvents() {
489
+        $log = $this->log;
490
+
491
+        $dispatcher = \OC::$server->getEventDispatcher();
492
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
493
+            if (!$event instanceof GenericEvent) {
494
+                return;
495
+            }
496
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
497
+        });
498
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
499
+            if (!$event instanceof GenericEvent) {
500
+                return;
501
+            }
502
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
503
+        });
504
+
505
+        $repairListener = function($event) use ($log) {
506
+            if (!$event instanceof GenericEvent) {
507
+                return;
508
+            }
509
+            switch ($event->getSubject()) {
510
+                case '\OC\Repair::startProgress':
511
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
512
+                    break;
513
+                case '\OC\Repair::advance':
514
+                    $desc = $event->getArgument(1);
515
+                    if (empty($desc)) {
516
+                        $desc = '';
517
+                    }
518
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
519
+
520
+                    break;
521
+                case '\OC\Repair::finishProgress':
522
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
523
+                    break;
524
+                case '\OC\Repair::step':
525
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
526
+                    break;
527
+                case '\OC\Repair::info':
528
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
529
+                    break;
530
+                case '\OC\Repair::warning':
531
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
532
+                    break;
533
+                case '\OC\Repair::error':
534
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
535
+                    break;
536
+            }
537
+        };
538
+
539
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
540
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
541
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
542
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
543
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
544
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
545
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
546
+
547
+
548
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
549
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
550
+        });
551
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
552
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
553
+        });
554
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
555
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
556
+        });
557
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
558
+            if ($success) {
559
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
560
+            } else {
561
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
562
+            }
563
+        });
564
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
565
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
566
+        });
567
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
568
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
569
+        });
570
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
571
+            $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']);
572
+        });
573
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
574
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
575
+        });
576
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
577
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
578
+        });
579
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
580
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
581
+        });
582
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
583
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
584
+        });
585
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
586
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
587
+        });
588
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
589
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
590
+        });
591
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
592
+            $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']);
593
+        });
594
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
595
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
596
+        });
597
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
598
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
599
+        });
600
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
601
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
602
+        });
603
+        $this->listen('\OC\Updater', 'failure', function ($message) use($log) {
604
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
605
+        });
606
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
607
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
608
+        });
609
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
610
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
611
+        });
612
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
613
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
614
+        });
615
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
616
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
617
+        });
618
+
619
+    }
620
+    private function waitForCronToFinish() {
621
+        while ($this->jobList->isAnyJobRunning()) {
622
+            $this->emit('\OC\Updater', 'waitForCronToFinish');
623
+            sleep(5);
624
+        }
625
+    }
626 626
 
627 627
 }
628 628
 
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -101,12 +101,12 @@  discard block
 block discarded – undo
101 101
 		$this->logAllEvents();
102 102
 
103 103
 		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
104
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
104
+		$this->emit('\OC\Updater', 'setDebugLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
105 105
 		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
106 106
 
107 107
 		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
108 108
 
109
-		if(!$wasMaintenanceModeEnabled) {
109
+		if (!$wasMaintenanceModeEnabled) {
110 110
 			$this->config->setSystemValue('maintenance', true);
111 111
 			$this->emit('\OC\Updater', 'maintenanceEnabled');
112 112
 		}
@@ -119,31 +119,31 @@  discard block
 block discarded – undo
119 119
 			$this->waitForCronToFinish();
120 120
 		}
121 121
 
122
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
122
+		$this->log->debug('starting upgrade from '.$installedVersion.' to '.$currentVersion, array('app' => 'core'));
123 123
 
124 124
 		$success = true;
125 125
 		try {
126 126
 			$this->doUpgrade($currentVersion, $installedVersion);
127 127
 		} catch (HintException $exception) {
128 128
 			$this->log->logException($exception, ['app' => 'core']);
129
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
129
+			$this->emit('\OC\Updater', 'failure', array($exception->getMessage().': '.$exception->getHint()));
130 130
 			$success = false;
131 131
 		} catch (\Exception $exception) {
132 132
 			$this->log->logException($exception, ['app' => 'core']);
133
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
133
+			$this->emit('\OC\Updater', 'failure', array(get_class($exception).': '.$exception->getMessage()));
134 134
 			$success = false;
135 135
 		}
136 136
 
137 137
 		$this->emit('\OC\Updater', 'updateEnd', array($success));
138 138
 
139
-		if(!$wasMaintenanceModeEnabled && $success) {
139
+		if (!$wasMaintenanceModeEnabled && $success) {
140 140
 			$this->config->setSystemValue('maintenance', false);
141 141
 			$this->emit('\OC\Updater', 'maintenanceDisabled');
142 142
 		} else {
143 143
 			$this->emit('\OC\Updater', 'maintenanceActive');
144 144
 		}
145 145
 
146
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
146
+		$this->emit('\OC\Updater', 'resetLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
147 147
 		$this->config->setSystemValue('loglevel', $logLevel);
148 148
 		$this->config->setSystemValue('installed', true);
149 149
 
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
 	 */
158 158
 	private function getAllowedPreviousVersions() {
159 159
 		// this should really be a JSON file
160
-		require \OC::$SERVERROOT . '/version.php';
160
+		require \OC::$SERVERROOT.'/version.php';
161 161
 		/** @var array $OC_VersionCanBeUpgradedFrom */
162 162
 		return $OC_VersionCanBeUpgradedFrom;
163 163
 	}
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 	 */
170 170
 	private function getVendor() {
171 171
 		// this should really be a JSON file
172
-		require \OC::$SERVERROOT . '/version.php';
172
+		require \OC::$SERVERROOT.'/version.php';
173 173
 		/** @var string $vendor */
174 174
 		return (string) $vendor;
175 175
 	}
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
 	 */
184 184
 	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
185 185
 		$version = explode('.', $oldVersion);
186
-		$majorMinor = $version[0] . '.' . $version[1];
186
+		$majorMinor = $version[0].'.'.$version[1];
187 187
 
188 188
 		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
189 189
 
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 		// create empty file in data dir, so we can later find
231 231
 		// out that this is indeed an ownCloud data directory
232 232
 		// (in case it didn't exist before)
233
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
233
+		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
234 234
 
235 235
 		// pre-upgrade repairs
236 236
 		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 		foreach ($errors as $appId => $exception) {
263 263
 			/** @var \Exception $exception */
264 264
 			$this->log->logException($exception, ['app' => $appId]);
265
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
265
+			$this->emit('\OC\Updater', 'failure', [$appId.': '.$exception->getMessage()]);
266 266
 		}
267 267
 
268 268
 		// post-upgrade repairs
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
 		$this->config->setAppValue('core', 'lastupdatedat', 0);
274 274
 
275 275
 		// Check for code integrity if not disabled
276
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
276
+		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
277 277
 			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
278 278
 			$this->checker->runInstanceVerification();
279 279
 			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
@@ -314,12 +314,12 @@  discard block
 block discarded – undo
314 314
 				 * @link https://github.com/owncloud/core/issues/10980
315 315
 				 * @see \OC_App::updateApp
316 316
 				 */
317
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
317
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/preupdate.php')) {
318 318
 					$this->includePreUpdate($appId);
319 319
 				}
320
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
320
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/database.xml')) {
321 321
 					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
322
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
322
+					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId).'/appinfo/database.xml');
323 323
 				}
324 324
 			}
325 325
 		}
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 	 * @param string $appId
333 333
 	 */
334 334
 	private function includePreUpdate($appId) {
335
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
335
+		include \OC_App::getAppPath($appId).'/appinfo/preupdate.php';
336 336
 	}
337 337
 
338 338
 	/**
@@ -350,7 +350,7 @@  discard block
 block discarded – undo
350 350
 		foreach ($apps as $appId) {
351 351
 			$priorityType = false;
352 352
 			foreach ($priorityTypes as $type) {
353
-				if(!isset($stacks[$type])) {
353
+				if (!isset($stacks[$type])) {
354 354
 					$stacks[$type] = array();
355 355
 				}
356 356
 				if (\OC_App::isType($appId, [$type])) {
@@ -370,7 +370,7 @@  discard block
 block discarded – undo
370 370
 					\OC_App::updateApp($appId);
371 371
 					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
372 372
 				}
373
-				if($type !== $pseudoOtherType) {
373
+				if ($type !== $pseudoOtherType) {
374 374
 					// load authentication, filesystem and logging apps after
375 375
 					// upgrading them. Other apps my need to rely on modifying
376 376
 					// user and/or filesystem aspects.
@@ -398,9 +398,9 @@  discard block
 block discarded – undo
398 398
 		foreach ($apps as $app) {
399 399
 			// check if the app is compatible with this version of ownCloud
400 400
 			$info = OC_App::getAppInfo($app);
401
-			if($info === null || !OC_App::isAppCompatible($version, $info)) {
401
+			if ($info === null || !OC_App::isAppCompatible($version, $info)) {
402 402
 				if ($appManager->isShipped($app)) {
403
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
403
+					throw new \UnexpectedValueException('The files of the app "'.$app.'" were not correctly replaced before running the update');
404 404
 				}
405 405
 				\OC::$server->getAppManager()->disableApp($app);
406 406
 				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
 	 * @throws \Exception
440 440
 	 */
441 441
 	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
442
-		foreach($disabledApps as $app) {
442
+		foreach ($disabledApps as $app) {
443 443
 			try {
444 444
 				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
445 445
 				if ($this->installer->isUpdateAvailable($app)) {
@@ -463,22 +463,22 @@  discard block
 block discarded – undo
463 463
 	 */
464 464
 	private function emitRepairEvents() {
465 465
 		$dispatcher = \OC::$server->getEventDispatcher();
466
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
466
+		$dispatcher->addListener('\OC\Repair::warning', function($event) {
467 467
 			if ($event instanceof GenericEvent) {
468 468
 				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
469 469
 			}
470 470
 		});
471
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
471
+		$dispatcher->addListener('\OC\Repair::error', function($event) {
472 472
 			if ($event instanceof GenericEvent) {
473 473
 				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
474 474
 			}
475 475
 		});
476
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
476
+		$dispatcher->addListener('\OC\Repair::info', function($event) {
477 477
 			if ($event instanceof GenericEvent) {
478 478
 				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
479 479
 			}
480 480
 		});
481
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
481
+		$dispatcher->addListener('\OC\Repair::step', function($event) {
482 482
 			if ($event instanceof GenericEvent) {
483 483
 				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
484 484
 			}
@@ -493,13 +493,13 @@  discard block
 block discarded – undo
493 493
 			if (!$event instanceof GenericEvent) {
494 494
 				return;
495 495
 			}
496
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
496
+			$log->info('\OC\DB\Migrator::executeSql: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
497 497
 		});
498 498
 		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
499 499
 			if (!$event instanceof GenericEvent) {
500 500
 				return;
501 501
 			}
502
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
502
+			$log->info('\OC\DB\Migrator::checkTable: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
503 503
 		});
504 504
 
505 505
 		$repairListener = function($event) use ($log) {
@@ -508,30 +508,30 @@  discard block
 block discarded – undo
508 508
 			}
509 509
 			switch ($event->getSubject()) {
510 510
 				case '\OC\Repair::startProgress':
511
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
511
+					$log->info('\OC\Repair::startProgress: Starting ... '.$event->getArgument(1).' ('.$event->getArgument(0).')', ['app' => 'updater']);
512 512
 					break;
513 513
 				case '\OC\Repair::advance':
514 514
 					$desc = $event->getArgument(1);
515 515
 					if (empty($desc)) {
516 516
 						$desc = '';
517 517
 					}
518
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
518
+					$log->info('\OC\Repair::advance: '.$desc.' ('.$event->getArgument(0).')', ['app' => 'updater']);
519 519
 
520 520
 					break;
521 521
 				case '\OC\Repair::finishProgress':
522 522
 					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
523 523
 					break;
524 524
 				case '\OC\Repair::step':
525
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
525
+					$log->info('\OC\Repair::step: Repair step: '.$event->getArgument(0), ['app' => 'updater']);
526 526
 					break;
527 527
 				case '\OC\Repair::info':
528
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
528
+					$log->info('\OC\Repair::info: Repair info: '.$event->getArgument(0), ['app' => 'updater']);
529 529
 					break;
530 530
 				case '\OC\Repair::warning':
531
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
531
+					$log->warning('\OC\Repair::warning: Repair warning: '.$event->getArgument(0), ['app' => 'updater']);
532 532
 					break;
533 533
 				case '\OC\Repair::error':
534
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
534
+					$log->error('\OC\Repair::error: Repair error: '.$event->getArgument(0), ['app' => 'updater']);
535 535
 					break;
536 536
 			}
537 537
 		};
@@ -545,74 +545,74 @@  discard block
 block discarded – undo
545 545
 		$dispatcher->addListener('\OC\Repair::error', $repairListener);
546 546
 
547 547
 
548
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
548
+		$this->listen('\OC\Updater', 'maintenanceEnabled', function() use($log) {
549 549
 			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
550 550
 		});
551
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
551
+		$this->listen('\OC\Updater', 'maintenanceDisabled', function() use($log) {
552 552
 			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
553 553
 		});
554
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
554
+		$this->listen('\OC\Updater', 'maintenanceActive', function() use($log) {
555 555
 			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
556 556
 		});
557
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
557
+		$this->listen('\OC\Updater', 'updateEnd', function($success) use($log) {
558 558
 			if ($success) {
559 559
 				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
560 560
 			} else {
561 561
 				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
562 562
 			}
563 563
 		});
564
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
564
+		$this->listen('\OC\Updater', 'dbUpgradeBefore', function() use($log) {
565 565
 			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
566 566
 		});
567
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
567
+		$this->listen('\OC\Updater', 'dbUpgrade', function() use($log) {
568 568
 			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
569 569
 		});
570
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
570
+		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function() use($log) {
571 571
 			$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']);
572 572
 		});
573
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
573
+		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function() use($log) {
574 574
 			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
575 575
 		});
576
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
577
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
576
+		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use($log) {
577
+			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: '.$app, ['app' => 'updater']);
578 578
 		});
579
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
580
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
579
+		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use($log) {
580
+			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "'.$app.'" in appstore', ['app' => 'updater']);
581 581
 		});
582
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
583
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
582
+		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use($log) {
583
+			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "'.$app.'" from appstore', ['app' => 'updater']);
584 584
 		});
585
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
586
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
585
+		$this->listen('\OC\Updater', 'checkAppStoreApp', function($app) use($log) {
586
+			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "'.$app.'" in appstore', ['app' => 'updater']);
587 587
 		});
588
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
588
+		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function() use ($log) {
589 589
 			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
590 590
 		});
591
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
592
-			$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']);
591
+		$this->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($log) {
592
+			$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']);
593 593
 		});
594
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
594
+		$this->listen('\OC\Updater', 'appUpgradeCheck', function() use ($log) {
595 595
 			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
596 596
 		});
597
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
598
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
597
+		$this->listen('\OC\Updater', 'appUpgradeStarted', function($app) use ($log) {
598
+			$log->info('\OC\Updater::appUpgradeStarted: Updating <'.$app.'> ...', ['app' => 'updater']);
599 599
 		});
600
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
601
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
600
+		$this->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($log) {
601
+			$log->info('\OC\Updater::appUpgrade: Updated <'.$app.'> to '.$version, ['app' => 'updater']);
602 602
 		});
603
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
604
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
603
+		$this->listen('\OC\Updater', 'failure', function($message) use($log) {
604
+			$log->error('\OC\Updater::failure: '.$message, ['app' => 'updater']);
605 605
 		});
606
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
606
+		$this->listen('\OC\Updater', 'setDebugLogLevel', function() use($log) {
607 607
 			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
608 608
 		});
609
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
610
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
609
+		$this->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use($log) {
610
+			$log->info('\OC\Updater::resetLogLevel: Reset log level to '.$logLevelName.'('.$logLevel.')', ['app' => 'updater']);
611 611
 		});
612
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
612
+		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use($log) {
613 613
 			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
614 614
 		});
615
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
615
+		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use($log) {
616 616
 			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
617 617
 		});
618 618
 
Please login to merge, or discard this patch.