diff --git a/apps/testing/lib/Command/StaticHunt.php b/apps/testing/lib/Command/StaticHunt.php
index 48fe283f2e3..44e332d788c 100644
--- a/apps/testing/lib/Command/StaticHunt.php
+++ b/apps/testing/lib/Command/StaticHunt.php
@@ -9,48 +9,76 @@ declare(strict_types=1);
namespace OCA\Testing\Command;
-use OCA\Theming\ImageManager;
-use OCA\Theming\ThemingDefaults;
-use OCP\IConfig;
+use OCP\App\IAppManager;
use Symfony\Component\Console\Command\Command;
-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 StaticHunt extends Command {
+ private const SKIP_REGEX = [
+ '@/templates/.+.php$@',
+ '@/ajax/.+.php$@',
+ '@/register_command.php$@',
+ ];
+
public function __construct(
- private IConfig $config,
+ private IAppManager $appManager,
) {
parent::__construct();
}
- protected function configure() {
+ #[\Override]
+ protected function configure(): void {
$this
->setName('testing:static-hunt')
->setDescription('Hunt for static properties in classes');
}
-
+ #[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int {
- //TODO run on all apps namespaces
$folders = [
- '\\OC' => __DIR__ . '/../../../../lib/private',
'' => __DIR__ . '/../../../../lib/private/legacy',
+ '\\OC' => __DIR__ . '/../../../../lib/private',
+ '\\OC\\Core' => __DIR__ . '/../../../../core',
+ ];
+ $apps = $this->appManager->getAllAppsInAppsFolders();
+ foreach ($apps as $app) {
+ $info = $this->appManager->getAppInfo($app);
+ if (!isset($info['namespace'])) {
+ continue;
+ }
+ $folders['\\OCA\\' . $info['namespace']] = $this->appManager->getAppPath($app) . '/lib';
+ }
+ $stats = [
+ 'classes' => 0,
+ 'properties' => 0,
];
foreach ($folders as $namespace => $folder) {
- $this->scanFolder($folder, $namespace, $output);
+ $this->scanFolder($folder, $namespace, $output, $stats);
}
+ $output->writeln('Found ' . $stats['properties'] . ' static properties spread among ' . $stats['classes'] . ' classes');
+
return 0;
}
- private function scanFolder(string $folder, string $namespace, OutputInterface $output): void {
+ private function scanFolder(string $folder, string $namespace, OutputInterface $output, array &$stats): void {
$folder = realpath($folder);
- foreach (glob($folder.'/**.php') as $filename) {
+ $output->writeln('Folder ' . $folder, OutputInterface::VERBOSITY_VERBOSE);
+ foreach ($this->recursiveGlob($folder) as $filename) {
try {
$filename = realpath($filename);
- $classname = $namespace.substr(str_replace('/', '\\', substr($filename, strlen($folder))), 0, -4);
+ if (($namespace === '\\OC') && str_contains($filename, 'lib/private/legacy')) {
+ // Skip legacy in OC as it’s scanned with an empty namespace separately
+ continue;
+ }
+ foreach (self::SKIP_REGEX as $skipRegex) {
+ if (preg_match($skipRegex, $filename)) {
+ continue 2;
+ }
+ }
+ $classname = $namespace . substr(str_replace('/', '\\', substr($filename, strlen($folder))), 0, -4);
+ $output->writeln('Class ' . $classname, OutputInterface::VERBOSITY_VERBOSE);
if (!class_exists($classname)) {
continue;
}
@@ -59,15 +87,25 @@ class StaticHunt extends Command {
if (empty($staticProperties)) {
continue;
}
+ $stats['classes']++;
$output->writeln('# ' . str_replace(\OC::$SERVERROOT, '', $filename) . " $classname");
foreach ($staticProperties as $property => $value) {
$propertyObject = $rClass->getProperty($property);
+ $stats['properties']++;
$output->write("$propertyObject");
}
- $output->writeln("");
+ $output->writeln('');
} catch (\Throwable $t) {
$output->writeln("$t");
}
}
}
+
+ private function recursiveGlob(string $path, int $depth = 1): \Generator {
+ $pattern = $path . str_repeat('/*', $depth);
+ yield from glob($pattern . '.php');
+ if (!empty(glob($pattern, GLOB_ONLYDIR))) {
+ yield from $this->recursiveGlob($path, $depth + 1);
+ }
+ }
}