Create basic project data structure from env template
This commit is contained in:
parent
940fbc1234
commit
b8ad06cda3
11 changed files with 179 additions and 46 deletions
|
@ -13,7 +13,8 @@
|
|||
"require": {
|
||||
"loomlabs/utility.collection": "^1.0",
|
||||
"loomlabs/utility.filepath": "^1.1",
|
||||
"symfony/console": "^7.2"
|
||||
"symfony/console": "^7.2",
|
||||
"symfony/yaml": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^12.1"
|
||||
|
|
3
config/.template.env
Normal file
3
config/.template.env
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROJECT_DIRECTORY=%s
|
||||
PROJECT_NAME=%s
|
||||
PHP_VERSION=%s
|
26
config/docker-compose.sample.yaml
Normal file
26
config/docker-compose.sample.yaml
Normal file
|
@ -0,0 +1,26 @@
|
|||
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
|
|
@ -1,38 +0,0 @@
|
|||
version: "3.9"
|
||||
|
||||
services:
|
||||
nginx:
|
||||
build:
|
||||
context: ./nginx
|
||||
ports:
|
||||
- ${NGINX_PORT}:80
|
||||
volumes:
|
||||
- ${PROJECT_DIRECTORY}:/var/www/html:cached
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d
|
||||
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
|
||||
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
|
41
config/php-fpm/Dockerfile
Normal file
41
config/php-fpm/Dockerfile
Normal file
|
@ -0,0 +1,41 @@
|
|||
ARG PHP_VERSION
|
||||
|
||||
ENV PHP_VERSION ${PHP_VERSION}
|
||||
|
||||
FROM php:${PHP_VERSION}-fpm
|
||||
|
||||
RUN mkdir -p /var/www/html
|
||||
|
||||
RUN apt-get -qq update && apt-get -qq install -y \
|
||||
apt-transport-https \
|
||||
git \
|
||||
curl \
|
||||
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
|
||||
|
||||
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 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 --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||
|
||||
WORKDIR /var/www/html
|
10
config/php.yaml
Normal file
10
config/php.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
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
|
4
config/spinner.yaml
Normal file
4
config/spinner.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
options:
|
||||
environment:
|
||||
php:
|
||||
version: 8.4
|
2
data/.gitignore
vendored
Normal file
2
data/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -8,8 +8,13 @@ use Loom\Utility\FilePath\FilePath;
|
|||
|
||||
class SpinnerFilePath extends FilePath
|
||||
{
|
||||
public function __construct(string $projectPath)
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(sprintf('%s%s%s', dirname(__DIR__, 3), DIRECTORY_SEPARATOR, $projectPath));
|
||||
parent::__construct(sprintf('%s%s%s', dirname(__DIR__, 3), DIRECTORY_SEPARATOR, $path));
|
||||
}
|
||||
|
||||
public function getProvidedPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
|
@ -8,11 +8,11 @@ use Loom\Spinner\Classes\Collection\FilePathCollection;
|
|||
use Loom\Spinner\Classes\File\SpinnerFilePath;
|
||||
use Loom\Spinner\Classes\OS\System;
|
||||
use Loom\Spinner\Command\Interface\ConsoleCommandInterface;
|
||||
use Loom\Utility\FilePath\FilePath;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
||||
{
|
||||
|
@ -34,6 +34,8 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
{
|
||||
$this->setStyle($input, $output);
|
||||
|
||||
$this->style->title('Loom Spinner');
|
||||
|
||||
if (!$this->system->isDockerEngineRunning()) {
|
||||
$this->style->error('It looks like the Docker Engine is not running. Please start it and try again.');
|
||||
|
||||
|
@ -41,7 +43,7 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
}
|
||||
|
||||
if ($input->hasArgument('path')) {
|
||||
$projectDirectory = new FilePath($input->getArgument('path'));
|
||||
$projectDirectory = new SpinnerFilePath($input->getArgument('path'));
|
||||
|
||||
if (!$projectDirectory->exists() || !$projectDirectory->isDirectory()) {
|
||||
$this->style->error('The provided path is not a valid directory.');
|
||||
|
@ -52,9 +54,58 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
$this->filePaths->add($projectDirectory, 'project');
|
||||
}
|
||||
|
||||
if ($input->hasArgument('name')) {
|
||||
$this->filePaths->add(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s', $input->getArgument('name'))),
|
||||
'projectData'
|
||||
);
|
||||
$this->filePaths->add(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s/.env', $input->getArgument('name'))),
|
||||
'projectEnv'
|
||||
);
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getDefaultConfig()
|
||||
{
|
||||
if (!$this->filePaths->get('defaultSpinnerConfig')?->exists()) {
|
||||
throw new \Exception('Default spinner configuration file not found.');
|
||||
}
|
||||
|
||||
return Yaml::parseFile($this->filePaths->get('defaultSpinnerConfig')->getAbsolutePath())['options'] ?? null;
|
||||
}
|
||||
|
||||
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(),
|
||||
$command,
|
||||
$this->filePaths->get('projectEnv')->getAbsolutePath()
|
||||
?? $this->filePaths->get('projectEnv')->getProvidedPath(),
|
||||
$daemon ? ' -d' : ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getDefaultPhpVersion(): ?float
|
||||
{
|
||||
if (!$this->filePaths->get('defaultSpinnerConfig')?->exists()) {
|
||||
throw new \Exception('Default spinner configuration file not found.');
|
||||
}
|
||||
|
||||
$config = $this->getDefaultConfig();
|
||||
|
||||
return $config['environment']['php']['version'] ?? null;
|
||||
}
|
||||
|
||||
private function setStyle(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->style = new SymfonyStyle($input, $output);
|
||||
|
@ -64,6 +115,9 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
{
|
||||
$this->filePaths = new FilePathCollection([
|
||||
'config' => new SpinnerFilePath('config'),
|
||||
'defaultSpinnerConfig' => new SpinnerFilePath('config/spinner.yaml'),
|
||||
'envTemplate' => new SpinnerFilePath('config/.template.env'),
|
||||
'data' => new SpinnerFilePath('data'),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -8,24 +8,49 @@ 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;
|
||||
|
||||
#[AsCommand(name: 'spin', description: 'Spin up a new development environment')]
|
||||
#[AsCommand(name: 'spin:up', description: 'Spin up a new development environment')]
|
||||
class SpinCommand extends AbstractSpinnerCommand
|
||||
{
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name for your Docker container.')
|
||||
->addArgument('path', InputArgument::REQUIRED, 'The absolute path to your projects root directory.');
|
||||
->addArgument('path', InputArgument::REQUIRED, 'The absolute path to your projects root directory.')
|
||||
->addOption('php', null, InputOption::VALUE_REQUIRED, 'The PHP version to use (e.g., 8.0).', $this->getDefaultPhpVersion());
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!parent::execute($input, $output)) {
|
||||
if (parent::execute($input, $output)) {
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($this->filePaths->get('projectData')->exists()) {
|
||||
$this->style->warning('Project data already exists. Skipping new build.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$this->style->success("Spinning up a new development environment...");
|
||||
|
||||
mkdir($this->filePaths->get('projectData')->getProvidedPath(), 0777, true);
|
||||
|
||||
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')
|
||||
)
|
||||
);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue