From 00b593d6d30facefded61d30d3d227ff265e414f Mon Sep 17 00:00:00 2001 From: Daniel Winning Date: Sat, 12 Apr 2025 19:09:40 +0100 Subject: [PATCH] Spins up basic PHP container --- config/.template.env | 5 ++- config/docker-compose.sample.yaml | 26 ------------ config/php-fpm/Dockerfile | 34 +++++++-------- config/php.yaml | 23 +++++----- src/Classes/OS/PortGenerator.php | 31 ++++++++++++++ src/Command/AbstractSpinnerCommand.php | 14 +++++-- src/Command/SpinCommand.php | 58 +++++++++++++++++++++++++- 7 files changed, 129 insertions(+), 62 deletions(-) delete mode 100644 config/docker-compose.sample.yaml create mode 100644 src/Classes/OS/PortGenerator.php diff --git a/config/.template.env b/config/.template.env index 60fecf1..2466925 100644 --- a/config/.template.env +++ b/config/.template.env @@ -1,3 +1,6 @@ PROJECT_DIRECTORY=%s PROJECT_NAME=%s -PHP_VERSION=%s \ No newline at end of file +PHP_VERSION=%s + +# Ports +PHP_PORT=%s \ No newline at end of file diff --git a/config/docker-compose.sample.yaml b/config/docker-compose.sample.yaml deleted file mode 100644 index f8ed8ff..0000000 --- a/config/docker-compose.sample.yaml +++ /dev/null @@ -1,26 +0,0 @@ -services: -# nginx: -# build: -# context: ./nginx -# ports: -# - ${NGINX_PORT}:80 -# volumes: -# - ${PROJECT_DIRECTORY}:/var/www/html:cached -# - ./nginx/conf.d:/etc/nginx/conf.d -# database: -# image: mysql:8.0 -# command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci -# ports: -# - ${MYSQL_PORT}:3306 -# expose: -# - "3306" -# environment: -# MYSQL_ROOT_PASSWORD: docker -# volumes: -# - ./data/${PROJECT_NAME}/mysql:/var/lib/mysql:cached -# cache: -# image: redis:latest -# ports: -# - ${REDIS_PORT}:6379 -# volumes: -# - ./data/${PROJECT_NAME}/redis:/data:cached \ No newline at end of file diff --git a/config/php-fpm/Dockerfile b/config/php-fpm/Dockerfile index b4a1759..5932aea 100644 --- a/config/php-fpm/Dockerfile +++ b/config/php-fpm/Dockerfile @@ -1,7 +1,3 @@ -ARG PHP_VERSION - -ENV PHP_VERSION ${PHP_VERSION} - FROM php:${PHP_VERSION}-fpm RUN mkdir -p /var/www/html @@ -13,29 +9,29 @@ RUN apt-get -qq update && apt-get -qq install -y \ zip \ unzip \ libicu-dev \ - imagick \ nano \ bash \ dnsutils -ENV NVM_DIR /root/.nvm -ENV NODE_VERSION 20 - -RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install $NODE_VERSION \ - && nvm use $NODE_VERSION - -COPY --from=node:20 /usr/local/bin/npx /usr/local/bin/npx +#ENV NVM_DIR /root/.nvm +#ENV NODE_VERSION 20 +# +#RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \ +# && . "$NVM_DIR/nvm.sh" \ +# && nvm install $NODE_VERSION \ +# && nvm use $NODE_VERSION +# +#COPY --from=node:20 /usr/local/bin/npx /usr/local/bin/npx RUN docker-php-ext-configure intl > /dev/null -RUN docker-php-ext-install mysqli pdo pdo_mysql sockets intl exif bcmath opcache > /dev/null +RUN docker-php-ext-install mysqli pdo pdo_mysql sockets intl exif bcmath > /dev/null -RUN pecl install xdebug redis \ - && docker-php-ext-enable redis +#RUN pecl install xdebug redis \ +# && docker-php-ext-enable redis -COPY ./xdebug.ini.tmp "${PHP_INI_DIR}/conf.d/xdebug.ini" -COPY ./opcache.ini "${PHP_INI_DIR}/conf.d" +#COPY ./xdebug.ini.tmp "${PHP_INI_DIR}/conf.d/xdebug.ini" +#RUN docker-php-ext-install opcache > /dev/null +#COPY ./opcache.ini "${PHP_INI_DIR}/conf.d" COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer WORKDIR /var/www/html \ No newline at end of file diff --git a/config/php.yaml b/config/php.yaml index b99d0bd..0e1aecd 100644 --- a/config/php.yaml +++ b/config/php.yaml @@ -1,10 +1,13 @@ -php: - build: - context: ./php-fpm - working_dir: /var/www/html - extra_hosts: - - host.docker.internal:host-gateway - volumes: - - ${PROJECT_DIRECTORY}:/var/www/html:cached - ports: - - ${PHP_PORT}:9003 \ No newline at end of file +services: + php: + build: + context: ./php-fpm + args: + PHP_VERSION: ${PHP_VERSION} + working_dir: /var/www/html + extra_hosts: + - host.docker.internal:host-gateway + volumes: + - ${PROJECT_DIRECTORY}:/var/www/html:cached + ports: + - ${PHP_PORT}:9003 \ No newline at end of file diff --git a/src/Classes/OS/PortGenerator.php b/src/Classes/OS/PortGenerator.php new file mode 100644 index 0000000..bd6d8c6 --- /dev/null +++ b/src/Classes/OS/PortGenerator.php @@ -0,0 +1,31 @@ +getArgument('name'))), 'projectEnv' ); + $this->filePaths->add( + new SpinnerFilePath(sprintf('data/environments/%s/docker-compose.yml', $input->getArgument('name'))), + 'projectDockerCompose' + ); } return Command::SUCCESS; @@ -83,11 +87,10 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface protected function buildDockerComposeCommand(string $command, bool $daemon = true): string { return sprintf( - 'cd %s && docker compose %s --env-file=%s%s', - $this->filePaths->get('config')->getAbsolutePath(), + 'cd %s && docker-compose --env-file=%s %s%s', + $this->filePaths->get('projectData')->getAbsolutePath(), + $this->filePaths->get('projectEnv')->getAbsolutePath(), $command, - $this->filePaths->get('projectEnv')->getAbsolutePath() - ?? $this->filePaths->get('projectEnv')->getProvidedPath(), $daemon ? ' -d' : '' ); } @@ -118,6 +121,9 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface 'defaultSpinnerConfig' => new SpinnerFilePath('config/spinner.yaml'), 'envTemplate' => new SpinnerFilePath('config/.template.env'), 'data' => new SpinnerFilePath('data'), + 'phpYamlTemplate' => new SpinnerFilePath('config/php.yaml'), + 'phpFpmDockerfileTemplate' => new SpinnerFilePath('config/php-fpm/Dockerfile'), + 'phpFpmDataDirectory' => new SpinnerFilePath('config/php-fpm'), ]); } } \ No newline at end of file diff --git a/src/Command/SpinCommand.php b/src/Command/SpinCommand.php index 995934a..b56fec4 100644 --- a/src/Command/SpinCommand.php +++ b/src/Command/SpinCommand.php @@ -4,16 +4,31 @@ declare(strict_types=1); namespace Loom\Spinner\Command; +use Loom\Spinner\Classes\OS\PortGenerator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Yaml\Yaml; #[AsCommand(name: 'spin:up', description: 'Spin up a new development environment')] class SpinCommand extends AbstractSpinnerCommand { + private PortGenerator $portGenerator; + private array $ports; + + public function __construct() + { + $this->portGenerator = new PortGenerator(); + $this->ports = [ + 'php' => $this->portGenerator->generateRandomPort(), + ]; + + parent::__construct(); + } + /** * @throws \Exception */ @@ -39,18 +54,57 @@ class SpinCommand extends AbstractSpinnerCommand $this->style->success("Spinning up a new development environment..."); + $this->createProjectData($input); + + $command = $this->buildDockerComposeCommand(sprintf('-p %s up', $input->getArgument('name'))); + + passthru($command); + + return Command::SUCCESS; + } + + private function createProjectData(InputInterface $input): void + { mkdir($this->filePaths->get('projectData')->getProvidedPath(), 0777, true); + $this->createEnvironmentFile($input); + $this->buildDockerComposeFile($input); + } + + private function createEnvironmentFile(InputInterface $input): void + { file_put_contents( $this->filePaths->get('projectEnv')->getProvidedPath(), sprintf( file_get_contents($this->filePaths->get('envTemplate')->getAbsolutePath()), $this->filePaths->get('project')->getAbsolutePath(), $input->getArgument('name'), - $input->getOption('php') + $input->getOption('php'), + $this->getPort('php'), ) ); + } - return Command::SUCCESS; + private function buildDockerComposeFile(InputInterface $input): void + { + if (!file_exists($this->filePaths->get('projectData')->getProvidedPath() . '/php-fpm')) { + mkdir($this->filePaths->get('projectData')->getProvidedPath() . '/php-fpm', 0777, true); + } + file_put_contents( + $this->filePaths->get('projectDockerCompose')->getProvidedPath(), + file_get_contents($this->filePaths->get('phpYamlTemplate')->getAbsolutePath()) + ); + $phpFpmDockerfileTemplate = file_get_contents($this->filePaths->get('phpFpmDockerfileTemplate')->getAbsolutePath()); + $phpFpmDockerfileTemplate = str_replace('${PHP_VERSION}', $input->getOption('php'), $phpFpmDockerfileTemplate); + + file_put_contents( + $this->filePaths->get('projectData')->getProvidedPath() . '/php-fpm/Dockerfile', + $phpFpmDockerfileTemplate + ); + } + + private function getPort(string $service): int + { + return $this->ports[$service] ?? $this->portGenerator->generateRandomPort(); } } \ No newline at end of file