From 6320fcc8c067a744de393dccbc6bfb6dbc4602b7 Mon Sep 17 00:00:00 2001 From: Thomas Schneider Date: Fri, 27 Mar 2026 14:32:02 +0100 Subject: [PATCH] =?UTF-8?q?Docker-Compose-Service=20hinzugef=C3=BCgt=20und?= =?UTF-8?q?=20DDEV-Hooks=20f=C3=BCr=20Umgebungsvariablen=20konfiguriert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ddev/config.yaml | 3 + src/Service/Docker/DockerCompose.php | 232 +++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 src/Service/Docker/DockerCompose.php diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 000dc80..9178ab3 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -14,6 +14,9 @@ composer_version: "2" web_environment: [] corepack_enable: false omit_containers: [db] +hooks: + pre-start: + - exec-host: ddev dotenv set .ddev/.env --docker-dotenv-vars="$(docker compose -f .ddev/.ddev-docker-compose-full.yaml config | awk '/^[[:space:]]{2}web:$/ {inweb=1; next} inweb && /^[[:space:]]{4}environment:$/ {inenv=1; next} inenv && /^[[:space:]]{6}[A-Za-z0-9_]+:/ {gsub(/^[[:space:]]+|:$/, "", $1); print $1; next} inenv && /^[[:space:]]{4}[^[:space:]]/ {inenv=0} inweb && /^[[:space:]]{2}[^[:space:]]/ && !/^[[:space:]]{4}/ {inweb=0}' | sort -u | paste -sd, -)" # Key features of DDEV's config.yaml: diff --git a/src/Service/Docker/DockerCompose.php b/src/Service/Docker/DockerCompose.php new file mode 100644 index 0000000..a381966 --- /dev/null +++ b/src/Service/Docker/DockerCompose.php @@ -0,0 +1,232 @@ + + * Alle Rechte vorbehalten. + */ + +namespace App\Service\Docker; + +use App\Service\Process\CleanProcess; +use Dotenv\Dotenv; +use Exception; +use Spatie\Docker\Exceptions\CouldNotStartDockerContainer; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Process\Process; + +class DockerCompose +{ + protected string $composeCmd = 'compose'; + + protected float $startCommandTimeout = 600; + + protected string $name = ''; + + protected bool $daemonize = false; + + protected string $dockerHost = ''; + + protected string $workingDir = ''; + + + protected array $composeFiles = []; + + protected array $envFiles = []; + + protected array $inlineEnvFiles = []; + + /** + * @throws CouldNotStartDockerContainer + */ + public function up(array $optionalArgs = []): void + { + $process = $this->process('up', $optionalArgs); + $process->run(function ($type, $buffer): void + { + echo $buffer; + }); + +// if(!$process->isSuccessful()) +// { +// throw CouldNotStartDockerContainer::processFailed($this, $process); +// } + + $error = $process->getErrorOutput(); + + $dockerIdentifier = trim($process->getOutput()); + } + + + protected function process(string $cmd, array $optionalArgs = []): Process + { + $env = [...$this->loadDotEnv(), ...$this->parseInlineEnvFiles()]; + + if(!empty($env['DOCKER_HOST'])) + { + $this->dockerHost = $env['DOCKER_HOST']; + } + + return CleanProcess::fromShellCommandline( + command: implode(' ', [...$this->getBaseCommand(), $cmd, ...$this->getExtraOptions($optionalArgs)]), + cwd: $this->workingDir, + env: $env, + timeout: $this->startCommandTimeout, + ); + } + + + protected function getBaseCommand(): array + { + return [ + ...explode(' ', $this->composeCmd), + ...$this->getExtraDockerOptions(), + ]; + } + + + protected function getExtraDockerOptions(): array + { + $extraDockerOptions = []; + + if($this->dockerHost !== '') + { + $extraDockerOptions[] = "-H {$this->dockerHost}"; + } + + if($this->name !== '') + { + $extraDockerOptions[] = "-p {$this->name}"; + } + + if($this->composeFiles) + { + foreach($this->composeFiles as $file) + { + $extraDockerOptions[] = "--file {$file}"; + } + } + + if($this->envFiles) + { + foreach($this->envFiles as $file) + { + $extraDockerOptions[] = "--env-file {$file}"; + } + } + + return $extraDockerOptions; + } + + + protected function getExtraOptions(array $optionalArgs = []): array + { + $extraOptions = [...$optionalArgs]; + + if($this->daemonize && !in_array('-d', $extraOptions, true)) + { + $extraOptions[] = '-d'; + } + + return $extraOptions; + } + + + public function setName(string $name): self + { + $this->name = $name; + return $this; + } + + + public function setWorkingDir(string $workingDir): self + { + $this->workingDir = $workingDir; + return $this; + } + + + public function setStartCommandTimeout(float $startCommandTimeout): self + { + $this->startCommandTimeout = $startCommandTimeout; + return $this; + } + + + public function setDockerHost(string $dockerHost): self + { + $this->dockerHost = $dockerHost; + return $this; + } + + + public function daemonize(bool $daemonize): self + { + $this->daemonize = $daemonize; + return $this; + } + + + public function setComposeFiles(array $composeFiles): self + { + $this->composeFiles = [...$this->composeFiles, ...$composeFiles]; + return $this; + } + + + public function setEnvFiles(array $envFiles): self + { + $this->envFiles = [...$this->envFiles, ...$envFiles]; + return $this; + } + + + public function setInlineEnvFiles(array $envFiles): self + { + $this->inlineEnvFiles = [...$this->inlineEnvFiles, ...$envFiles]; + return $this; + } + + + public function getInlineEnvFiles(): array + { + return $this->inlineEnvFiles; + } + + + protected function parseInlineEnvFiles(): array + { + $env = []; + $filesystem = new Filesystem(); + + foreach ($this->inlineEnvFiles as $file) + { + try + { + if(!empty($envFromFile = Dotenv::parse($filesystem->readFile($file)))) + { + $env = [...$env, ...$envFromFile]; + } + } + catch(Exception $e) + { + continue; + } + } + + return $env; + } + + + protected function loadDotEnv(): array + { + try + { + return Dotenv::createArrayBacked($this->workingDir)->load(); + } + catch(Exception $e) + { + return []; + } + } +}