150 lines
3.9 KiB
PHP
150 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Compose;
|
|
|
|
use App\Drivers\Concerns\RendersCompose;
|
|
use App\Models\Service;
|
|
use InvalidArgumentException;
|
|
|
|
class ComposeRenderer
|
|
{
|
|
public function render(Service $service): string
|
|
{
|
|
$driver = $service->driver();
|
|
|
|
if (! $driver instanceof RendersCompose) {
|
|
throw new InvalidArgumentException("Driver [{$service->driver_name}] cannot render Docker Compose.");
|
|
}
|
|
|
|
$composeService = $driver->composeService();
|
|
|
|
if ($service->default_cpu_limit && ! isset($composeService['cpus'])) {
|
|
$composeService['cpus'] = (string) $service->default_cpu_limit;
|
|
}
|
|
|
|
if ($service->default_memory_limit_mb && ! isset($composeService['mem_limit'])) {
|
|
$composeService['mem_limit'] = "{$service->default_memory_limit_mb}m";
|
|
$composeService['memswap_limit'] = "{$service->default_memory_limit_mb}m";
|
|
}
|
|
|
|
$document = [
|
|
'services' => [
|
|
$this->serviceKey($service) => $composeService,
|
|
],
|
|
];
|
|
|
|
$volumes = array_filter($driver->composeVolumes(), fn (mixed $volume): bool => $volume !== false);
|
|
|
|
if ($volumes !== []) {
|
|
$document['volumes'] = $volumes;
|
|
}
|
|
|
|
return $this->toYaml($document);
|
|
}
|
|
|
|
public function renderEnvironmentFile(Service $service): string
|
|
{
|
|
$driver = $service->driver();
|
|
|
|
if (! method_exists($driver, 'environmentExports')) {
|
|
return '';
|
|
}
|
|
|
|
return collect($driver->environmentExports())
|
|
->map(fn (mixed $value, string $key): string => $key.'='.$this->formatEnvValue($value))
|
|
->implode("\n");
|
|
}
|
|
|
|
private function serviceKey(Service $service): string
|
|
{
|
|
return str($service->name)->slug('_')->value() ?: 'service';
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $document
|
|
*/
|
|
private function toYaml(array $document, int $indent = 0): string
|
|
{
|
|
$lines = [];
|
|
|
|
foreach ($document as $key => $value) {
|
|
$prefix = str_repeat(' ', $indent);
|
|
|
|
if (is_array($value)) {
|
|
if ($value === []) {
|
|
$lines[] = "{$prefix}{$key}: []";
|
|
|
|
continue;
|
|
}
|
|
|
|
$lines[] = "{$prefix}{$key}:";
|
|
$lines[] = $this->arrayToYaml($value, $indent + 1);
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($value === null) {
|
|
$lines[] = "{$prefix}{$key}: {}";
|
|
|
|
continue;
|
|
}
|
|
|
|
$lines[] = "{$prefix}{$key}: ".$this->formatScalar($value);
|
|
}
|
|
|
|
return implode("\n", array_filter($lines))."\n";
|
|
}
|
|
|
|
/**
|
|
* @param array<mixed> $items
|
|
*/
|
|
private function arrayToYaml(array $items, int $indent): string
|
|
{
|
|
if (array_is_list($items)) {
|
|
return $this->listToYaml($items, $indent);
|
|
}
|
|
|
|
return $this->toYaml($items, $indent);
|
|
}
|
|
|
|
/**
|
|
* @param array<int, mixed> $items
|
|
*/
|
|
private function listToYaml(array $items, int $indent): string
|
|
{
|
|
$lines = [];
|
|
$prefix = str_repeat(' ', $indent);
|
|
|
|
foreach ($items as $item) {
|
|
if (is_array($item)) {
|
|
$lines[] = "{$prefix}-";
|
|
$lines[] = $this->arrayToYaml($item, $indent + 1);
|
|
|
|
continue;
|
|
}
|
|
|
|
$lines[] = "{$prefix}- ".$this->formatScalar($item);
|
|
}
|
|
|
|
return implode("\n", $lines);
|
|
}
|
|
|
|
private function formatScalar(mixed $value): string
|
|
{
|
|
if (is_bool($value)) {
|
|
return $value ? 'true' : 'false';
|
|
}
|
|
|
|
if (is_numeric($value)) {
|
|
return (string) $value;
|
|
}
|
|
|
|
return '"'.str_replace('"', '\"', (string) $value).'"';
|
|
}
|
|
|
|
private function formatEnvValue(mixed $value): string
|
|
{
|
|
return str_replace(["\n", "\r"], ['\n', ''], (string) $value);
|
|
}
|
|
}
|