diff --git a/src/Module/ModuleFilter.php b/src/Module/ModuleFilter.php new file mode 100644 index 0000000..62b6dab --- /dev/null +++ b/src/Module/ModuleFilter.php @@ -0,0 +1,28 @@ +activeModules) || in_array($moduleName, $this->activeModules, true); + } +} diff --git a/src/Module/ModuleFilterInterface.php b/src/Module/ModuleFilterInterface.php new file mode 100644 index 0000000..82e31df --- /dev/null +++ b/src/Module/ModuleFilterInterface.php @@ -0,0 +1,10 @@ +io->debug( + sprintf('Loading module filter configuration at %s', $configurationFilePath), + ); + + $configurationData = $this->readJsonFile($configurationFilePath); + if (!isset($configurationData)) { + return ModuleFilter::unrestricted(); + } + + $localConfigurationData = $this->readJsonFile($localConfigurationFilePath); + + $mergedConfiguration = array_values(array_unique([...$configurationData->core, ...($localConfigurationData ?? [])])); + + return ModuleFilter::restrictedTo($mergedConfiguration); + } + + private function readJsonFile(string $filePath): ?object + { + $fileContents = @file_get_contents($filePath); + if ($fileContents === false) { + $this->io->warning('No module filter configuration found'); + + return null; + } + + try { + $jsonData = json_decode($fileContents, false, 512, JSON_OBJECT_AS_ARRAY | JSON_THROW_ON_ERROR); + } catch (JsonException $exception) { + $this->io->warning(sprintf('Invalid module filter configuration: %s', $exception->getMessage())); + + return null; + } + + return $jsonData; + } +} diff --git a/src/Module/ModuleIncludeAllFilter.php b/src/Module/ModuleIncludeAllFilter.php new file mode 100644 index 0000000..34d48fa --- /dev/null +++ b/src/Module/ModuleIncludeAllFilter.php @@ -0,0 +1,13 @@ +moduleFilter = $moduleFilter; $this->io = $io; } /** * @return ModulePackage[] */ - public function load(string $basePath): iterable + public function load(string $basePath, bool $forceAll = false): iterable { $this->io->debug( sprintf( @@ -40,7 +42,11 @@ public function load(string $basePath): iterable ); foreach ($this->scanForComposerFiles($basePath) as $composerFile) { - yield $this->loadModule($composerFile); + $moduleName = basename(dirname($composerFile)); + + if ($forceAll || $this->moduleFilter->shouldLoad($moduleName)) { + yield $this->loadModule($composerFile); + } } } diff --git a/src/Plugin/MergePlugin.php b/src/Plugin/MergePlugin.php index ecb6b7b..31b0505 100644 --- a/src/Plugin/MergePlugin.php +++ b/src/Plugin/MergePlugin.php @@ -4,6 +4,8 @@ namespace Artemeon\Composer\Plugin; +use Artemeon\Composer\Module\ModuleFilterLoader; +use Artemeon\Composer\Module\ModuleIncludeAllFilter; use Artemeon\Composer\Module\ModulePackageLoader; use Composer\Composer; use Composer\DependencyResolver\Operation\InstallOperation; @@ -27,6 +29,8 @@ final class MergePlugin implements PluginInterface, EventSubscriberInterface private const CALLBACK_PRIORITY = 50000; private const MODULES_BASE_PATH = 'core'; private const OVERRIDDEN_MODULES = './module_*'; + private const FILTER_CONFIGURATION_PATH = './packageconfig.json'; + private const PROJECT = './.projectrc'; private Composer $composer; private IOInterface $io; @@ -39,7 +43,25 @@ public function activate(Composer $composer, IOInterface $io): void $this->composer = $composer; $this->io = $io; - $this->modulePackageLoader = new ModulePackageLoader($io); + $packageConfig = $composer->getPackage()->getExtra()['packageconfig'] ?? true; + if ($packageConfig) { + $project = 'default'; + if (is_file(self::PROJECT)) { + $project = trim(file_get_contents(self::PROJECT) ?? $project); + } + if (count($apps = glob('apps/*', GLOB_ONLYDIR)) === 1) { + $project = basename($apps[0]); + } + + $filterFilePath = sprintf('./apps/%s/%s', $project, self::FILTER_CONFIGURATION_PATH); + $localFilePath = self::FILTER_CONFIGURATION_PATH; + + $moduleFilter = (new ModuleFilterLoader($io))->load($filterFilePath, $localFilePath); + } else { + $moduleFilter = new ModuleIncludeAllFilter(); + } + + $this->modulePackageLoader = new ModulePackageLoader($moduleFilter, $io); } public function deactivate(Composer $composer, IOInterface $io): void @@ -117,7 +139,7 @@ private function mergeAutoloadOverrides(RootPackageInterface $rootPackage): void private function mergeRequires(RootPackageInterface $rootPackage): void { - foreach ($this->modulePackageLoader->load($this->getBasePath($rootPackage)) as $modulePackage) { + foreach ($this->modulePackageLoader->load($this->getBasePath($rootPackage), true) as $modulePackage) { $modulePackage->mergeRequires($rootPackage); } }