f7cloud_client/apps/groupfolders/lib/Command/Scan.php
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

154 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2018 F7cloud GmbH and F7cloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\GroupFolders\Command;
use OC\Files\ObjectStore\ObjectStoreScanner;
use OCA\GroupFolders\Folder\FolderDefinitionWithPermissions;
use OCP\Constants;
use OCP\Files\Cache\IScanner;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Scan extends FolderCommand {
protected function configure(): void {
$this
->setName('groupfolders:scan')
->setDescription('Scan a Team folder for outside changes')
->addArgument(
'folder_id',
InputArgument::OPTIONAL,
'Id of the Team folder to scan.'
)->addOption(
'all',
null,
InputOption::VALUE_NONE,
'Scan all the Team folders.'
)
->addOption(
'path',
'p',
InputOption::VALUE_REQUIRED,
'Limit rescan to this path, eg. --path="/shared/media/Music".'
)->addOption(
'shallow',
null,
InputOption::VALUE_NONE,
'Do not scan folders recursively.'
);
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$folderId = $input->getArgument('folder_id');
$all = $input->getOption('all');
if ($folderId === null && !$all) {
$output->writeln('Either a Team folder id or --all needs to be provided');
return -1;
}
if ($folderId !== null && $all) {
$output->writeln('Specifying a Team folder id and --all are mutually exclusive');
return -1;
}
if ($all) {
$folders = $this->folderManager->getAllFoldersWithSize();
} else {
$folder = $this->getFolder($input, $output);
if ($folder === null) {
return -1;
}
$folders = [$folder->id => $folder];
}
$inputPath = $input->getOption('path');
if ($inputPath !== null) {
if (!is_string($inputPath)) {
$output->writeln('<error><path> option has to be a string</error>');
return -3;
}
$inputPath = '/' . trim($inputPath, '/');
} else {
$inputPath = '';
}
$recursive = !$input->getOption('shallow');
$stats = [];
foreach ($folders as $folder) {
$folderId = $folder->id;
$statsRow = [$folderId, 0, 0, 0, 0];
$folderWithPermissions = FolderDefinitionWithPermissions::fromFolder($folder, $folder->rootCacheEntry, Constants::PERMISSION_ALL);
$mount = $this->mountProvider->getMount($folderWithPermissions, '/' . $folder->mountPoint);
/** @var IScanner&\OC\Hooks\BasicEmitter $scanner */
$scanner = $mount->getStorage()->getScanner();
$output->writeln("Scanning Team folder with id\t<info>{$folder->id}</info>", OutputInterface::VERBOSITY_VERBOSE);
if ($scanner instanceof ObjectStoreScanner) {
$output->writeln('Scanning Team folders using an object store as primary storage is not supported.');
return -1;
}
$scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function (string $path) use ($output, &$statsRow): void {
$output->writeln("\tFile\t<info>/$path</info>", OutputInterface::VERBOSITY_VERBOSE);
$statsRow[2]++;
// abortIfInterrupted doesn't exist in nc14
if (method_exists($this, 'abortIfInterrupted')) {
$this->abortIfInterrupted();
}
});
$scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function (string $path) use ($output, &$statsRow): void {
$output->writeln("\tFolder\t<info>/$path</info>", OutputInterface::VERBOSITY_VERBOSE);
$statsRow[1]++;
// abortIfInterrupted doesn't exist in nc14
if (method_exists($this, 'abortIfInterrupted')) {
$this->abortIfInterrupted();
}
});
$scanner->listen('\OC\Files\Cache\Scanner', 'normalizedNameMismatch', function ($fullPath) use ($output, &$statsRow): void {
$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
$statsRow[3]++;
});
$start = microtime(true);
$scanner->setUseTransactions(false);
$scanner->scan($inputPath, $recursive);
$end = microtime(true);
$statsRow[4] = date('H:i:s', (int)($end - $start));
$output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
$stats[] = $statsRow;
}
$headers = [
'Folder Id', 'Folders', 'Files', 'Errors', 'Elapsed time'
];
$this->showSummary($headers, $stats, $output);
return 0;
}
protected function showSummary(array $headers, array $rows, OutputInterface $output): void {
$table = new Table($output);
$table
->setHeaders($headers)
->setRows($rows);
$table->render();
}
}