Files
keystone/app/Services/Compose/ComposeRenderer.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);
}
}