Passed
Push — master ( a70f28...060286 )
by Blizzz
11:44
created
apps/files_external/lib/Command/Notify.php 2 patches
Indentation   +299 added lines, -299 removed lines patch added patch discarded remove patch
@@ -48,303 +48,303 @@
 block discarded – undo
48 48
 use Symfony\Component\Console\Output\OutputInterface;
49 49
 
50 50
 class Notify extends Base {
51
-	/** @var GlobalStoragesService */
52
-	private $globalService;
53
-	/** @var IDBConnection */
54
-	private $connection;
55
-	/** @var ILogger */
56
-	private $logger;
57
-	/** @var IUserManager */
58
-	private $userManager;
59
-
60
-	public function __construct(
61
-		GlobalStoragesService $globalService,
62
-		IDBConnection $connection,
63
-		ILogger $logger,
64
-		IUserManager $userManager
65
-	) {
66
-		parent::__construct();
67
-		$this->globalService = $globalService;
68
-		$this->connection = $connection;
69
-		$this->logger = $logger;
70
-		$this->userManager = $userManager;
71
-	}
72
-
73
-	protected function configure() {
74
-		$this
75
-			->setName('files_external:notify')
76
-			->setDescription('Listen for active update notifications for a configured external mount')
77
-			->addArgument(
78
-				'mount_id',
79
-				InputArgument::REQUIRED,
80
-				'the mount id of the mount to listen to'
81
-			)->addOption(
82
-				'user',
83
-				'u',
84
-				InputOption::VALUE_REQUIRED,
85
-				'The username for the remote mount (required only for some mount configuration that don\'t store credentials)'
86
-			)->addOption(
87
-				'password',
88
-				'p',
89
-				InputOption::VALUE_REQUIRED,
90
-				'The password for the remote mount (required only for some mount configuration that don\'t store credentials)'
91
-			)->addOption(
92
-				'path',
93
-				'',
94
-				InputOption::VALUE_REQUIRED,
95
-				'The directory in the storage to listen for updates in',
96
-				'/'
97
-			)->addOption(
98
-				'no-self-check',
99
-				'',
100
-				InputOption::VALUE_NONE,
101
-				'Disable self check on startup'
102
-			);
103
-		parent::configure();
104
-	}
105
-
106
-	private function getUserOption(InputInterface $input): ?string {
107
-		if ($input->getOption('user')) {
108
-			return (string)$input->getOption('user');
109
-		} elseif (isset($_ENV['NOTIFY_USER'])) {
110
-			return (string)$_ENV['NOTIFY_USER'];
111
-		} elseif (isset($_SERVER['NOTIFY_USER'])) {
112
-			return (string)$_SERVER['NOTIFY_USER'];
113
-		} else {
114
-			return null;
115
-		}
116
-	}
117
-
118
-	private function getPasswordOption(InputInterface $input): ?string {
119
-		if ($input->getOption('password')) {
120
-			return (string)$input->getOption('password');
121
-		} elseif (isset($_ENV['NOTIFY_PASSWORD'])) {
122
-			return (string)$_ENV['NOTIFY_PASSWORD'];
123
-		} elseif (isset($_SERVER['NOTIFY_PASSWORD'])) {
124
-			return (string)$_SERVER['NOTIFY_PASSWORD'];
125
-		} else {
126
-			return null;
127
-		}
128
-	}
129
-
130
-	protected function execute(InputInterface $input, OutputInterface $output): int {
131
-		$mount = $this->globalService->getStorage($input->getArgument('mount_id'));
132
-		if (is_null($mount)) {
133
-			$output->writeln('<error>Mount not found</error>');
134
-			return 1;
135
-		}
136
-		$noAuth = false;
137
-
138
-		$userOption = $this->getUserOption($input);
139
-		$passwordOption = $this->getPasswordOption($input);
140
-
141
-		// if only the user is provided, we get the user object to pass along to the auth backend
142
-		// this allows using saved user credentials
143
-		$user = ($userOption && !$passwordOption) ? $this->userManager->get($userOption) : null;
144
-
145
-		try {
146
-			$authBackend = $mount->getAuthMechanism();
147
-			$authBackend->manipulateStorageConfig($mount, $user);
148
-		} catch (InsufficientDataForMeaningfulAnswerException $e) {
149
-			$noAuth = true;
150
-		} catch (StorageNotAvailableException $e) {
151
-			$noAuth = true;
152
-		}
153
-
154
-		if ($userOption) {
155
-			$mount->setBackendOption('user', $userOption);
156
-		}
157
-		if ($passwordOption) {
158
-			$mount->setBackendOption('password', $passwordOption);
159
-		}
160
-
161
-		try {
162
-			$backend = $mount->getBackend();
163
-			$backend->manipulateStorageConfig($mount, $user);
164
-		} catch (InsufficientDataForMeaningfulAnswerException $e) {
165
-			$noAuth = true;
166
-		} catch (StorageNotAvailableException $e) {
167
-			$noAuth = true;
168
-		}
169
-
170
-		try {
171
-			$storage = $this->createStorage($mount);
172
-		} catch (\Exception $e) {
173
-			$output->writeln('<error>Error while trying to create storage</error>');
174
-			if ($noAuth) {
175
-				$output->writeln('<error>Username and/or password required</error>');
176
-			}
177
-			return 1;
178
-		}
179
-		if (!$storage instanceof INotifyStorage) {
180
-			$output->writeln('<error>Mount of type "' . $mount->getBackend()->getText() . '" does not support active update notifications</error>');
181
-			return 1;
182
-		}
183
-
184
-		$verbose = $input->getOption('verbose');
185
-
186
-		$path = trim($input->getOption('path'), '/');
187
-		$notifyHandler = $storage->notify($path);
188
-
189
-		if (!$input->getOption('no-self-check')) {
190
-			$this->selfTest($storage, $notifyHandler, $verbose, $output);
191
-		}
192
-
193
-		$notifyHandler->listen(function (IChange $change) use ($mount, $verbose, $output) {
194
-			if ($verbose) {
195
-				$this->logUpdate($change, $output);
196
-			}
197
-			if ($change instanceof IRenameChange) {
198
-				$this->markParentAsOutdated($mount->getId(), $change->getTargetPath(), $output);
199
-			}
200
-			$this->markParentAsOutdated($mount->getId(), $change->getPath(), $output);
201
-		});
202
-		return 0;
203
-	}
204
-
205
-	private function createStorage(StorageConfig $mount) {
206
-		$class = $mount->getBackend()->getStorageClass();
207
-		return new $class($mount->getBackendOptions());
208
-	}
209
-
210
-	private function markParentAsOutdated($mountId, $path, OutputInterface $output) {
211
-		$parent = ltrim(dirname($path), '/');
212
-		if ($parent === '.') {
213
-			$parent = '';
214
-		}
215
-
216
-		try {
217
-			$storageIds = $this->getStorageIds($mountId);
218
-		} catch (DriverException $ex) {
219
-			$this->logger->logException($ex, ['message' => 'Error while trying to find correct storage ids.', 'level' => ILogger::WARN]);
220
-			$this->connection = $this->reconnectToDatabase($this->connection, $output);
221
-			$output->writeln('<info>Needed to reconnect to the database</info>');
222
-			$storageIds = $this->getStorageIds($mountId);
223
-		}
224
-		if (count($storageIds) === 0) {
225
-			throw new StorageNotAvailableException('No storages found by mount ID ' . $mountId);
226
-		}
227
-		$storageIds = array_map('intval', $storageIds);
228
-
229
-		$result = $this->updateParent($storageIds, $parent);
230
-		if ($result === 0) {
231
-			//TODO: Find existing parent further up the tree in the database and register that folder instead.
232
-			$this->logger->info('Failed updating parent for "' . $path . '" while trying to register change. It may not exist in the filecache.');
233
-		}
234
-	}
235
-
236
-	private function logUpdate(IChange $change, OutputInterface $output) {
237
-		switch ($change->getType()) {
238
-			case INotifyStorage::NOTIFY_ADDED:
239
-				$text = 'added';
240
-				break;
241
-			case INotifyStorage::NOTIFY_MODIFIED:
242
-				$text = 'modified';
243
-				break;
244
-			case INotifyStorage::NOTIFY_REMOVED:
245
-				$text = 'removed';
246
-				break;
247
-			case INotifyStorage::NOTIFY_RENAMED:
248
-				$text = 'renamed';
249
-				break;
250
-			default:
251
-				return;
252
-		}
253
-
254
-		$text .= ' ' . $change->getPath();
255
-		if ($change instanceof IRenameChange) {
256
-			$text .= ' to ' . $change->getTargetPath();
257
-		}
258
-
259
-		$output->writeln($text);
260
-	}
261
-
262
-	/**
263
-	 * @param int $mountId
264
-	 * @return array
265
-	 */
266
-	private function getStorageIds($mountId) {
267
-		$qb = $this->connection->getQueryBuilder();
268
-		return $qb
269
-			->select('storage_id')
270
-			->from('mounts')
271
-			->where($qb->expr()->eq('mount_id', $qb->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)))
272
-			->execute()
273
-			->fetchAll(\PDO::FETCH_COLUMN);
274
-	}
275
-
276
-	/**
277
-	 * @param array $storageIds
278
-	 * @param string $parent
279
-	 * @return int
280
-	 */
281
-	private function updateParent($storageIds, $parent) {
282
-		$pathHash = md5(trim(\OC_Util::normalizeUnicode($parent), '/'));
283
-		$qb = $this->connection->getQueryBuilder();
284
-		return $qb
285
-			->update('filecache')
286
-			->set('size', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT))
287
-			->where($qb->expr()->in('storage', $qb->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY, ':storage_ids')))
288
-			->andWhere($qb->expr()->eq('path_hash', $qb->createNamedParameter($pathHash, IQueryBuilder::PARAM_STR)))
289
-			->execute();
290
-	}
291
-
292
-	/**
293
-	 * @return \OCP\IDBConnection
294
-	 */
295
-	private function reconnectToDatabase(IDBConnection $connection, OutputInterface $output) {
296
-		try {
297
-			$connection->close();
298
-		} catch (\Exception $ex) {
299
-			$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while disconnecting from DB', 'level' => ILogger::WARN]);
300
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
301
-		}
302
-		while (!$connection->isConnected()) {
303
-			try {
304
-				$connection->connect();
305
-			} catch (\Exception $ex) {
306
-				$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while re-connecting to database', 'level' => ILogger::WARN]);
307
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
308
-				sleep(60);
309
-			}
310
-		}
311
-		return $connection;
312
-	}
313
-
314
-
315
-	private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $verbose, OutputInterface $output) {
316
-		usleep(100 * 1000); //give time for the notify to start
317
-		$storage->file_put_contents('/.nc_test_file.txt', 'test content');
318
-		$storage->mkdir('/.nc_test_folder');
319
-		$storage->file_put_contents('/.nc_test_folder/subfile.txt', 'test content');
320
-
321
-		usleep(100 * 1000); //time for all changes to be processed
322
-		$changes = $notifyHandler->getChanges();
323
-
324
-		$storage->unlink('/.nc_test_file.txt');
325
-		$storage->unlink('/.nc_test_folder/subfile.txt');
326
-		$storage->rmdir('/.nc_test_folder');
327
-
328
-		usleep(100 * 1000); //time for all changes to be processed
329
-		$notifyHandler->getChanges(); // flush
330
-
331
-		$foundRootChange = false;
332
-		$foundSubfolderChange = false;
333
-
334
-		foreach ($changes as $change) {
335
-			if ($change->getPath() === '/.nc_test_file.txt' || $change->getPath() === '.nc_test_file.txt') {
336
-				$foundRootChange = true;
337
-			} elseif ($change->getPath() === '/.nc_test_folder/subfile.txt' || $change->getPath() === '.nc_test_folder/subfile.txt') {
338
-				$foundSubfolderChange = true;
339
-			}
340
-		}
341
-
342
-		if ($foundRootChange && $foundSubfolderChange && $verbose) {
343
-			$output->writeln('<info>Self-test successful</info>');
344
-		} elseif ($foundRootChange && !$foundSubfolderChange) {
345
-			$output->writeln('<error>Error while running self-test, change is subfolder not detected</error>');
346
-		} elseif (!$foundRootChange) {
347
-			$output->writeln('<error>Error while running self-test, no changes detected</error>');
348
-		}
349
-	}
51
+    /** @var GlobalStoragesService */
52
+    private $globalService;
53
+    /** @var IDBConnection */
54
+    private $connection;
55
+    /** @var ILogger */
56
+    private $logger;
57
+    /** @var IUserManager */
58
+    private $userManager;
59
+
60
+    public function __construct(
61
+        GlobalStoragesService $globalService,
62
+        IDBConnection $connection,
63
+        ILogger $logger,
64
+        IUserManager $userManager
65
+    ) {
66
+        parent::__construct();
67
+        $this->globalService = $globalService;
68
+        $this->connection = $connection;
69
+        $this->logger = $logger;
70
+        $this->userManager = $userManager;
71
+    }
72
+
73
+    protected function configure() {
74
+        $this
75
+            ->setName('files_external:notify')
76
+            ->setDescription('Listen for active update notifications for a configured external mount')
77
+            ->addArgument(
78
+                'mount_id',
79
+                InputArgument::REQUIRED,
80
+                'the mount id of the mount to listen to'
81
+            )->addOption(
82
+                'user',
83
+                'u',
84
+                InputOption::VALUE_REQUIRED,
85
+                'The username for the remote mount (required only for some mount configuration that don\'t store credentials)'
86
+            )->addOption(
87
+                'password',
88
+                'p',
89
+                InputOption::VALUE_REQUIRED,
90
+                'The password for the remote mount (required only for some mount configuration that don\'t store credentials)'
91
+            )->addOption(
92
+                'path',
93
+                '',
94
+                InputOption::VALUE_REQUIRED,
95
+                'The directory in the storage to listen for updates in',
96
+                '/'
97
+            )->addOption(
98
+                'no-self-check',
99
+                '',
100
+                InputOption::VALUE_NONE,
101
+                'Disable self check on startup'
102
+            );
103
+        parent::configure();
104
+    }
105
+
106
+    private function getUserOption(InputInterface $input): ?string {
107
+        if ($input->getOption('user')) {
108
+            return (string)$input->getOption('user');
109
+        } elseif (isset($_ENV['NOTIFY_USER'])) {
110
+            return (string)$_ENV['NOTIFY_USER'];
111
+        } elseif (isset($_SERVER['NOTIFY_USER'])) {
112
+            return (string)$_SERVER['NOTIFY_USER'];
113
+        } else {
114
+            return null;
115
+        }
116
+    }
117
+
118
+    private function getPasswordOption(InputInterface $input): ?string {
119
+        if ($input->getOption('password')) {
120
+            return (string)$input->getOption('password');
121
+        } elseif (isset($_ENV['NOTIFY_PASSWORD'])) {
122
+            return (string)$_ENV['NOTIFY_PASSWORD'];
123
+        } elseif (isset($_SERVER['NOTIFY_PASSWORD'])) {
124
+            return (string)$_SERVER['NOTIFY_PASSWORD'];
125
+        } else {
126
+            return null;
127
+        }
128
+    }
129
+
130
+    protected function execute(InputInterface $input, OutputInterface $output): int {
131
+        $mount = $this->globalService->getStorage($input->getArgument('mount_id'));
132
+        if (is_null($mount)) {
133
+            $output->writeln('<error>Mount not found</error>');
134
+            return 1;
135
+        }
136
+        $noAuth = false;
137
+
138
+        $userOption = $this->getUserOption($input);
139
+        $passwordOption = $this->getPasswordOption($input);
140
+
141
+        // if only the user is provided, we get the user object to pass along to the auth backend
142
+        // this allows using saved user credentials
143
+        $user = ($userOption && !$passwordOption) ? $this->userManager->get($userOption) : null;
144
+
145
+        try {
146
+            $authBackend = $mount->getAuthMechanism();
147
+            $authBackend->manipulateStorageConfig($mount, $user);
148
+        } catch (InsufficientDataForMeaningfulAnswerException $e) {
149
+            $noAuth = true;
150
+        } catch (StorageNotAvailableException $e) {
151
+            $noAuth = true;
152
+        }
153
+
154
+        if ($userOption) {
155
+            $mount->setBackendOption('user', $userOption);
156
+        }
157
+        if ($passwordOption) {
158
+            $mount->setBackendOption('password', $passwordOption);
159
+        }
160
+
161
+        try {
162
+            $backend = $mount->getBackend();
163
+            $backend->manipulateStorageConfig($mount, $user);
164
+        } catch (InsufficientDataForMeaningfulAnswerException $e) {
165
+            $noAuth = true;
166
+        } catch (StorageNotAvailableException $e) {
167
+            $noAuth = true;
168
+        }
169
+
170
+        try {
171
+            $storage = $this->createStorage($mount);
172
+        } catch (\Exception $e) {
173
+            $output->writeln('<error>Error while trying to create storage</error>');
174
+            if ($noAuth) {
175
+                $output->writeln('<error>Username and/or password required</error>');
176
+            }
177
+            return 1;
178
+        }
179
+        if (!$storage instanceof INotifyStorage) {
180
+            $output->writeln('<error>Mount of type "' . $mount->getBackend()->getText() . '" does not support active update notifications</error>');
181
+            return 1;
182
+        }
183
+
184
+        $verbose = $input->getOption('verbose');
185
+
186
+        $path = trim($input->getOption('path'), '/');
187
+        $notifyHandler = $storage->notify($path);
188
+
189
+        if (!$input->getOption('no-self-check')) {
190
+            $this->selfTest($storage, $notifyHandler, $verbose, $output);
191
+        }
192
+
193
+        $notifyHandler->listen(function (IChange $change) use ($mount, $verbose, $output) {
194
+            if ($verbose) {
195
+                $this->logUpdate($change, $output);
196
+            }
197
+            if ($change instanceof IRenameChange) {
198
+                $this->markParentAsOutdated($mount->getId(), $change->getTargetPath(), $output);
199
+            }
200
+            $this->markParentAsOutdated($mount->getId(), $change->getPath(), $output);
201
+        });
202
+        return 0;
203
+    }
204
+
205
+    private function createStorage(StorageConfig $mount) {
206
+        $class = $mount->getBackend()->getStorageClass();
207
+        return new $class($mount->getBackendOptions());
208
+    }
209
+
210
+    private function markParentAsOutdated($mountId, $path, OutputInterface $output) {
211
+        $parent = ltrim(dirname($path), '/');
212
+        if ($parent === '.') {
213
+            $parent = '';
214
+        }
215
+
216
+        try {
217
+            $storageIds = $this->getStorageIds($mountId);
218
+        } catch (DriverException $ex) {
219
+            $this->logger->logException($ex, ['message' => 'Error while trying to find correct storage ids.', 'level' => ILogger::WARN]);
220
+            $this->connection = $this->reconnectToDatabase($this->connection, $output);
221
+            $output->writeln('<info>Needed to reconnect to the database</info>');
222
+            $storageIds = $this->getStorageIds($mountId);
223
+        }
224
+        if (count($storageIds) === 0) {
225
+            throw new StorageNotAvailableException('No storages found by mount ID ' . $mountId);
226
+        }
227
+        $storageIds = array_map('intval', $storageIds);
228
+
229
+        $result = $this->updateParent($storageIds, $parent);
230
+        if ($result === 0) {
231
+            //TODO: Find existing parent further up the tree in the database and register that folder instead.
232
+            $this->logger->info('Failed updating parent for "' . $path . '" while trying to register change. It may not exist in the filecache.');
233
+        }
234
+    }
235
+
236
+    private function logUpdate(IChange $change, OutputInterface $output) {
237
+        switch ($change->getType()) {
238
+            case INotifyStorage::NOTIFY_ADDED:
239
+                $text = 'added';
240
+                break;
241
+            case INotifyStorage::NOTIFY_MODIFIED:
242
+                $text = 'modified';
243
+                break;
244
+            case INotifyStorage::NOTIFY_REMOVED:
245
+                $text = 'removed';
246
+                break;
247
+            case INotifyStorage::NOTIFY_RENAMED:
248
+                $text = 'renamed';
249
+                break;
250
+            default:
251
+                return;
252
+        }
253
+
254
+        $text .= ' ' . $change->getPath();
255
+        if ($change instanceof IRenameChange) {
256
+            $text .= ' to ' . $change->getTargetPath();
257
+        }
258
+
259
+        $output->writeln($text);
260
+    }
261
+
262
+    /**
263
+     * @param int $mountId
264
+     * @return array
265
+     */
266
+    private function getStorageIds($mountId) {
267
+        $qb = $this->connection->getQueryBuilder();
268
+        return $qb
269
+            ->select('storage_id')
270
+            ->from('mounts')
271
+            ->where($qb->expr()->eq('mount_id', $qb->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)))
272
+            ->execute()
273
+            ->fetchAll(\PDO::FETCH_COLUMN);
274
+    }
275
+
276
+    /**
277
+     * @param array $storageIds
278
+     * @param string $parent
279
+     * @return int
280
+     */
281
+    private function updateParent($storageIds, $parent) {
282
+        $pathHash = md5(trim(\OC_Util::normalizeUnicode($parent), '/'));
283
+        $qb = $this->connection->getQueryBuilder();
284
+        return $qb
285
+            ->update('filecache')
286
+            ->set('size', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT))
287
+            ->where($qb->expr()->in('storage', $qb->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY, ':storage_ids')))
288
+            ->andWhere($qb->expr()->eq('path_hash', $qb->createNamedParameter($pathHash, IQueryBuilder::PARAM_STR)))
289
+            ->execute();
290
+    }
291
+
292
+    /**
293
+     * @return \OCP\IDBConnection
294
+     */
295
+    private function reconnectToDatabase(IDBConnection $connection, OutputInterface $output) {
296
+        try {
297
+            $connection->close();
298
+        } catch (\Exception $ex) {
299
+            $this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while disconnecting from DB', 'level' => ILogger::WARN]);
300
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
301
+        }
302
+        while (!$connection->isConnected()) {
303
+            try {
304
+                $connection->connect();
305
+            } catch (\Exception $ex) {
306
+                $this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while re-connecting to database', 'level' => ILogger::WARN]);
307
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
308
+                sleep(60);
309
+            }
310
+        }
311
+        return $connection;
312
+    }
313
+
314
+
315
+    private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $verbose, OutputInterface $output) {
316
+        usleep(100 * 1000); //give time for the notify to start
317
+        $storage->file_put_contents('/.nc_test_file.txt', 'test content');
318
+        $storage->mkdir('/.nc_test_folder');
319
+        $storage->file_put_contents('/.nc_test_folder/subfile.txt', 'test content');
320
+
321
+        usleep(100 * 1000); //time for all changes to be processed
322
+        $changes = $notifyHandler->getChanges();
323
+
324
+        $storage->unlink('/.nc_test_file.txt');
325
+        $storage->unlink('/.nc_test_folder/subfile.txt');
326
+        $storage->rmdir('/.nc_test_folder');
327
+
328
+        usleep(100 * 1000); //time for all changes to be processed
329
+        $notifyHandler->getChanges(); // flush
330
+
331
+        $foundRootChange = false;
332
+        $foundSubfolderChange = false;
333
+
334
+        foreach ($changes as $change) {
335
+            if ($change->getPath() === '/.nc_test_file.txt' || $change->getPath() === '.nc_test_file.txt') {
336
+                $foundRootChange = true;
337
+            } elseif ($change->getPath() === '/.nc_test_folder/subfile.txt' || $change->getPath() === '.nc_test_folder/subfile.txt') {
338
+                $foundSubfolderChange = true;
339
+            }
340
+        }
341
+
342
+        if ($foundRootChange && $foundSubfolderChange && $verbose) {
343
+            $output->writeln('<info>Self-test successful</info>');
344
+        } elseif ($foundRootChange && !$foundSubfolderChange) {
345
+            $output->writeln('<error>Error while running self-test, change is subfolder not detected</error>');
346
+        } elseif (!$foundRootChange) {
347
+            $output->writeln('<error>Error while running self-test, no changes detected</error>');
348
+        }
349
+    }
350 350
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -105,11 +105,11 @@  discard block
 block discarded – undo
105 105
 
106 106
 	private function getUserOption(InputInterface $input): ?string {
107 107
 		if ($input->getOption('user')) {
108
-			return (string)$input->getOption('user');
108
+			return (string) $input->getOption('user');
109 109
 		} elseif (isset($_ENV['NOTIFY_USER'])) {
110
-			return (string)$_ENV['NOTIFY_USER'];
110
+			return (string) $_ENV['NOTIFY_USER'];
111 111
 		} elseif (isset($_SERVER['NOTIFY_USER'])) {
112
-			return (string)$_SERVER['NOTIFY_USER'];
112
+			return (string) $_SERVER['NOTIFY_USER'];
113 113
 		} else {
114 114
 			return null;
115 115
 		}
@@ -117,11 +117,11 @@  discard block
 block discarded – undo
117 117
 
118 118
 	private function getPasswordOption(InputInterface $input): ?string {
119 119
 		if ($input->getOption('password')) {
120
-			return (string)$input->getOption('password');
120
+			return (string) $input->getOption('password');
121 121
 		} elseif (isset($_ENV['NOTIFY_PASSWORD'])) {
122
-			return (string)$_ENV['NOTIFY_PASSWORD'];
122
+			return (string) $_ENV['NOTIFY_PASSWORD'];
123 123
 		} elseif (isset($_SERVER['NOTIFY_PASSWORD'])) {
124
-			return (string)$_SERVER['NOTIFY_PASSWORD'];
124
+			return (string) $_SERVER['NOTIFY_PASSWORD'];
125 125
 		} else {
126 126
 			return null;
127 127
 		}
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 			return 1;
178 178
 		}
179 179
 		if (!$storage instanceof INotifyStorage) {
180
-			$output->writeln('<error>Mount of type "' . $mount->getBackend()->getText() . '" does not support active update notifications</error>');
180
+			$output->writeln('<error>Mount of type "'.$mount->getBackend()->getText().'" does not support active update notifications</error>');
181 181
 			return 1;
182 182
 		}
183 183
 
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 			$this->selfTest($storage, $notifyHandler, $verbose, $output);
191 191
 		}
192 192
 
193
-		$notifyHandler->listen(function (IChange $change) use ($mount, $verbose, $output) {
193
+		$notifyHandler->listen(function(IChange $change) use ($mount, $verbose, $output) {
194 194
 			if ($verbose) {
195 195
 				$this->logUpdate($change, $output);
196 196
 			}
@@ -222,14 +222,14 @@  discard block
 block discarded – undo
222 222
 			$storageIds = $this->getStorageIds($mountId);
223 223
 		}
224 224
 		if (count($storageIds) === 0) {
225
-			throw new StorageNotAvailableException('No storages found by mount ID ' . $mountId);
225
+			throw new StorageNotAvailableException('No storages found by mount ID '.$mountId);
226 226
 		}
227 227
 		$storageIds = array_map('intval', $storageIds);
228 228
 
229 229
 		$result = $this->updateParent($storageIds, $parent);
230 230
 		if ($result === 0) {
231 231
 			//TODO: Find existing parent further up the tree in the database and register that folder instead.
232
-			$this->logger->info('Failed updating parent for "' . $path . '" while trying to register change. It may not exist in the filecache.');
232
+			$this->logger->info('Failed updating parent for "'.$path.'" while trying to register change. It may not exist in the filecache.');
233 233
 		}
234 234
 	}
235 235
 
@@ -251,9 +251,9 @@  discard block
 block discarded – undo
251 251
 				return;
252 252
 		}
253 253
 
254
-		$text .= ' ' . $change->getPath();
254
+		$text .= ' '.$change->getPath();
255 255
 		if ($change instanceof IRenameChange) {
256
-			$text .= ' to ' . $change->getTargetPath();
256
+			$text .= ' to '.$change->getTargetPath();
257 257
 		}
258 258
 
259 259
 		$output->writeln($text);
Please login to merge, or discard this patch.