diff --git a/src/Utils/Config.php b/src/Utils/Config.php index 8c3cc6a..14ceee9 100644 --- a/src/Utils/Config.php +++ b/src/Utils/Config.php @@ -3,175 +3,41 @@ namespace App\Utils; -use BenTools\CartesianProduct\CartesianProduct; +use App\Utils\Config\AdapterInterface; -use InvalidArgumentException; +use \ReflectionClass; +use \ReflectionMethod; final class Config { - private $basePath; - private $loadedContent = []; + private $adapter; - private function loadJson(string $fileName): void { - if (isset($this->loadedContent[$fileName]) === true) { - return; - } - - $filePath = $this->basePath . DIRECTORY_SEPARATOR . $fileName; - if (! is_file($filePath)) { - throw new InvalidArgumentException('$fileName must be a valid file'); - } - - $raw = file_get_contents($filePath); - if ($raw === false) { - throw new InvalidArgumentException('Could not read from file'); - } - - $json = json_decode($raw, true); - if ($json === false) { - throw new InvalidArgumentException('Could not decode json data'); - } - - $this->loadedContent[$fileName] = $json; + public function __construct(AdapterInterface $adapter) { + $this->adapter = $adapter; + $this->methods = $this->getAdapterPublicMethods(); } - public function __construct(string $basePath) { - $basePath = rtrim($basePath, DIRECTORY_SEPARATOR); - if (! is_dir($basePath)) { - throw new InvalidArgumentException('$basePath must be a valid directory'); - } - - $this->basePath = $basePath; - } + public function __call(string $method, array $arguments): array { + $argument = $this->getArgument($arguments); - public function getExtensionSpecs(string $extName = null): array { - $this->loadJson('extensions.json'); - if ($extName !== null) { - return $this->loadedContent['extensions.json'][$extName] ?? []; + if (in_array($method, $this->methods)) { + return $this->adapter->$method($argument); } - - $extensions = array_filter( - $this->loadedContent['extensions.json'], - function (array $specs): bool { - return (isset($specs['disabled']) === false || $specs['disabled'] === false); - }, - ARRAY_FILTER_USE_BOTH - ); - ksort($extensions); - - return $extensions; - } - - public function getExtensionList(): array { - return array_keys($this->getExtensionSpecs()); } + + private function getAdapterPublicMethods(): array { + $interface = new ReflectionClass('App\Utils\Config\AdapterInterface'); + $reflection = $interface->getMethods(ReflectionMethod::IS_PUBLIC); - public function getExtensionUrls(): array { - return array_map( - function (array $items): string { - return $items['build']['url'] ?? ''; - }, - $this->getExtensionSpecs() - ); + return array_map(function ($item) { + return $item->name; + }, $reflection); } - public function getOsSpecs(string $osName = null): array { - $this->loadJson('operating-systems.json'); - if ($osName !== null) { - return $this->loadedContent['operating-systems.json'][$osName] ?? []; + private function getArgument($arguments): ?string { + if (empty($arguments)) { + return null; } - $os = array_filter( - $this->loadedContent['operating-systems.json'], - function (array $specs): bool { - return (isset($specs['disabled']) === false || $specs['disabled'] === false); - }, - ARRAY_FILTER_USE_BOTH - ); - ksort($os); - - return $os; - } - - public function getOsList(): array { - return array_keys($this->getOSSpecs()); - } - - public function getPhpList(): array { - $this->loadJson('php-versions.json'); - $php = array_map( - function (array $items): string { - return implode('-', array_filter($items)); - }, - iterator_to_array( - new CartesianProduct( - [ - $this->loadedContent['php-versions.json'], - ['', 'zts'] - ] - ) - ) - ); - sort($php); - - return $php; - } - - public function getVersionList(): array { - return ['pecl', 'dev']; - } - - public function getExtensionMatrix(): array { - $ext = array_map( - function (array $items): string { - return implode(':', $items); - }, - iterator_to_array( - new CartesianProduct( - [ - $this->getExtensionList(), - $this->getVersionList() - ] - ) - ) - ); - sort($ext); - - return $ext; - } - - public function getPhpMatrix(): array { - $php = array_map( - function (array $items): string { - return implode('-', $items); - }, - iterator_to_array( - new CartesianProduct( - [ - $this->getPhpList(), - $this->getOSList() - ] - ) - ) - ); - - sort($php); - - return $php; - } - - public function getBuildMatrix(): array { - return array_map( - function (array $items): string { - return implode('@', $items); - }, - iterator_to_array( - new CartesianProduct( - [ - $this->getExtensionMatrix(), - $this->getPhpMatrix() - ] - ) - ) - ); + return array_shift($arguments); } } diff --git a/src/Utils/Config/AdapterInterface.php b/src/Utils/Config/AdapterInterface.php new file mode 100644 index 0000000..5a65bf4 --- /dev/null +++ b/src/Utils/Config/AdapterInterface.php @@ -0,0 +1,17 @@ +loadedContent[$fileName]) === true) { + return; + } + + $filePath = $this->basePath . DIRECTORY_SEPARATOR . $fileName; + if (! is_file($filePath)) { + throw new InvalidArgumentException('$fileName must be a valid file'); + } + + $raw = file_get_contents($filePath); + if ($raw === false) { + throw new InvalidArgumentException('Could not read from file'); + } + + $json = json_decode($raw, true); + if ($json === false) { + throw new InvalidArgumentException('Could not decode json data'); + } + + $this->loadedContent[$fileName] = $json; + } + + public function __construct(string $basePath) { + $basePath = rtrim($basePath, DIRECTORY_SEPARATOR); + if (! is_dir($basePath)) { + throw new InvalidArgumentException('$basePath must be a valid directory'); + } + + $this->basePath = $basePath; + } + + public function getExtensionSpecs(string $extName = null): array { + $this->loadJson('extensions.json'); + if ($extName !== null) { + return $this->loadedContent['extensions.json'][$extName] ?? []; + } + + $extensions = array_filter( + $this->loadedContent['extensions.json'], + function (array $specs): bool { + return (isset($specs['disabled']) === false || $specs['disabled'] === false); + }, + ARRAY_FILTER_USE_BOTH + ); + ksort($extensions); + + return $extensions; + } + + public function getExtensionList(): array { + return array_keys($this->getExtensionSpecs()); + } + + public function getExtensionUrls(): array { + return array_map( + function (array $items): string { + return $items['build']['url'] ?? ''; + }, + $this->getExtensionSpecs() + ); + } + + public function getOSSpecs(string $osName = null): array { + $this->loadJson('operating-systems.json'); + if ($osName !== null) { + return $this->loadedContent['operating-systems.json'][$osName] ?? []; + } + + $os = array_filter( + $this->loadedContent['operating-systems.json'], + function (array $specs): bool { + return (isset($specs['disabled']) === false || $specs['disabled'] === false); + }, + ARRAY_FILTER_USE_BOTH + ); + ksort($os); + + return $os; + } + + public function getOSList(): array { + return array_keys($this->getOSSpecs()); + } + + public function getPHPList(): array { + $this->loadJson('php-versions.json'); + $php = array_map( + function (array $items): string { + return implode('-', array_filter($items)); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->loadedContent['php-versions.json'], + ['', 'zts'] + ] + ) + ) + ); + sort($php); + + return $php; + } + + public function getVersionList(): array { + return ['pecl', 'dev']; + } + + public function getExtensionMatrix(): array { + $ext = array_map( + function (array $items): string { + return implode(':', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->getExtensionList(), + $this->getVersionList() + ] + ) + ) + ); + sort($ext); + + return $ext; + } + + public function getPHPMatrix(): array { + $php = array_map( + function (array $items): string { + return implode('-', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->getPHPList(), + $this->getOSList() + ] + ) + ) + ); + + sort($php); + + return $php; + } + + public function getBuildMatrix(): array { + return array_map( + function (array $items): string { + return implode('@', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->getExtensionMatrix(), + $this->getPHPMatrix() + ] + ) + ) + ); + } +} diff --git a/tests/Utils/Config/Adapters/JsonAdapterTest.php b/tests/Utils/Config/Adapters/JsonAdapterTest.php new file mode 100644 index 0000000..e60e4d9 --- /dev/null +++ b/tests/Utils/Config/Adapters/JsonAdapterTest.php @@ -0,0 +1,191 @@ +adapter = new JsonAdapter($configPath); + + $jsonConfig = file_get_contents($configPath . DIRECTORY_SEPARATOR . 'extensions.json'); + $this->extensions = json_decode($jsonConfig, true); + + $jsonConfig = file_get_contents($configPath . DIRECTORY_SEPARATOR . 'operating-systems.json'); + $this->operatingSystems = json_decode($jsonConfig, true); + + $jsonConfig = file_get_contents($configPath . DIRECTORY_SEPARATOR . 'php-versions.json'); + $this->phpVersions = json_decode($jsonConfig, true); + } + + public function testSingleExtensionSpecs(): void { + $this->assertEquals( + $this->adapter->getExtensionSpecs('amqp'), + $this->extensions['amqp'] + ); + } + + public function testAllExtensionSpecs(): void { + $this->assertEquals( + $this->adapter->getExtensionSpecs(), + $this->extensions + ); + } + + public function testExtensionList(): void { + $expected = ['ahocorasick', 'amqp']; + + $this->assertEquals( + $this->adapter->getExtensionList(), + $expected + ); + } + + public function testExtensionUrls(): void { + $expected = [ + 'ahocorasick' => 'https://github.com/ph4r05/php_aho_corasick', + 'amqp' => 'https://github.com/php-amqp/php-amqp' + ]; + + $this->assertEquals( + $this->adapter->getExtensionUrls(), + $expected + ); + } + + public function testSingleOSSpecs(): void { + $this->assertEquals( + $this->adapter->getOSSpecs('alpine'), + $this->operatingSystems['alpine'] + ); + } + + public function testOSSpecs(): void { + $expected = [ + 'buster' => $this->operatingSystems['buster'] + ]; + + $this->assertEquals( + $this->adapter->getOSSpecs(), + $expected + ); + } + + public function testOSList(): void { + $expected = ['buster']; + + $this->assertEquals( + $this->adapter->getOSList(), + $expected + ); + } + + public function testPHPList(): void { + $expected = array_map( + function (array $items): string { + return implode('-', array_filter($items)); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->phpVersions, + ['', 'zts'] + ] + ) + ) + ); + sort($expected); + + $this->assertEquals( + $this->adapter->getPHPList(), + $expected + ); + } + + public function testVersionList(): void { + $expected = [ + 'pecl', + 'dev' + ]; + + $this->assertEquals( + $this->adapter->getVersionList(), + $expected + ); + } + + public function testExtensionMatrix(): void { + $expected = array_map( + function (array $items): string { + return implode(':', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->adapter->getExtensionList(), + $this->adapter->getVersionList() + ] + ) + ) + ); + sort($expected); + + $this->assertEquals( + $this->adapter->getExtensionMatrix(), + $expected + ); + } + + public function testPHPMatrix(): void { + $expected = array_map( + function (array $items): string { + return implode('-', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->adapter->getPHPList(), + $this->adapter->getOSList() + ] + ) + ) + ); + sort($expected); + + $this->assertEquals( + $this->adapter->getPHPMatrix(), + $expected + ); + } + + public function testBuildMatrix(): void { + $expected = array_map( + function (array $items): string { + return implode('@', $items); + }, + iterator_to_array( + new CartesianProduct( + [ + $this->adapter->getExtensionMatrix(), + $this->adapter->getPHPMatrix() + ] + ) + ) + ); + sort($expected); + + $this->assertEquals( + $this->adapter->getBuildMatrix(), + $expected + ); + } +} diff --git a/tests/fixtures/config/extensions.json b/tests/fixtures/config/extensions.json new file mode 100644 index 0000000..efd12c4 --- /dev/null +++ b/tests/fixtures/config/extensions.json @@ -0,0 +1,32 @@ +{ + "ahocorasick": { + "build": { + "flag": "--enable-ahocorasick", + "type": "git", + "url": "https://github.com/ph4r05/php_aho_corasick" + }, + "require": { + "min": "7.3.99" + }, + "summary": "Effective Aho-Corasick string pattern matching algorithm" + }, + "amqp": { + "build": { + "deps": { + "alpine": [ + "rabbitmq-c-dev" + ], + "buster": [ + "librabbitmq-dev" + ] + }, + "flag": "--with-amqp", + "type": "git", + "url": "https://github.com/php-amqp/php-amqp" + }, + "require": { + "min": "5.6.0" + }, + "summary": "Communicate with any AMQP compliant server" + } +} diff --git a/tests/fixtures/config/operating-systems.json b/tests/fixtures/config/operating-systems.json new file mode 100644 index 0000000..c08e6dc --- /dev/null +++ b/tests/fixtures/config/operating-systems.json @@ -0,0 +1,34 @@ +{ + "alpine": { + "deps": { + "cmd": "apk add --no-cache", + "list": [ + "git", + "autoconf", + "build-base" + ] + }, + "disabled": true, + "pre": [ + "apk update", + "apk upgrade" + ] + }, + "buster": { + "deps": { + "cmd": "apt install -y --no-install-recommends", + "list": [ + "git", + "autoconf", + "build-essential" + ] + }, + "pre": [ + "apt update", + "apt full-upgrade -y" + ], + "post": [ + "rm -rf /var/lib/apt/lists/*" + ] + } +} diff --git a/tests/fixtures/config/php-versions.json b/tests/fixtures/config/php-versions.json new file mode 100644 index 0000000..9b97154 --- /dev/null +++ b/tests/fixtures/config/php-versions.json @@ -0,0 +1,5 @@ +[ + "7.3.25", + "7.4.13", + "8.0.0" +]