3 declare(strict_types
=1);
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 require __DIR__
. '/../../vendor/autoload.php';
19 if (PHP_SAPI
!== 'cli') {
20 die('Script must be called from command line.' . chr(10));
24 * Core integrity test script:
26 * Find all ReST files configured in EXT:install/Configuration/ExtensionScanner/Php
27 * and verify they exist in EXT:core/Documentation/Changelog
29 class ExtensionScannerRstFileReferencesChecker
32 * @var array<string, string>
34 private $invalidRestFiles = [];
37 * @var array<string, string>
39 private $validRestFiles = [];
42 * @var array<string, int>
44 private $existingRestFiles = [];
46 public function check(): int
48 $this->existingRestFiles
= $this->fetchExistingRstFiles();
50 $finder = new Symfony\Component\Finder\
Finder();
51 $matcherConfigurationFiles = $finder->files()
52 ->in(__DIR__
. '/../../typo3/sysext/install/Configuration/ExtensionScanner/Php');
54 foreach ($matcherConfigurationFiles as $matcherConfigurationFile) {
55 /** @var SplFileInfo $matcherConfigurationFile */
56 $matcherConfigurations = require $matcherConfigurationFile->getPathname();
57 foreach ($matcherConfigurations as $matcherConfiguration) {
58 if (!isset($matcherConfiguration['restFiles'])) {
59 // `ConstructorArgumentsMatcher` is using an additional level which has to be checked
60 foreach ($matcherConfiguration as $nestedMatcherConfiguration) {
61 $this->checkRstFiles($nestedMatcherConfiguration, $matcherConfigurationFile);
64 $this->checkRstFiles($matcherConfiguration, $matcherConfigurationFile);
69 if (empty($this->invalidRestFiles
)) {
70 return 0; // we are done, nothing found. Script will exit with 0
72 echo "ReST files references in extension scanner configuration that could not be found:\n";
73 foreach ($this->invalidRestFiles
as $invalid) {
75 " - '%s' in file '%s'\n",
76 $invalid['invalidFile'],
77 $invalid['configurationFile']
81 return 1; // we got findings, script will exit with 1
84 private function fetchExistingRstFiles(): array
86 $finder = new Symfony\Component\Finder\
Finder();
89 ->notName(['Changelog-*.rst', 'Index.rst', 'Master.rst'])
90 ->in(__DIR__
. '/../../typo3/sysext/core/Documentation/Changelog');
91 $fileNames = array_map(
92 function (SplFileInfo
$file) {
93 return $file->getFilename();
95 iterator_to_array($finder)
97 // remove array keys containing the full file path again
98 $fileNames = array_values($fileNames);
99 // e.g. `['SomeFileA.rst' => 1, 'SomeOtherFile.rst' => 4]` counting occurrences
100 return array_count_values($fileNames);
103 private function checkRstFiles($matcherConfiguration, $matcherConfigurationFile): void
105 if (!is_array($matcherConfiguration['restFiles'] ??
null)) {
106 throw new \
InvalidArgumentException(sprintf(
107 'Configuration has no `restFiles` section defined in %s',
108 $matcherConfigurationFile
111 foreach ($matcherConfiguration['restFiles'] as $restFile) {
112 if (in_array($restFile, $this->validRestFiles
, true)) {
113 // Local cache as guard to not check same file over and over again
116 if (($this->existingRestFiles
[$restFile] ??
0) === 1) {
117 $this->validRestFiles
[] = $restFile;
119 $this->invalidRestFiles
[] = [
120 'configurationFile' => $matcherConfigurationFile->getPathname(),
121 'invalidFile' => $restFile,
128 $checker = new ExtensionScannerRstFileReferencesChecker();
129 exit($checker->check());