diff --git a/apps/files_external/lib/Command/Notify.php b/apps/files_external/lib/Command/Notify.php index 31919ba2d2a0d..de74900331af7 100644 --- a/apps/files_external/lib/Command/Notify.php +++ b/apps/files_external/lib/Command/Notify.php @@ -99,6 +99,11 @@ protected function configure() { '', InputOption::VALUE_NONE, 'Disable self check on startup' + )->addOption( + 'dry-run', + '', + InputOption::VALUE_NONE, + 'Don\'t make any changes, only log detected changes' ); parent::configure(); } @@ -181,23 +186,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 1; } - $verbose = $input->getOption('verbose'); + $dryRun = $input->getOption('dry-run'); + if ($dryRun && $output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + } $path = trim($input->getOption('path'), '/'); $notifyHandler = $storage->notify($path); if (!$input->getOption('no-self-check')) { - $this->selfTest($storage, $notifyHandler, $verbose, $output); + $this->selfTest($storage, $notifyHandler, $output); } - $notifyHandler->listen(function (IChange $change) use ($mount, $verbose, $output) { - if ($verbose) { - $this->logUpdate($change, $output); - } + $notifyHandler->listen(function (IChange $change) use ($mount, $output, $dryRun) { + $this->logUpdate($change, $output); if ($change instanceof IRenameChange) { - $this->markParentAsOutdated($mount->getId(), $change->getTargetPath(), $output); + $this->markParentAsOutdated($mount->getId(), $change->getTargetPath(), $output, $dryRun); } - $this->markParentAsOutdated($mount->getId(), $change->getPath(), $output); + $this->markParentAsOutdated($mount->getId(), $change->getPath(), $output, $dryRun); }); return 0; } @@ -207,29 +213,44 @@ private function createStorage(StorageConfig $mount) { return new $class($mount->getBackendOptions()); } - private function markParentAsOutdated($mountId, $path, OutputInterface $output) { + private function markParentAsOutdated($mountId, $path, OutputInterface $output, bool $dryRun) { $parent = ltrim(dirname($path), '/'); if ($parent === '.') { $parent = ''; } try { - $storageIds = $this->getStorageIds($mountId); + $storages = $this->getStorageIds($mountId, $parent); } catch (DriverException $ex) { $this->logger->logException($ex, ['message' => 'Error while trying to find correct storage ids.', 'level' => ILogger::WARN]); $this->connection = $this->reconnectToDatabase($this->connection, $output); $output->writeln('Needed to reconnect to the database'); - $storageIds = $this->getStorageIds($mountId); + $storages = $this->getStorageIds($mountId, $path); } - if (count($storageIds) === 0) { - throw new StorageNotAvailableException('No storages found by mount ID ' . $mountId); + if (count($storages) === 0) { + $output->writeln(" no users found with access to '$parent', skipping", OutputInterface::VERBOSITY_VERBOSE); + return; } - $storageIds = array_map('intval', $storageIds); - $result = $this->updateParent($storageIds, $parent); - if ($result === 0) { - //TODO: Find existing parent further up the tree in the database and register that folder instead. - $this->logger->info('Failed updating parent for "' . $path . '" while trying to register change. It may not exist in the filecache.'); + $users = array_map(function (array $storage) { + return $storage['user_id']; + }, $storages); + + $output->writeln(" marking '$parent' as outdated for " . implode(', ', $users), OutputInterface::VERBOSITY_VERBOSE); + + $storageIds = array_map(function (array $storage) { + return intval($storage['storage_id']); + }, $storages); + $storageIds = array_values(array_unique($storageIds)); + + if ($dryRun) { + $output->writeln(" dry-run: skipping database write"); + } else { + $result = $this->updateParent($storageIds, $parent); + if ($result === 0) { + //TODO: Find existing parent further up the tree in the database and register that folder instead. + $this->logger->info('Failed updating parent for "' . $path . '" while trying to register change. It may not exist in the filecache.'); + } } } @@ -256,21 +277,20 @@ private function logUpdate(IChange $change, OutputInterface $output) { $text .= ' to ' . $change->getTargetPath(); } - $output->writeln($text); + $output->writeln($text, OutputInterface::VERBOSITY_VERBOSE); } - /** - * @param int $mountId - * @return array - */ - private function getStorageIds($mountId) { + private function getStorageIds(int $mountId, string $path): array { + $pathHash = md5(trim((string)\OC_Util::normalizeUnicode($path), '/')); $qb = $this->connection->getQueryBuilder(); return $qb - ->select('storage_id') - ->from('mounts') + ->select('storage_id', 'user_id') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $qb->expr()->eq('m.storage_id', 'f.storage')) ->where($qb->expr()->eq('mount_id', $qb->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('path_hash', $qb->createNamedParameter($pathHash, IQueryBuilder::PARAM_STR))) ->execute() - ->fetchAll(\PDO::FETCH_COLUMN); + ->fetchAll(); } /** @@ -312,7 +332,7 @@ private function reconnectToDatabase(IDBConnection $connection, OutputInterface } - private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $verbose, OutputInterface $output) { + private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, OutputInterface $output) { usleep(100 * 1000); //give time for the notify to start $storage->file_put_contents('/.nc_test_file.txt', 'test content'); $storage->mkdir('/.nc_test_folder'); @@ -339,11 +359,11 @@ private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $ver } } - if ($foundRootChange && $foundSubfolderChange && $verbose) { - $output->writeln('Self-test successful'); - } elseif ($foundRootChange && !$foundSubfolderChange) { + if ($foundRootChange && $foundSubfolderChange) { + $output->writeln('Self-test successful', OutputInterface::VERBOSITY_VERBOSE); + } elseif ($foundRootChange) { $output->writeln('Error while running self-test, change is subfolder not detected'); - } elseif (!$foundRootChange) { + } else { $output->writeln('Error while running self-test, no changes detected'); } }