Compare commits
2 commits
f3fb68af39
...
df67dafb8e
Author | SHA1 | Date | |
---|---|---|---|
df67dafb8e | |||
3fe612cb36 |
11 changed files with 148 additions and 269 deletions
2
bin/spinner
Normal file → Executable file
2
bin/spinner
Normal file → Executable file
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Loom\Spinner\Command\DestroyCommand;
|
||||
use Loom\Spinner\Command\SpinCommand;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
|
@ -9,6 +10,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
|||
$application = new Application('Loom Spinner');
|
||||
|
||||
$application->add(new SpinCommand());
|
||||
$application->add(new DestroyCommand());
|
||||
|
||||
try {
|
||||
$application->run();
|
||||
|
|
|
@ -4,41 +4,52 @@ declare(strict_types=1);
|
|||
|
||||
namespace Loom\Spinner\Classes\Config;
|
||||
|
||||
use Loom\Spinner\Classes\Collection\FilePathCollection;
|
||||
use Loom\Spinner\Classes\File\Interface\DataPathInterface;
|
||||
use Loom\Spinner\Classes\File\SpinnerFilePath;
|
||||
use Loom\Utility\FilePath\FilePath;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Config
|
||||
{
|
||||
private FilePathCollection $filePaths;
|
||||
private string $spinnerRootPath;
|
||||
private string $configDirectory;
|
||||
private string $dataDirectory;
|
||||
private ?string $projectWorkPath = null;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(string $projectName, ?string $projectWorkPath = null)
|
||||
{
|
||||
$this->setFilePaths();
|
||||
$this->spinnerRootPath = dirname(__DIR__, 3);
|
||||
$this->configDirectory = $this->spinnerRootPath . '/config';
|
||||
$this->dataDirectory = $this->spinnerRootPath . '/data/environments/' . $projectName;
|
||||
|
||||
if ($projectWorkPath) {
|
||||
$this->projectWorkPath = $projectWorkPath;
|
||||
}
|
||||
}
|
||||
|
||||
public function getFilePaths(): FilePathCollection
|
||||
public function getDataDirectory(): string
|
||||
{
|
||||
return $this->filePaths;
|
||||
return $this->dataDirectory;
|
||||
}
|
||||
|
||||
public function getFilePath(string $key): ?FilePath
|
||||
public function getConfigFilePath(string $fileName): string
|
||||
{
|
||||
return $this->filePaths->get($key);
|
||||
return $this->configDirectory . '/' . $fileName;
|
||||
}
|
||||
|
||||
public function addFilePath(FilePath $filePath, string $key): void
|
||||
public function getConfigFileContents(string $fileName): string|null
|
||||
{
|
||||
$this->filePaths->add($filePath, $key);
|
||||
if (file_exists($this->configDirectory . '/' . $fileName)) {
|
||||
return file_get_contents($this->configDirectory . '/' . $fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getPhpVersion(InputInterface $input): ?float
|
||||
return null;
|
||||
}
|
||||
|
||||
public function projectDataExists(string $projectName): bool
|
||||
{
|
||||
return file_exists($this->dataDirectory . '/environments/' . $projectName);
|
||||
}
|
||||
|
||||
public function getPhpVersion(InputInterface $input): float
|
||||
{
|
||||
if ($input->getOption('php')) {
|
||||
return (float) $input->getOption('php');
|
||||
|
@ -92,7 +103,7 @@ class Config
|
|||
return false;
|
||||
}
|
||||
|
||||
return $this->getEnvironmentOption('database', 'enabled');
|
||||
return (bool) $this->getEnvironmentOption('database', 'enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,52 +130,29 @@ class Config
|
|||
return (int) $this->getEnvironmentOption('node','version');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getEnvironmentOption(string $service, string $option): mixed
|
||||
{
|
||||
$projectCustomConfig = $this->filePaths->get('projectCustomConfig');
|
||||
$projectCustomConfig = $this->getProjectCustomConfig();
|
||||
|
||||
if ($projectCustomConfig->exists()) {
|
||||
$customConfig = Yaml::parseFile($projectCustomConfig->getAbsolutePath())['options']['environment']
|
||||
?? null;
|
||||
|
||||
if ($customConfig) {
|
||||
if (isset($customConfig[$service][$option])) {
|
||||
return $customConfig[$service][$option];
|
||||
}
|
||||
}
|
||||
if ($projectCustomConfig) {
|
||||
return $projectCustomConfig[$service][$option] ?? $this->getDefaultConfig()[$service][$option] ?? null;
|
||||
}
|
||||
|
||||
return $this->getDefaultConfig()['environment'][$service][$option] ?? null;
|
||||
return $this->getDefaultConfig()[$service][$option] ?? null;
|
||||
}
|
||||
|
||||
public function getProjectCustomConfig(): ?array
|
||||
{
|
||||
if ($this->projectWorkPath && file_exists($this->projectWorkPath . '/spinner.yaml')) {
|
||||
return Yaml::parseFile($this->projectWorkPath . '/spinner.yaml')['options']['environment'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getDefaultConfig(): ?array
|
||||
{
|
||||
return Yaml::parseFile($this->filePaths->get('defaultSpinnerConfig')?->getAbsolutePath())['options']
|
||||
return Yaml::parseFile($this->configDirectory . '/spinner.yaml')['options']['environment']
|
||||
?? null;
|
||||
}
|
||||
|
||||
private function setFilePaths(): void
|
||||
{
|
||||
$this->filePaths = new FilePathCollection([
|
||||
'config' => new SpinnerFilePath('config'),
|
||||
'defaultSpinnerConfig' => new SpinnerFilePath('config/spinner.yaml'),
|
||||
'envTemplate' => new SpinnerFilePath('config/.template.env'),
|
||||
'data' => new SpinnerFilePath('data'),
|
||||
'phpYamlTemplate' => new SpinnerFilePath('config/php.yaml'),
|
||||
'nginxYamlTemplate' => new SpinnerFilePath('config/nginx.yaml'),
|
||||
'phpFpmDataDirectory' => new SpinnerFilePath('config/php-fpm'),
|
||||
DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE => new SpinnerFilePath(DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE),
|
||||
DataPathInterface::CONFIG_NGINX_DOCKERFILE => new SpinnerFilePath(DataPathInterface::CONFIG_NGINX_DOCKERFILE),
|
||||
'nodeDockerfileTemplate' => new SpinnerFilePath('config/php-fpm/Node.Dockerfile'),
|
||||
'xdebugIniTemplate' => new SpinnerFilePath('config/php-fpm/xdebug.ini'),
|
||||
'opcacheIniTemplate' => new SpinnerFilePath('config/php-fpm/opcache.ini'),
|
||||
'xdebugDockerfileTemplate' => new SpinnerFilePath('config/php-fpm/XDebug.Dockerfile'),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ abstract class AbstractFileBuilder implements FileBuilderInterface
|
|||
{
|
||||
protected string $content;
|
||||
|
||||
public function __construct(protected SpinnerFilePath $path, protected Config $config)
|
||||
public function __construct(protected string $path, protected Config $config)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ abstract class AbstractFileBuilder implements FileBuilderInterface
|
|||
|
||||
public function save(): void
|
||||
{
|
||||
file_put_contents($this->path->getProvidedPath(), $this->content);
|
||||
file_put_contents($this->path, $this->content);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Loom\Spinner\Classes\File;
|
||||
|
||||
use Loom\Spinner\Classes\Config\Config;
|
||||
use Loom\Utility\FilePath\FilePath;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
class DockerComposeFileBuilder extends AbstractFileBuilder
|
||||
|
@ -14,13 +15,7 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
|
|||
*/
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$projectDockerCompose = $config->getFilePaths()->get('projectDockerCompose');
|
||||
|
||||
if (!$projectDockerCompose instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Project Docker Compose file path not found.');
|
||||
}
|
||||
|
||||
return parent::__construct($projectDockerCompose, $config);
|
||||
return parent::__construct($config->getDataDirectory() . '/docker-compose.yaml', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,9 +23,7 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
|
|||
*/
|
||||
public function build(InputInterface $input): DockerComposeFileBuilder
|
||||
{
|
||||
$this->content = file_get_contents(
|
||||
$this->config->getFilePaths()->get('phpYamlTemplate')->getAbsolutePath()
|
||||
);
|
||||
$this->content = $this->config->getConfigFileContents('php.yaml');
|
||||
|
||||
if ($this->config->isDatabaseEnabled($input) && in_array($this->config->getDatabaseDriver($input), ['sqlite3', 'sqlite'])) {
|
||||
$this->addSqliteDatabaseConfig();
|
||||
|
@ -48,20 +41,18 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
|
|||
$this->content .= str_replace(
|
||||
'services:',
|
||||
'',
|
||||
file_get_contents(
|
||||
$this->config->getFilePaths()->get('nginxYamlTemplate')->getAbsolutePath()
|
||||
)
|
||||
$this->config->getConfigFileContents('nginx.yaml')
|
||||
);
|
||||
$this->content = str_replace(
|
||||
'./nginx/conf.d',
|
||||
(new SpinnerFilePath('config/nginx/conf.d'))->getAbsolutePath(),
|
||||
$this->config->getConfigFilePath('nginx/conf.d'),
|
||||
$this->content
|
||||
);
|
||||
}
|
||||
|
||||
private function addSqliteDatabaseConfig(): void
|
||||
{
|
||||
$sqlLiteConfig = file_get_contents((new SpinnerFilePath('config/sqlite.yaml'))->getAbsolutePath());
|
||||
$sqlLiteConfig = $this->config->getConfigFileContents('sqlite.yaml');
|
||||
$sqlLiteConfig = str_replace('volumes:', '', $sqlLiteConfig);
|
||||
$this->content .= $sqlLiteConfig;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Loom\Spinner\Classes\File\Interface;
|
||||
|
||||
interface DataPathInterface
|
||||
{
|
||||
public const string CONFIG_PHP_FPM_DOCKERFILE = 'config/php-fpm/Dockerfile';
|
||||
public const string CONFIG_NGINX_DOCKERFILE = 'config/nginx/Dockerfile';
|
||||
}
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace Loom\Spinner\Classes\File;
|
||||
|
||||
use Loom\Spinner\Classes\Config\Config;
|
||||
use Loom\Spinner\Classes\File\Interface\DataPathInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
class NginxDockerFileBuilder extends AbstractFileBuilder
|
||||
|
@ -15,22 +14,12 @@ class NginxDockerFileBuilder extends AbstractFileBuilder
|
|||
*/
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$projectNginxDockerfilePath = $config->getFilePath('projectNginxDockerfile');
|
||||
|
||||
if (!$projectNginxDockerfilePath instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Project PHP-FPM Dockerfile not found');
|
||||
}
|
||||
|
||||
return parent::__construct($projectNginxDockerfilePath, $config);
|
||||
return parent::__construct($config->getDataDirectory() . '/nginx/Dockerfile', $config);
|
||||
}
|
||||
|
||||
public function build(InputInterface $input): AbstractFileBuilder
|
||||
{
|
||||
$this->content = file_get_contents(
|
||||
$this->config->getFilePaths()
|
||||
->get(DataPathInterface::CONFIG_NGINX_DOCKERFILE)
|
||||
->getAbsolutePath()
|
||||
);
|
||||
$this->content = $this->config->getConfigFileContents('nginx/Dockerfile');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace Loom\Spinner\Classes\File;
|
||||
|
||||
use Loom\Spinner\Classes\Config\Config;
|
||||
use Loom\Spinner\Classes\File\Interface\DataPathInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
class PHPDockerFileBuilder extends AbstractFileBuilder
|
||||
|
@ -15,13 +14,7 @@ class PHPDockerFileBuilder extends AbstractFileBuilder
|
|||
*/
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$projectPhpFpmDockerfile = $config->getFilePath('projectPhpFpmDockerfile');
|
||||
|
||||
if (!$projectPhpFpmDockerfile instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Project PHP-FPM Dockerfile not found');
|
||||
}
|
||||
|
||||
return parent::__construct($projectPhpFpmDockerfile, $config);
|
||||
return parent::__construct($config->getDataDirectory() . '/php-fpm/Dockerfile', $config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,27 +27,27 @@ class PHPDockerFileBuilder extends AbstractFileBuilder
|
|||
$this->content = str_replace('${PHP_VERSION}', (string) $this->config->getPhpVersion($input), $this->content);
|
||||
|
||||
file_put_contents(
|
||||
(new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/opcache.ini', $input->getArgument('name'))))->getProvidedPath(),
|
||||
file_get_contents($this->config->getFilePaths()->get('opcacheIniTemplate')->getAbsolutePath())
|
||||
$this->config->getDataDirectory() . '/php-fpm/opcache.ini',
|
||||
$this->config->getConfigFileContents('php-fpm/opcache.ini')
|
||||
);
|
||||
|
||||
if ($this->config->isDatabaseEnabled($input) && in_array($this->config->getDatabaseDriver($input), ['sqlite3', 'sqlite'])) {
|
||||
$this->addNewLine();
|
||||
$this->content .= file_get_contents((new SpinnerFilePath('config/php-fpm/Sqlite.Dockerfile'))->getAbsolutePath());
|
||||
$this->content .= $this->config->getConfigFileContents('php-fpm/Sqlite.Dockerfile');
|
||||
}
|
||||
|
||||
if ($this->config->isNodeEnabled($input)) {
|
||||
$this->addNewLine();
|
||||
$this->content .= file_get_contents($this->config->getFilePaths()->get('nodeDockerfileTemplate')->getAbsolutePath());
|
||||
$this->content .= $this->config->getConfigFileContents('php-fpm/Node.Dockerfile');
|
||||
$this->content = str_replace('${NODE_VERSION}', (string) $this->config->getNodeVersion($input), $this->content);
|
||||
}
|
||||
|
||||
if ($this->config->isXdebugEnabled($input)) {
|
||||
$this->addNewLine();
|
||||
$this->content .= file_get_contents($this->config->getFilePaths()->get('xdebugDockerfileTemplate')->getAbsolutePath());
|
||||
$this->content .= $this->config->getConfigFileContents('php-fpm/Xdebug.Dockerfile');
|
||||
file_put_contents(
|
||||
(new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/xdebug.ini', $input->getArgument('name'))))->getProvidedPath(),
|
||||
file_get_contents($this->config->getFilePaths()->get('xdebugIniTemplate')->getAbsolutePath())
|
||||
$this->config->getDataDirectory() . '/php-fpm/xdebug.ini',
|
||||
$this->config->getConfigFileContents('php-fpm/xdebug.ini')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -63,8 +56,6 @@ class PHPDockerFileBuilder extends AbstractFileBuilder
|
|||
|
||||
private function setInitialContent(): void
|
||||
{
|
||||
$this->content = file_get_contents(
|
||||
$this->config->getFilePaths()->get(DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE)->getAbsolutePath()
|
||||
);
|
||||
$this->content = $this->config->getConfigFileContents('php-fpm/Dockerfile');
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Loom\Spinner\Classes\File;
|
||||
|
||||
use Loom\Utility\FilePath\FilePath;
|
||||
|
||||
class SpinnerFilePath extends FilePath
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(sprintf('%s%s%s', dirname(__DIR__, 3), DIRECTORY_SEPARATOR, $path));
|
||||
}
|
||||
|
||||
public function getProvidedPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
|
@ -4,17 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace Loom\Spinner\Command;
|
||||
|
||||
use Loom\Spinner\Classes\Collection\FilePathCollection;
|
||||
use Loom\Spinner\Classes\Config\Config;
|
||||
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\InputArgument;
|
||||
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
|
||||
{
|
||||
|
@ -25,7 +22,6 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
public function __construct()
|
||||
{
|
||||
$this->system = new System();
|
||||
$this->config = new Config();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -42,73 +38,20 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
|
|||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!$this->validatePathArgument($input)) {
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$this->validateNameArgument($input);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function buildDockerComposeCommand(string $command, bool $daemon = true): string
|
||||
{
|
||||
return sprintf(
|
||||
'cd %s && docker-compose --env-file=%s %s%s',
|
||||
$this->config->getFilePaths()->get('projectData')->getAbsolutePath(),
|
||||
$this->config->getFilePaths()->get('projectEnv')->getAbsolutePath(),
|
||||
'cd %s && docker compose --env-file=%s %s%s',
|
||||
$this->config->getDataDirectory(),
|
||||
$this->config->getDataDirectory() . '/.env',
|
||||
$command,
|
||||
$daemon ? ' -d' : ''
|
||||
);
|
||||
}
|
||||
|
||||
private function validatePathArgument(InputInterface $input): bool
|
||||
{
|
||||
if ($input->hasArgument('path')) {
|
||||
$projectDirectory = new FilePath($input->getArgument('path'));
|
||||
|
||||
if (!$projectDirectory->exists() || !$projectDirectory->isDirectory()) {
|
||||
$this->style->error('The provided path is not a valid directory.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->config->addFilePath($projectDirectory, 'project');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function validateNameArgument(InputInterface $input): void
|
||||
{
|
||||
if ($input->hasArgument('name')) {
|
||||
$this->config->addFilePath(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s', $input->getArgument('name'))),
|
||||
'projectData'
|
||||
);
|
||||
$this->config->addFilePath(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s/.env', $input->getArgument('name'))),
|
||||
'projectEnv'
|
||||
);
|
||||
$this->config->addFilePath(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s/docker-compose.yml', $input->getArgument('name'))),
|
||||
'projectDockerCompose'
|
||||
);
|
||||
$this->config->addFilePath(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/Dockerfile', $input->getArgument('name'))),
|
||||
'projectPhpFpmDockerfile'
|
||||
);
|
||||
$this->config->addFilePath(
|
||||
new SpinnerFilePath(sprintf('data/environments/%s/nginx/Dockerfile', $input->getArgument('name'))),
|
||||
'projectNginxDockerfile'
|
||||
);
|
||||
$this->config->addFilePath(
|
||||
new FilePath($this->config->getFilePaths()->get('project')->getAbsolutePath() . DIRECTORY_SEPARATOR . 'spinner.yaml'),
|
||||
'projectCustomConfig'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function setStyle(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->style = new SymfonyStyle($input, $output);
|
||||
|
|
33
src/Command/DestroyCommand.php
Normal file
33
src/Command/DestroyCommand.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Loom\Spinner\Command;
|
||||
|
||||
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\Output\OutputInterface;
|
||||
|
||||
#[AsCommand(name: 'spin:down', description: 'Destroy a development environment')]
|
||||
class DestroyCommand extends AbstractSpinnerCommand
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addArgument(
|
||||
'name',
|
||||
InputArgument::REQUIRED,
|
||||
'The name of the project (as used when running spin:up).'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (parent::execute($input, $output)) {
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace Loom\Spinner\Command;
|
||||
|
||||
use Loom\Spinner\Classes\Config\Config;
|
||||
use Loom\Spinner\Classes\File\DockerComposeFileBuilder;
|
||||
use Loom\Spinner\Classes\File\NginxDockerFileBuilder;
|
||||
use Loom\Spinner\Classes\File\PHPDockerFileBuilder;
|
||||
use Loom\Spinner\Classes\File\SpinnerFilePath;
|
||||
use Loom\Spinner\Classes\OS\PortGenerator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
@ -21,6 +21,7 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
{
|
||||
private PortGenerator $portGenerator;
|
||||
private array $ports;
|
||||
private string $projectWorkPath = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -84,14 +85,35 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($this->projectDataExists()) {
|
||||
return Command::SUCCESS;
|
||||
$this->projectWorkPath = $input->getArgument('path') === '.'
|
||||
? getcwd()
|
||||
: $input->getArgument('path');
|
||||
|
||||
if (!file_exists($this->projectWorkPath)) {
|
||||
$this->style->error('The provided project path does not exist.');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$this->config = new Config($input->getArgument('name'), $this->projectWorkPath);
|
||||
|
||||
if ($this->config->projectDataExists($input->getArgument('name'))) {
|
||||
$this->style->error('A project with the same name already exists.');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$this->style->success("Spinning up a new development environment...");
|
||||
|
||||
$this->style->text('Creating project data...');
|
||||
|
||||
try {
|
||||
$this->createProjectData($input);
|
||||
} catch (\Exception $exception) {
|
||||
$this->style->error('Failed to create project data: '. $exception->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$this->style->success('Project data created.');
|
||||
|
||||
$this->style->text('Building Docker images...');
|
||||
|
@ -102,23 +124,12 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function projectDataExists(): bool
|
||||
{
|
||||
if ($this->config->getFilePaths()->get('projectData')->exists()) {
|
||||
$this->style->warning('Project already exists. Skipping new build.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function createProjectData(InputInterface $input): void
|
||||
{
|
||||
$this->createProjectDataDirectory();
|
||||
$this->createProjectDataDirectory($input);
|
||||
$this->createEnvironmentFile($input);
|
||||
$this->buildDockerComposeFile($input);
|
||||
$this->buildDockerfiles($input);
|
||||
|
@ -127,15 +138,13 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function createProjectDataDirectory(): void
|
||||
private function createProjectDataDirectory(InputInterface $input): void
|
||||
{
|
||||
$projectData = $this->config->getFilePaths()->get('projectData');
|
||||
|
||||
if (!$projectData instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Invalid project data directory provided.');
|
||||
}
|
||||
|
||||
mkdir($projectData->getProvidedPath(), 0777, true);
|
||||
mkdir(
|
||||
$this->config->getDataDirectory(),
|
||||
0777,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,21 +152,15 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
*/
|
||||
private function createEnvironmentFile(InputInterface $input): void
|
||||
{
|
||||
$projectEnv = $this->config->getFilePaths()->get('projectEnv');
|
||||
|
||||
if (!$projectEnv instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Invalid project environment file provided.');
|
||||
}
|
||||
|
||||
file_put_contents(
|
||||
$projectEnv->getProvidedPath(),
|
||||
$this->config->getDataDirectory() . '/.env',
|
||||
sprintf(
|
||||
file_get_contents($this->config->getFilePaths()->get('envTemplate')->getAbsolutePath()),
|
||||
$this->config->getFilePaths()->get('project')->getAbsolutePath(),
|
||||
$this->config->getConfigFileContents('.template.env'),
|
||||
$this->projectWorkPath,
|
||||
$input->getArgument('name'),
|
||||
$this->config->getPhpVersion($input),
|
||||
$this->getPort('php'),
|
||||
$this->getPort('nginx'),
|
||||
$this->ports['php'],
|
||||
$this->ports['nginx'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -167,12 +170,7 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
*/
|
||||
private function buildDockerComposeFile(InputInterface $input): void
|
||||
{
|
||||
$this->createProjectPhpFpmDirectory();
|
||||
|
||||
if ($this->config->isServerEnabled($input)) {
|
||||
$this->createProjectNginxDirectory();
|
||||
(new NginxDockerFileBuilder($this->config))->build($input)->save();
|
||||
}
|
||||
$this->createProjectDataSubDirectory('php-fpm');
|
||||
|
||||
(new DockerComposeFileBuilder($this->config))->build($input)->save();
|
||||
}
|
||||
|
@ -182,43 +180,18 @@ class SpinCommand extends AbstractSpinnerCommand
|
|||
*/
|
||||
private function buildDockerfiles(InputInterface $input): void
|
||||
{
|
||||
if ($this->config->isServerEnabled($input)) {
|
||||
$this->createProjectDataSubDirectory('nginx');
|
||||
(new NginxDockerFileBuilder($this->config))->build($input)->save();
|
||||
}
|
||||
|
||||
(new PHPDockerFileBuilder($this->config))->build($input)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function createProjectPhpFpmDirectory(): void
|
||||
private function createProjectDataSubDirectory(string $directory): void
|
||||
{
|
||||
$projectData = $this->config->getFilePaths()->get('projectData');
|
||||
|
||||
if (!$projectData instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Invalid project data directory provided.');
|
||||
}
|
||||
|
||||
if (!file_exists($projectData->getProvidedPath() . '/php-fpm')) {
|
||||
mkdir($projectData->getProvidedPath() . '/php-fpm', 0777, true);
|
||||
if (!file_exists($this->config->getDataDirectory() . '/' . $directory)) {
|
||||
mkdir($this->config->getDataDirectory() . '/' . $directory, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function createProjectNginxDirectory(): void
|
||||
{
|
||||
$projectData = $this->config->getFilePaths()->get('projectData');
|
||||
|
||||
if (!$projectData instanceof SpinnerFilePath) {
|
||||
throw new \Exception('Invalid project data directory provided.');
|
||||
}
|
||||
|
||||
if (!file_exists($projectData->getProvidedPath() . '/nginx')) {
|
||||
mkdir($projectData->getProvidedPath() . '/nginx', 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
private function getPort(string $service): ?int
|
||||
{
|
||||
return $this->ports[$service];
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue