biurad /
php-monorepo
| 1 | <?php declare(strict_types=1); |
||
| 2 | |||
| 3 | /* |
||
| 4 | * This file is part of Biurad opensource projects. |
||
| 5 | * |
||
| 6 | * @copyright 2022 Biurad Group (https://biurad.com/) |
||
| 7 | * @license https://opensource.org/licenses/BSD-3-Clause License |
||
| 8 | * |
||
| 9 | * For the full copyright and license information, please view the LICENSE |
||
| 10 | * file that was distributed with this source code. |
||
| 11 | */ |
||
| 12 | |||
| 13 | namespace Biurad\Monorepo; |
||
| 14 | |||
| 15 | use Symfony\Component\OptionsResolver\Exception\{AccessException, InvalidOptionsException}; |
||
| 16 | use Symfony\Component\OptionsResolver\{Options, OptionsResolver}; |
||
| 17 | use Symfony\Component\Yaml\Yaml; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * Monorepo configuration (.monorepo). |
||
| 21 | * |
||
| 22 | * @author Divine Niiquaye Ibok <[email protected]> |
||
| 23 | */ |
||
| 24 | final class Config implements \ArrayAccess, \Countable |
||
| 25 | { |
||
| 26 | /** @var array<string,mixed> */ |
||
| 27 | private array $config; |
||
| 28 | |||
| 29 | public function __construct(string $rootPath, string $cachePath = null, bool $reclone) |
||
| 30 | { |
||
| 31 | if (!\file_exists($configFile = ($this->config['path'] = $rootPath).'/.monorepo')) { |
||
| 32 | throw new \RuntimeException(\sprintf('Config file "%s" does not exist.', $configFile)); |
||
| 33 | } |
||
| 34 | |||
| 35 | $workers = []; |
||
| 36 | $this->config['reclone'] = $reclone; |
||
| 37 | $options = new OptionsResolver(); |
||
| 38 | $options |
||
| 39 | ->define('base_url')->default(null)->allowedTypes('string', 'null') |
||
| 40 | ->define('branch_filter')->default(null)->allowedTypes('string', 'null') |
||
| 41 | ->define('extra')->default([])->allowedTypes('array') |
||
| 42 | ->define('workers')->default([])->allowedTypes('array') |
||
| 43 | ->normalize(function (Options $options, array $value): array { |
||
| 44 | if (\array_is_list($value)) { |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 45 | return ['main' => $value]; |
||
| 46 | } |
||
| 47 | |||
| 48 | foreach ($value as $k => $v) { |
||
| 49 | $v = \is_string($v) ? [$v] : $v; |
||
| 50 | |||
| 51 | if (!\is_string($k)) { |
||
| 52 | throw new InvalidOptionsException('Expected workers config to begin with a string key.'); |
||
| 53 | } |
||
| 54 | |||
| 55 | if (!\is_array($v) || !\array_is_list($v)) { |
||
| 56 | throw new InvalidOptionsException('Expected workers config\'s key value be a list of workers classes.'); |
||
| 57 | } |
||
| 58 | } |
||
| 59 | |||
| 60 | return $value; |
||
| 61 | }) |
||
| 62 | ->define('repositories') |
||
| 63 | ->default(function (OptionsResolver $options, Options $parent) use (&$workers): void { |
||
| 64 | $workers = \array_keys($parent['workers']); |
||
| 65 | $options->setPrototype(true) |
||
| 66 | ->define('url')->default(null)->allowedTypes('string', 'null')->required() |
||
| 67 | ->define('merge')->default(false)->allowedTypes('bool') |
||
| 68 | ->define('path') |
||
| 69 | ->allowedTypes('string') |
||
| 70 | ->default(\Closure::bind(fn (Options $options): string => $options->prototypeIndex, null, $options)) |
||
|
0 ignored issues
–
show
|
|||
| 71 | ->normalize(fn (Options $options, string $value): string => \trim($value, '/')) |
||
| 72 | ->define('workers')->default($workers)->allowedTypes('array') |
||
| 73 | ->normalize(function (Options $options, array $value) use ($workers): array { |
||
| 74 | foreach ($value as $worker) { |
||
| 75 | if (!\in_array($worker, $workers, true)) { |
||
| 76 | throw new InvalidOptionsException(\sprintf('The worker "%s" for monorepo\'s path "%s" does not exist.', $worker, $options['path'])); |
||
| 77 | } |
||
| 78 | } |
||
| 79 | |||
| 80 | return $value; |
||
| 81 | }) |
||
| 82 | ; |
||
| 83 | })->allowedTypes('array') |
||
| 84 | ; |
||
| 85 | |||
| 86 | $options->setRequired(['base_url', 'branch_filter', 'workers', 'repositories']); |
||
| 87 | $this->config += $options->resolve(\function_exists('yaml_parse_file') ? yaml_parse_file($configFile) : Yaml::parseFile($configFile)); |
||
| 88 | $this->config['cache'] = $cachePath ?? $this->config['path'].'/.monorepo-cache'; |
||
| 89 | } |
||
| 90 | |||
| 91 | /** |
||
| 92 | * {@inheritdoc} |
||
| 93 | */ |
||
| 94 | public function offsetGet(mixed $offset): mixed |
||
| 95 | { |
||
| 96 | if (!\is_string($offset)) { |
||
| 97 | throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset))); |
||
| 98 | } |
||
| 99 | |||
| 100 | return $this->config[$offset] ?? throw new InvalidOptionsException(\sprintf('Value for "%s" does not exist.', $offset)); |
||
| 101 | } |
||
| 102 | |||
| 103 | /** |
||
| 104 | * {@inheritdoc} |
||
| 105 | */ |
||
| 106 | public function offsetExists(mixed $offset): bool |
||
| 107 | { |
||
| 108 | if (!\is_string($offset)) { |
||
| 109 | throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset))); |
||
| 110 | } |
||
| 111 | |||
| 112 | return \array_key_exists($offset, $this->config); |
||
| 113 | } |
||
| 114 | |||
| 115 | /** |
||
| 116 | * {@inheritdoc} |
||
| 117 | */ |
||
| 118 | public function offsetSet(mixed $offset, mixed $value): void |
||
| 119 | { |
||
| 120 | throw new AccessException('Unexpected call for setting config, kindly define config in the .monorepo file.'); |
||
| 121 | } |
||
| 122 | |||
| 123 | /** |
||
| 124 | * {@inheritdoc} |
||
| 125 | */ |
||
| 126 | public function offsetUnset(mixed $offset): void |
||
| 127 | { |
||
| 128 | if (!\is_string($offset)) { |
||
| 129 | throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset))); |
||
| 130 | } |
||
| 131 | |||
| 132 | unset($this->config[$offset]); |
||
| 133 | } |
||
| 134 | |||
| 135 | /** |
||
| 136 | * {@inheritdoc} |
||
| 137 | */ |
||
| 138 | public function count(): int |
||
| 139 | { |
||
| 140 | return \count($this->config); |
||
| 141 | } |
||
| 142 | } |
||
| 143 |