N°7331 - Refactor for better understanding

This commit is contained in:
Molkobain
2024-03-13 12:05:32 +01:00
parent 700c4d0b04
commit c2f72f713a
9 changed files with 153 additions and 130 deletions

View File

@@ -34,7 +34,7 @@ clearstatcache();
// Read params
$key = array_search("--manager", $argv);
if (false === $key || false === isset($argv[$key + 1]) ) {
throw new \Exception("Usage: " . __FILE__ . " --manager composer|npm");
throw new \InvalidArgumentException("Usage: " . __FILE__ . " --manager composer|npm");
}
$sDependenciesHandlerCode = $argv[$key + 1];
@@ -53,7 +53,7 @@ switch ($sDependenciesHandlerCode) {
// Start handler
$oDependenciesHandler = new $sDependenciesHandlerFQCN();
$aDeniedButStillPresent = $oDependenciesHandler->ListDeniedButStillPresent();
$aDeniedButStillPresent = $oDependenciesHandler->ListDeniedButStillPresentFoldersAbsPaths();
echo "\n";
foreach ($aDeniedButStillPresent as $sDir)
@@ -61,7 +61,7 @@ foreach ($aDeniedButStillPresent as $sDir)
if (false === $oDependenciesHandler::IsQuestionnableFolder($sDir))
{
echo "ERROR found INVALID denied test dir: '$sDir'\n";
throw new \Exception("$sDir must end with /Test/ or /test/");
throw new \RuntimeException("$sDir is in the denied list but doesn't comply with the rule (see IsQuestionnableFolder method)");
}
if (false === file_exists($sDir)) {
@@ -80,14 +80,14 @@ foreach ($aDeniedButStillPresent as $sDir)
$aAllowedAndDeniedDirs = array_merge(
$oDependenciesHandler->ListAllowedQuestionnableFoldersAbsPaths(),
$oDependenciesHandler->ListDeniedQuestionnableFolderAbsPaths()
$oDependenciesHandler->ListAllowedFoldersRelPaths(),
$oDependenciesHandler->ListDeniedFoldersRelPaths()
);
$aExistingDirs = $oDependenciesHandler->ListAllQuestionnableFoldersAbsPaths();
$aExistingDirs = $oDependenciesHandler->ListAllFoldersAbsPaths();
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
if (false === empty($aMissing)) {
echo "Some new tests dirs exists !\n"
.' They must be declared either in the allowed or denied list in '.$sDependenciesHandlerFQCN." (see N°2651).\n"
." They must be declared either in the allowed or denied list in {$sDependenciesHandlerFQCN}\n"
.' List of dirs:'."\n".var_export($aMissing, true)."\n";
}

View File

@@ -417,7 +417,7 @@ return array(
'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => $baseDir . '/sources/Core/MetaModel/FriendlyNameType.php',
'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => $baseDir . '/sources/Core/MetaModel/HierarchicalKey.php',
'Combodo\\iTop\\Core\\Trigger\\Enum\\SubscriptionPolicy' => $baseDir . '/sources/Core/Trigger/Enum/SubscriptionPolicy.php',
'Combodo\\iTop\\Dependencies\\AbstractHook' => $baseDir . '/sources/Dependencies/AbstractHook.php',
'Combodo\\iTop\\Dependencies\\AbstractFolderAnalyzer' => $baseDir . '/sources/Dependencies/AbstractFolderAnalyzer.php',
'Combodo\\iTop\\Dependencies\\Composer\\iTopComposer' => $baseDir . '/sources/Dependencies/Composer/iTopComposer.php',
'Combodo\\iTop\\Dependencies\\NPM\\iTopNPM' => $baseDir . '/sources/Dependencies/NPM/iTopNPM.php',
'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php',

View File

@@ -792,7 +792,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => __DIR__ . '/../..' . '/sources/Core/MetaModel/FriendlyNameType.php',
'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => __DIR__ . '/../..' . '/sources/Core/MetaModel/HierarchicalKey.php',
'Combodo\\iTop\\Core\\Trigger\\Enum\\SubscriptionPolicy' => __DIR__ . '/../..' . '/sources/Core/Trigger/Enum/SubscriptionPolicy.php',
'Combodo\\iTop\\Dependencies\\AbstractHook' => __DIR__ . '/../..' . '/sources/Dependencies/AbstractHook.php',
'Combodo\\iTop\\Dependencies\\AbstractFolderAnalyzer' => __DIR__ . '/../..' . '/sources/Dependencies/AbstractFolderAnalyzer.php',
'Combodo\\iTop\\Dependencies\\Composer\\iTopComposer' => __DIR__ . '/../..' . '/sources/Dependencies/Composer/iTopComposer.php',
'Combodo\\iTop\\Dependencies\\NPM\\iTopNPM' => __DIR__ . '/../..' . '/sources/Dependencies/NPM/iTopNPM.php',
'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',

2
node_modules/.htaccess generated vendored
View File

@@ -5,7 +5,7 @@
# Apache 2.4
<ifModule mod_authz_core.c>
Require all denied
<FilesMatch ".+\.(css|scss|js|map|png|bmp|gif|jpe?g|svg|tiff|woff2?|ttf|eot1)$">
<FilesMatch ".+\.(css|scss|js|map|png|bmp|gif|jpe?g|svg|tiff|woff2?|ttf|eot)$">
Require all granted
</FilesMatch>
</ifModule>

View File

@@ -11,14 +11,16 @@ use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/**
* Class AbstractHook
* Class AbstractFolderAnalyzer
*
* Extend this class to enable a dependency manager such as Composer or NPM to clean unnecessary files after an installation or update of a package.
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop\Dependencies
*
* @since 3.2.0 N°7331 class creation to have managers for both Composer and NPM (only Composer was existing before)
*/
abstract class AbstractHook
abstract class AbstractFolderAnalyzer
{
/**
* Questionnable folder is a folder name that seems like it doesn't need to be package as it only contain
@@ -34,15 +36,32 @@ abstract class AbstractHook
public const QUESTIONNABLE_FOLDER_REGEXP = '/^(tests?|examples?|htdocs?|demos?|external)$/i';
/**
* @return string Absolute path to the root folder of the dependencies (composer, npm, ...)
* @return string Relative path to the root folder of the dependencies (e.g. "lib" for composer, "node_modules" for npm, ...) from iTop app. root
*/
abstract protected function GetDependenciesRootFolderAbsPath(): string;
abstract protected function GetDependenciesRootFolderRelPath(): string;
/**
* @return string Absolute path to the root folder of the dependencies
*/
public function GetDependenciesRootFolderAbsPath(): string
{
return $this->GetApprootPathWithSlashes() . $this->GetDependenciesRootFolderRelPath();
}
/**
* @return string APPROOT constant but with slashes instead of DIRECTORY_SEPARATOR.
* This ease writing our paths, as we can use '/' for every platform.
*/
final protected function GetApprootPathWithSlashes(): string
{
return str_replace(DIRECTORY_SEPARATOR, '/', APPROOT);
}
/**
* @return array List of all subdirs of the dependencies folder that are {@see IsQuestionnableFolder}.
* Warning : each path contains slashes (meaning on Windows you'll get eg `C:/Dev/wamp64/www/itop-27/lib/goaop/framework/tests`)
*/
public function ListAllQuestionnableFoldersAbsPaths(): array
public function ListAllFoldersAbsPaths(): array
{
$aAllTestDirs = array();
$sPath = realpath($this->GetDependenciesRootFolderAbsPath());
@@ -84,31 +103,38 @@ abstract class AbstractHook
}
/**
* @return string APPROOT constant but with slashes instead of DIRECTORY_SEPARATOR.
* This ease writing our paths, as we can use '/' for every platform.
* @return array Array of absolute paths to allowed questionnable folders
*/
final protected function GetApprootPathWithSlashes(): string
abstract public function ListAllowedFoldersRelPaths(): array;
/**
* @return array Array of absolute paths to allowed folders
*/
public function ListAllowedFoldersAbsPaths(): array
{
return str_replace(DIRECTORY_SEPARATOR, '/', APPROOT);
return array_map(fn ($sRelPath): string => $this->GetDependenciesRootFolderAbsPath() . $sRelPath, $this->ListAllowedFoldersRelPaths());
}
/**
* @return array Array of absolute paths to allowed questionnable folders
* @return array Array of relative paths (from dependencies root folder {@see static::GetDependenciesRootFolderAbsPath()}) to denied folders
*/
abstract public function ListAllowedQuestionnableFoldersAbsPaths(): array;
abstract public function ListDeniedFoldersRelPaths(): array;
/**
* @return array Array of absolute paths to denied questionnable folders
* @return array Array of absolute paths to denied folders
*/
abstract public function ListDeniedQuestionnableFolderAbsPaths(): array;
public function ListDeniedFoldersAbsPaths(): array
{
return array_map(fn ($sRelPath): string => $this->GetDependenciesRootFolderAbsPath() . $sRelPath, $this->ListDeniedFoldersRelPaths());
}
/**
* @return array Array of absolute paths to questionnable denied test folders that need to be marked as allowed or denied
*/
public function ListDeniedButStillPresent(): array
public function ListDeniedButStillPresentFoldersAbsPaths(): array
{
$aDeniedTestDir = $this->ListDeniedQuestionnableFolderAbsPaths();
$aAllTestDir = $this->ListAllQuestionnableFoldersAbsPaths();
$aDeniedTestDir = $this->ListDeniedFoldersAbsPaths();
$aAllTestDir = $this->ListAllowedFoldersAbsPaths();
return array_intersect($aDeniedTestDir, $aAllTestDir);
}
}

View File

@@ -21,89 +21,87 @@
namespace Combodo\iTop\Dependencies\Composer;
use Combodo\iTop\Dependencies\AbstractHook;
use Combodo\iTop\Dependencies\AbstractFolderAnalyzer;
class iTopComposer extends AbstractHook
class iTopComposer extends AbstractFolderAnalyzer
{
/**
* @inheritDoc
*/
protected function GetDependenciesRootFolderAbsPath(): string
protected function GetDependenciesRootFolderRelPath(): string
{
return $this->GetApprootPathWithSlashes() . "lib";
return "lib/";
}
/**
* @inheritDoc
*/
public function ListAllowedQuestionnableFoldersAbsPaths(): array
public function ListAllowedFoldersRelPaths(): array
{
$APPROOT_WITH_SLASHES = $this->GetDependenciesRootFolderAbsPath();
return [
$APPROOT_WITH_SLASHES . '/twig/twig/src/Node/Expression/Test',
'twig/twig/src/Node/Expression/Test',
];
}
/**
* @inheritDoc
*/
public function ListDeniedQuestionnableFolderAbsPaths(): array
public function ListDeniedFoldersRelPaths(): array
{
$APPROOT_WITH_SLASHES = $this->GetDependenciesRootFolderAbsPath();
return [
$APPROOT_WITH_SLASHES . '/doctrine/lexer/tests',
'doctrine/lexer/tests',
$APPROOT_WITH_SLASHES . '/goaop/framework/tests',
'goaop/framework/tests',
$APPROOT_WITH_SLASHES . '/laminas/laminas-servicemanager/src/Test',
'laminas/laminas-servicemanager/src/Test',
$APPROOT_WITH_SLASHES . '/nikic/php-parser/test',
'nikic/php-parser/test',
$APPROOT_WITH_SLASHES . '/pear/archive_tar/tests',
$APPROOT_WITH_SLASHES . '/pear/console_getopt/tests',
$APPROOT_WITH_SLASHES . '/pear/pear_exception/tests',
'pear/archive_tar/tests',
'pear/console_getopt/tests',
'pear/pear_exception/tests',
$APPROOT_WITH_SLASHES . '/psr/log/Psr/Log/Test',
'psr/log/Psr/Log/Test',
$APPROOT_WITH_SLASHES . '/symfony/cache/Tests',
$APPROOT_WITH_SLASHES . '/symfony/cache/Tests/DoctrineProviderTest.php',
$APPROOT_WITH_SLASHES . '/symfony/class-loader/Tests',
$APPROOT_WITH_SLASHES . '/symfony/config/Tests',
$APPROOT_WITH_SLASHES . '/symfony/console/Tests',
$APPROOT_WITH_SLASHES . '/symfony/css-selector/Tests',
$APPROOT_WITH_SLASHES . '/symfony/debug/Resources/ext/tests',
$APPROOT_WITH_SLASHES . '/symfony/debug/Tests',
$APPROOT_WITH_SLASHES . '/symfony/dependency-injection/Tests',
$APPROOT_WITH_SLASHES . '/symfony/dotenv/Tests',
$APPROOT_WITH_SLASHES . '/symfony/event-dispatcher/Tests',
$APPROOT_WITH_SLASHES . '/symfony/filesystem/Tests',
$APPROOT_WITH_SLASHES . '/symfony/finder/Tests',
$APPROOT_WITH_SLASHES . '/symfony/http-client-contracts/Test',
$APPROOT_WITH_SLASHES . '/symfony/http-foundation/Test',
$APPROOT_WITH_SLASHES . '/symfony/http-kernel/Tests',
$APPROOT_WITH_SLASHES . '/symfony/service-contracts/Test',
$APPROOT_WITH_SLASHES . '/symfony/framework-bundle/Test',
$APPROOT_WITH_SLASHES . '/symfony/mime/Test',
$APPROOT_WITH_SLASHES . '/symfony/routing/Tests',
$APPROOT_WITH_SLASHES . '/symfony/stopwatch/Tests',
$APPROOT_WITH_SLASHES . '/symfony/translation-contracts/Test',
$APPROOT_WITH_SLASHES . '/symfony/twig-bridge/Test',
$APPROOT_WITH_SLASHES . '/symfony/twig-bundle/Tests',
$APPROOT_WITH_SLASHES . '/symfony/var-dumper/Test',
$APPROOT_WITH_SLASHES . '/symfony/var-dumper/Tests/Test',
$APPROOT_WITH_SLASHES . '/symfony/var-dumper/Tests',
$APPROOT_WITH_SLASHES . '/symfony/web-profiler-bundle/Tests',
$APPROOT_WITH_SLASHES . '/symfony/yaml/Tests',
'symfony/cache/Tests',
'symfony/cache/Tests/DoctrineProviderTest.php',
'symfony/class-loader/Tests',
'symfony/config/Tests',
'symfony/console/Tests',
'symfony/css-selector/Tests',
'symfony/debug/Resources/ext/tests',
'symfony/debug/Tests',
'symfony/dependency-injection/Tests',
'symfony/dotenv/Tests',
'symfony/event-dispatcher/Tests',
'symfony/filesystem/Tests',
'symfony/finder/Tests',
'symfony/http-client-contracts/Test',
'symfony/http-foundation/Test',
'symfony/http-kernel/Tests',
'symfony/service-contracts/Test',
'symfony/framework-bundle/Test',
'symfony/mime/Test',
'symfony/routing/Tests',
'symfony/stopwatch/Tests',
'symfony/translation-contracts/Test',
'symfony/twig-bridge/Test',
'symfony/twig-bundle/Tests',
'symfony/var-dumper/Test',
'symfony/var-dumper/Tests/Test',
'symfony/var-dumper/Tests',
'symfony/web-profiler-bundle/Tests',
'symfony/yaml/Tests',
$APPROOT_WITH_SLASHES . '/tecnickcom/tcpdf/examples',
'tecnickcom/tcpdf/examples',
$APPROOT_WITH_SLASHES . '/thenetworg/oauth2-azure/tests',
'thenetworg/oauth2-azure/tests',
$APPROOT_WITH_SLASHES . '/twig/twig/src/Test',
$APPROOT_WITH_SLASHES . '/twig/twig/lib/Twig/Test',
$APPROOT_WITH_SLASHES . '/twig/twig/doc/tests',
'twig/twig/src/Test',
'twig/twig/lib/Twig/Test',
'twig/twig/doc/tests',
$APPROOT_WITH_SLASHES . '/laminas/laminas-servicemanager/src/Test',
'laminas/laminas-servicemanager/src/Test',
];
}
}

View File

@@ -21,67 +21,66 @@
namespace Combodo\iTop\Dependencies\NPM;
use Combodo\iTop\Dependencies\AbstractHook;
use Combodo\iTop\Dependencies\AbstractFolderAnalyzer;
class iTopNPM extends AbstractHook
class iTopNPM extends AbstractFolderAnalyzer
{
/**
* @inheritDoc
*/
protected function GetDependenciesRootFolderAbsPath(): string
protected function GetDependenciesRootFolderRelPath(): string
{
return $this->GetApprootPathWithSlashes() . "node_modules";
return "node_modules/";
}
/**
* @inheritDoc
*/
public function ListAllowedQuestionnableFoldersAbsPaths(): array
public function ListAllowedFoldersRelPaths(): array
{
$APPROOT_WITH_SLASHES = $this->GetDependenciesRootFolderAbsPath();
return [
// jQuery Sizzle used by jQuery
$APPROOT_WITH_SLASHES . '/jquery/external',
'jquery/external',
];
}
/**
* @inheritDoc
*/
public function ListDeniedQuestionnableFolderAbsPaths(): array
public function ListDeniedFoldersRelPaths(): array
{
$APPROOT_WITH_SLASHES = $this->GetDependenciesRootFolderAbsPath();
return [
$APPROOT_WITH_SLASHES . '/ace-builds/demo',
$APPROOT_WITH_SLASHES . '/ace-builds/src',
$APPROOT_WITH_SLASHES . '/ace-builds/src-min-noconflict',
$APPROOT_WITH_SLASHES . '/ace-builds/src-noconflict',
// ACE Editor see https://www.npmjs.com/package/ace-builds for dir contents
'ace-builds/demo',
'ace-builds/src',
'ace-builds/src-min-noconflict',
'ace-builds/src-noconflict',
$APPROOT_WITH_SLASHES . '/c3/htdocs',
$APPROOT_WITH_SLASHES . '/clipboard/demo',
$APPROOT_WITH_SLASHES . '/clipboard/test',
$APPROOT_WITH_SLASHES . '/delegate/demo',
$APPROOT_WITH_SLASHES . '/delegate/test',
$APPROOT_WITH_SLASHES . '/good-listener/demo',
$APPROOT_WITH_SLASHES . '/good-listener/test',
$APPROOT_WITH_SLASHES . '/jquery-migrate/test',
'c3/htdocs',
'clipboard/demo',
'clipboard/test',
'delegate/demo',
'delegate/test',
'good-listener/demo',
'good-listener/test',
'jquery-migrate/test',
// `jquery-ui` package is just there for vulnerability scans, so we don't want to version its files (only `jquery-ui-dist` is used within the code base)
$APPROOT_WITH_SLASHES . '/jquery-ui/.github',
$APPROOT_WITH_SLASHES . '/jquery-ui/build',
$APPROOT_WITH_SLASHES . '/jquery-ui/dist',
$APPROOT_WITH_SLASHES . '/jquery-ui/external',
$APPROOT_WITH_SLASHES . '/jquery-ui/themes',
$APPROOT_WITH_SLASHES . '/jquery-ui/ui',
'jquery-ui/.github',
'jquery-ui/build',
'jquery-ui/dist',
'jquery-ui/external',
'jquery-ui/themes',
'jquery-ui/ui',
$APPROOT_WITH_SLASHES . '/jquery-ui-dist/external',
$APPROOT_WITH_SLASHES . '/mousetrap/plugins/record/tests',
$APPROOT_WITH_SLASHES . '/mousetrap/tests',
$APPROOT_WITH_SLASHES . '/select/demo',
$APPROOT_WITH_SLASHES . '/select/test',
$APPROOT_WITH_SLASHES . '/selectize-plugin-a11y/examples',
$APPROOT_WITH_SLASHES . '/tiny-emitter/test',
$APPROOT_WITH_SLASHES . '/toastify-js/example',
'jquery-ui-dist/external',
'mousetrap/plugins/record/tests',
'mousetrap/tests',
'select/demo',
'select/test',
'selectize-plugin-a11y/examples',
'tiny-emitter/test',
'toastify-js/example',
];
}
}

View File

@@ -34,10 +34,10 @@ class iTopComposerTest extends ItopTestCase
}
/**
* @dataProvider IsTestFolderProvider
* @dataProvider IsQuestionnableFolderProvider
* @return void
*/
public function testIsTestFolder($sDirName, $bIsTest)
public function testIsQuestionnableFolder($sDirName, $bIsTest)
{
$isTestDir = iTopComposer::IsQuestionnableFolder($sDirName);
$this->assertIsInt($isTestDir);
@@ -48,7 +48,7 @@ class iTopComposerTest extends ItopTestCase
}
}
public function IsTestFolderProvider()
public function IsQuestionnableFolderProvider()
{
return [
'test' => ['test', true],
@@ -62,10 +62,10 @@ class iTopComposerTest extends ItopTestCase
];
}
public function testListAllTestFoldersAbsPaths()
public function testListAllFoldersAbsPaths()
{
$oiTopComposer = new iTopComposer();
$aDirs = $oiTopComposer->ListAllQuestionnableFoldersAbsPaths();
$aDirs = $oiTopComposer->ListAllFoldersAbsPaths();
$this->assertTrue(is_array($aDirs));
@@ -76,10 +76,10 @@ class iTopComposerTest extends ItopTestCase
}
public function testListDeniedTestFolderAbsPaths()
public function testListDeniedFolderAbsPaths()
{
$oiTopComposer = new iTopComposer();
$aDirs = $oiTopComposer->ListDeniedQuestionnableFolderAbsPaths();
$aDirs = $oiTopComposer->ListDeniedFoldersAbsPaths();
$this->assertTrue(is_array($aDirs));
@@ -91,13 +91,13 @@ class iTopComposerTest extends ItopTestCase
}
$this->assertEmpty($aDeniedDirWrongFormat,
'There are elements in \Combodo\iTop\Dependencies\Composer\iTopComposer::ListDeniedQuestionnableFolderAbsPaths that are not test dirs :'.var_export($aDeniedDirWrongFormat, true));
'There are elements in \Combodo\iTop\Dependencies\Composer\iTopComposer::ListDeniedFoldersRelPaths that are not test dirs :'.var_export($aDeniedDirWrongFormat, true));
}
public function testListAllowedTestFoldersAbsPaths()
public function testListAllowedFoldersAbsPaths()
{
$oiTopComposer = new iTopComposer();
$aDirs = $oiTopComposer->ListAllowedQuestionnableFoldersAbsPaths();
$aDirs = $oiTopComposer->ListAllowedFoldersAbsPaths();
$this->assertTrue(is_array($aDirs));
}
@@ -109,7 +109,7 @@ class iTopComposerTest extends ItopTestCase
{
$oiTopComposer = new iTopComposer();
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresentFoldersAbsPaths();
$this->assertEmpty(
$aDeniedButStillPresent,
@@ -125,11 +125,11 @@ class iTopComposerTest extends ItopTestCase
{
$oDependenciesHandler = new iTopComposer();
$aAllowedAndDeniedDirs = array_merge(
$oDependenciesHandler->ListAllowedQuestionnableFoldersAbsPaths(),
$oDependenciesHandler->ListDeniedQuestionnableFolderAbsPaths()
$oDependenciesHandler->ListAllowedFoldersAbsPaths(),
$oDependenciesHandler->ListDeniedFoldersAbsPaths()
);
$aExistingDirs = $oDependenciesHandler->ListAllQuestionnableFoldersAbsPaths();
$aExistingDirs = $oDependenciesHandler->ListAllFoldersAbsPaths();
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
$aExtra = array_diff($aAllowedAndDeniedDirs, $aExistingDirs);

View File

@@ -40,11 +40,11 @@ class iTopNPMTest extends ItopTestCase
{
$oDependenciesHandler = new iTopNPM();
$aAllowedAndDeniedDirs = array_merge(
$oDependenciesHandler->ListAllowedQuestionnableFoldersAbsPaths(),
$oDependenciesHandler->ListDeniedQuestionnableFolderAbsPaths()
$oDependenciesHandler->ListAllowedFoldersAbsPaths(),
$oDependenciesHandler->ListDeniedFoldersAbsPaths()
);
$aExistingDirs = $oDependenciesHandler->ListAllQuestionnableFoldersAbsPaths();
$aExistingDirs = $oDependenciesHandler->ListAllFoldersAbsPaths();
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
$aExtra = array_diff($aAllowedAndDeniedDirs, $aExistingDirs);