-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6456a7d
commit fec18b2
Showing
10 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
<?php declare(strict_types=1); | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
namespace Framework\CLI\Commands; | ||
|
||
use Framework\CLI\CLI; | ||
use Framework\CLI\Command; | ||
use Framework\Helpers\Isolation; | ||
use Framework\MVC\App; | ||
use RuntimeException; | ||
|
||
/** | ||
* Class MergeConfigs. | ||
* | ||
* @package dev-commands | ||
*/ | ||
class MergeConfigs extends Command | ||
{ | ||
protected string $description = 'Merge configuration files.'; | ||
protected string $group = 'Configs'; | ||
protected array $options = [ | ||
'--extension' => 'Set a custom file extension. Default is ".php"', | ||
'-i' => 'Ignore files that do not return an array in the correct format.', | ||
]; | ||
protected string $usage = 'mergeconfigs [options] -- [directory]'; | ||
|
||
protected function getDirectory() : string | ||
{ | ||
$dir = $this->console->getArgument(0); | ||
if ($dir) { | ||
return $this->validateDir($dir); | ||
} | ||
$options = []; | ||
foreach (['config', 'configs'] as $option) { | ||
$dir = \getcwd() . '/' . $option; | ||
if (\is_dir($dir)) { | ||
$options[] = $option; | ||
} | ||
} | ||
$dir = \defined('IS_IN_PHPUNIT') && IS_IN_PHPUNIT | ||
? __DIR__ . '/../tests/configs/ok' | ||
: CLI::prompt('Config directory', $options); | ||
return $this->validateDir($dir); | ||
} | ||
|
||
protected function validateDir(string $dir) : string | ||
{ | ||
if (!\is_dir($dir)) { | ||
throw new RuntimeException('Config directory "' . $dir . '" does not exist'); | ||
} | ||
return $dir; | ||
} | ||
|
||
protected function getExtension() : string | ||
{ | ||
$extension = $this->console->getOption('extension'); | ||
if ($extension === true || $extension === null) { | ||
return '.php'; | ||
} | ||
return $extension; // @phpstan-ignore-line; | ||
} | ||
|
||
public function run() : void | ||
{ | ||
$dir = $this->getDirectory(); | ||
$extension = $this->getExtension(); | ||
$config = []; | ||
$files = App::locator()->listFiles($dir); | ||
foreach ($files as $file) { | ||
if (!\str_ends_with($file, $extension)) { | ||
continue; | ||
} | ||
\ob_start(); | ||
$contents = Isolation::require($file); | ||
\ob_end_clean(); | ||
if (!\is_array($contents)) { | ||
if ($this->allowIgnore()) { | ||
continue; | ||
} | ||
throw new RuntimeException( | ||
'Config file "' . $file . '" does not return an array' | ||
); | ||
} | ||
if (empty($contents)) { | ||
if ($this->allowIgnore()) { | ||
continue; | ||
} | ||
throw new RuntimeException( | ||
'Config file "' . $file . '" return an empty array' | ||
); | ||
} | ||
foreach ($contents as $key => $values) { | ||
if (!\is_string($key)) { | ||
if ($this->allowIgnore()) { | ||
continue 2; | ||
} | ||
throw new RuntimeException( | ||
'Config file "' . $file . '" return invalid keys (must be strings)' | ||
); | ||
} | ||
if (!\is_array($values)) { | ||
if ($this->allowIgnore()) { | ||
continue 2; | ||
} | ||
throw new RuntimeException( | ||
'Config file "' . $file . '" return invalid values (must be arrays)' | ||
); | ||
} | ||
} | ||
$service = \substr($file, \strrpos($file, \DIRECTORY_SEPARATOR) + 1); | ||
$service = \substr($service, 0, -\strlen($extension)); | ||
$config[$service] = $contents; | ||
} | ||
$config = \var_export($config, true); | ||
CLI::write('<?php'); | ||
CLI::write('// Do not edit this file. It is created automatically.'); | ||
CLI::write('// Created at: ' . \gmdate('Y-m-d H:i:s') . ' UTC'); | ||
CLI::write('return ' . $config . ';'); | ||
} | ||
|
||
public function allowIgnore() : bool | ||
{ | ||
return (bool) $this->console->getOption('i'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
namespace Tests\CLI\Commands; | ||
|
||
use Framework\Config\Config; | ||
use Framework\Testing\TestCase; | ||
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; | ||
|
||
#[RunTestsInSeparateProcesses] | ||
final class MergeConfigsTest extends TestCase | ||
{ | ||
protected function prepareDefaults() : void | ||
{ | ||
$this->config = new Config([ | ||
'console' => [ | ||
'default' => [ | ||
'directories' => [ | ||
__DIR__ . '/../src', | ||
], | ||
], | ||
], | ||
]); | ||
parent::prepareDefaults(); | ||
} | ||
|
||
protected function makeDir(string $relativePath) : string | ||
{ | ||
$dir = __DIR__ . \DIRECTORY_SEPARATOR . $relativePath; | ||
return \str_replace(' ', '\ ', $dir); | ||
} | ||
|
||
protected function runCli(string $relativePath, string $append = '') : void | ||
{ | ||
$dir = $this->makeDir($relativePath); | ||
$append = $append !== '' ? ' ' . $append : ''; | ||
$this->app->runCli('mergeconfigs ' . $dir . $append); | ||
} | ||
|
||
public function testNoDir() : void | ||
{ | ||
$this->app->runCli('mergeconfigs'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
|
||
public function testCustomExtension() : void | ||
{ | ||
$this->app->runCli('mergeconfigs --extension=.php'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
|
||
public function testInvalidDir() : void | ||
{ | ||
$this->expectException(\RuntimeException::class); | ||
$path = $this->makeDir('foo'); | ||
$this->expectExceptionMessage('Config directory "' . $path . '" does not exist'); | ||
$this->runCli('foo'); | ||
} | ||
|
||
public function testEmptyDir() : void | ||
{ | ||
$this->runCli('configs/empty-dir'); | ||
self::assertStdoutContains('<?php'); | ||
self::assertStdoutContains('// Do not edit this file. It is created automatically.'); | ||
self::assertStdoutContains('return array ('); | ||
self::assertStdoutContains(');'); | ||
self::assertStdoutNotContains("'bar' =>"); | ||
} | ||
|
||
public function testOk() : void | ||
{ | ||
$this->runCli('configs/ok'); | ||
self::assertStdoutContains('<?php'); | ||
self::assertStdoutContains('// Do not edit this file. It is created automatically.'); | ||
self::assertStdoutContains('return array ('); | ||
self::assertStdoutContains("'bar' =>"); | ||
self::assertStdoutContains("'key' => 'value'"); | ||
self::assertStdoutContains("'other' =>"); | ||
self::assertStdoutContains("'foo' => 'baz'"); | ||
self::assertStdoutContains(');'); | ||
} | ||
|
||
public function testNotArray() : void | ||
{ | ||
$this->expectException(\RuntimeException::class); | ||
$path = \realpath(__DIR__ . '/configs/not-array/foo.php'); | ||
$this->expectExceptionMessage('Config file "' . $path . '" does not return an array'); | ||
$this->runCli('configs/not-array'); | ||
} | ||
|
||
public function testNotArrayWithIgnore() : void | ||
{ | ||
$this->runCli('configs/not-array', '-i'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
|
||
public function testEmptyArray() : void | ||
{ | ||
$this->expectException(\RuntimeException::class); | ||
$path = \realpath(__DIR__ . '/configs/empty-array/foo.php'); | ||
$this->expectExceptionMessage('Config file "' . $path . '" return an empty array'); | ||
$this->runCli('configs/empty-array'); | ||
} | ||
|
||
public function testEmptyArrayWithIgnore() : void | ||
{ | ||
$this->runCli('configs/empty-array', '-i'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
|
||
public function testInvalidKeys() : void | ||
{ | ||
$this->expectException(\RuntimeException::class); | ||
$path = \realpath(__DIR__ . '/configs/invalid-keys/foo.php'); | ||
$this->expectExceptionMessage('Config file "' . $path . '" return invalid keys (must be strings)'); | ||
$this->runCli('configs/invalid-keys'); | ||
} | ||
|
||
public function testInvalidKeysWithIgnore() : void | ||
{ | ||
$this->runCli('configs/invalid-keys', '-i'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
|
||
public function testInvalidValues() : void | ||
{ | ||
$this->expectException(\RuntimeException::class); | ||
$path = \realpath(__DIR__ . '/configs/invalid-values/foo.php'); | ||
$this->expectExceptionMessage('Config file "' . $path . '" return invalid values (must be arrays)'); | ||
$this->runCli('configs/invalid-values'); | ||
} | ||
|
||
public function testInvalidValuesWithIgnore() : void | ||
{ | ||
$this->runCli('configs/invalid-values', '-i'); | ||
self::assertStdoutContains('<?php'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
return []; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
return [ | ||
1 => [], | ||
3 => [], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
return [ | ||
'foo' => 'bar', | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
return [ | ||
'default' => [ | ||
'key' => 'value', | ||
], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
/* | ||
* This file is part of Aplus Framework Dev Commands Library. | ||
* | ||
* (c) Natan Felles <natanfelles@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
return [ | ||
'default' => [ | ||
'key' => 'value', | ||
], | ||
'other' => [ | ||
'foo' => 'baz', | ||
], | ||
]; |