Skip to content

Commit

Permalink
- Added recipe commands
Browse files Browse the repository at this point in the history
- General clean up
- Added cron service
- Updated readme
  • Loading branch information
jawngee committed May 2, 2022
1 parent 77b3bba commit 1a509c6
Show file tree
Hide file tree
Showing 19 changed files with 436 additions and 112 deletions.
7 changes: 7 additions & 0 deletions bin/greedo
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ foreach ($files as $file) {

use ILAB\Greedo\Commands\BuildCommand;
use ILAB\Greedo\Commands\InitCommand;
use ILAB\Greedo\Commands\Recipes\AddRecipeCommand;
use ILAB\Greedo\Commands\Recipes\UseRecipeCommand;
use ILAB\Greedo\Commands\StartCommand;
use ILAB\Greedo\Commands\StopCommand;
use ILAB\Greedo\Commands\WPCommand;
Expand All @@ -31,6 +33,9 @@ $wpCommand = new WPCommand(null, $root, __DIR__.'/..');
$composerCommand = new ComposerCommand(null, $root, __DIR__.'/..');
$sshCommand = new SSHCommand(null, $root, __DIR__.'/..');

$addRecipeCommand = new AddRecipeCommand(null, $root, __DIR__.'/..');
$recipeCommand = new UseRecipeCommand(null, $root, __DIR__.'/..');

$application = new Application();
$application->setName('Greedo');
$application->setVersion('2.0.0');
Expand All @@ -41,5 +46,7 @@ $application->add($stopCommand);
$application->add($wpCommand);
$application->add($composerCommand);
$application->add($sshCommand);
$application->add($recipeCommand);
$application->add($addRecipeCommand);
$application->run();

78 changes: 53 additions & 25 deletions classes/Commands/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Process;

class BuildCommand extends GreedoCommand {
protected static $defaultName = 'build';
Expand Down Expand Up @@ -59,11 +60,9 @@ protected function execute(InputInterface $input, OutputInterface $output) {

$hasPHP = !empty(arrayPath($this->config, 'services/php', null));
$appDir = arrayPath($this->config, 'services/php/app_dir');
if (strpos($appDir, DIRECTORY_SEPARATOR) !== 0) {
if (strpos($appDir, './') === 0) {
$appDir = '../../'.substr($appDir, 2);
}
}

$hasCron = !empty(arrayPath($this->config, 'services/cron', null));
$cronJobs = arrayPath($this->config, 'services/cron/jobs', []);

$publicDir = arrayPath($this->config, 'services/php/public_dir');
$uploadLimit = arrayPath($this->config, 'services/php/upload_limit', '32');
Expand All @@ -76,13 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
$installComposer = arrayPath($this->config, 'services/php/composer', false);
$installWPCLI = arrayPath($this->config, 'services/php/wpcli', false);
$mounts = arrayPath($this->config, 'services/php/mount', []);
array_walk($mounts, function(&$item) {
if (strpos($item, DIRECTORY_SEPARATOR) !== 0) {
if (strpos($item, './') === 0) {
$item = '../../'.substr($item, 2);
}
}
});
$installMysqlClient = arrayPath($this->config, 'services/php/mysql_client', false);

if ($xdebug) {
$extensions[] = 'xdebug';
Expand Down Expand Up @@ -121,32 +114,31 @@ protected function execute(InputInterface $input, OutputInterface $output) {
'mounts' => $mounts,
'installComposer' => $installComposer,
'installWPCLI' => $installWPCLI,
'installMysqlClient' => $installMysqlClient,
'hasCron' => $hasCron,
'cronJobs' => $cronJobs,
];

$buildDir = trailingslashit($this->rootDir).'docker/'.$name.'/';
$buildDir = trailingslashit($this->rootDir).'docker/';
if (!file_exists($buildDir)) {
mkdir($buildDir, 0755, true);
}

if (arrayPath($this->config, 'proxy') === 'caddy') {
$output->write("<info>Generating Caddyfile ... </info>");
$caddy = $blade->render('caddyfile', $data);
file_put_contents($buildDir."Caddyfile", $caddy);
file_put_contents($this->rootDir."Caddyfile", $caddy);
$output->writeln("<options=bold>Done</>");
}

$output->write("<info>Generating docker-compose.yml ... </info>");
$compose = $blade->render('docker-compose', $data);
file_put_contents($buildDir."docker-compose.yml", $compose);
file_put_contents($this->rootDir."docker-compose.yml", $compose);
$output->writeln("<options=bold>Done</>");

$output->write("<info>Generating PHP-FPM Dockerfile ... </info>");
$fpmDockerDir = $buildDir . 'phpfpm/';
if (!file_exists($fpmDockerDir)) {
mkdir($fpmDockerDir, 0755, true);
}
$fpmDocker = $blade->render('phpfpm-dockerfile', $data);
file_put_contents($fpmDockerDir."Dockerfile", $fpmDocker);
file_put_contents($buildDir."phpfpm-Dockerfile", $fpmDocker);
$output->writeln("<options=bold>Done</>");

$output->write("<info>Generating NGINX config ... </info>");
Expand All @@ -158,6 +150,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
file_put_contents($nginxConfigDir."default.conf", $nginx);
$output->writeln("<options=bold>Done</>");


$output->write("<info>Generating PHP-FPM config ... </info>");
$fpmConfigDir = $buildDir . 'conf/php-fpm/';
if (!file_exists($fpmConfigDir)) {
Expand All @@ -167,21 +160,56 @@ protected function execute(InputInterface $input, OutputInterface $output) {
file_put_contents($fpmConfigDir."www.conf", $fpm);
$output->writeln("<options=bold>Done</>");

if ($hasCron) {
$output->write("<info>Generating cron config ... </info>");
$cronConfigDir = $buildDir . 'cron/';
if (!file_exists($cronConfigDir)) {
mkdir($cronConfigDir, 0755, true);
}
file_put_contents($cronConfigDir."crontab.txt", implode("\n", $cronJobs));

$cronEntry = $blade->render('cron-entry-sh', $data);
file_put_contents($cronConfigDir.'entry.sh', $cronEntry);

$cronDocker = $blade->render('cron-dockerfile', $data);
file_put_contents($buildDir."cron-Dockerfile", $cronDocker);

$output->writeln("<options=bold>Done</>");
}

if ($hasPHP) {
if ($io->ask("Do you want to rebuild the PHP-FPM Docker image?")) {
if (!function_exists('pcntl_exec')) {
$output->writeln("<error>PHP extension 'pcntl' is not installed.</error>");
if ($io->confirm("Do you want to rebuild the PHP-FPM Docker image?", false)) {
$docker = rtrim(`which docker`);
if (empty($docker)) {
$output->writeln("<error>Docker not found.</error>");
return Command::FAILURE;
}

$process = new Process([$docker, "compose", "build", "{$name}_php", "--no-cache"]);
$process->setTimeout(PHP_INT_MAX);
$process->run(function($type, $buffer) use ($output) {
$output->write($buffer);
});
$output->writeln('');
// echo `$docker compose build {$name}_php --no-cache`;
}
}

if ($hasCron) {
if ($io->confirm("Do you want to rebuild the cron Docker image?", false)) {
$docker = rtrim(`which docker`);
if (empty($docker)) {
$output->writeln("<error>Docker not found.</error>");
return Command::FAILURE;
}

chdir($buildDir);
pcntl_exec($docker, ["compose", "build", "--no-cache"]);
$process = new Process([$docker, "compose", "build", "{$name}_cron", "--no-cache"]);
$process->setTimeout(PHP_INT_MAX);
$process->run(function($type, $buffer) use ($output) {
$output->write($buffer);
});
$output->writeln('');
// echo `$docker compose build {$name}_cron --no-cache`;
}
}

Expand Down
13 changes: 0 additions & 13 deletions classes/Commands/ComposerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
return $result;
}



$name = arrayPath($this->config, 'name');
if (empty(arrayPath($this->config, 'services/php', null))) {
$output->writeln("<error>No PHP service configured for $name</error>");
return Command::FAILURE;
}

$buildDir = trailingslashit($this->rootDir).'docker/'.$name.'/';
if (!file_exists($buildDir)) {
$output->writeln("<error>Docker directory does not exist.</error>");
return Command::FAILURE;
}
chdir($buildDir);

$publicDir = arrayPath($this->config, 'services/php/public_dir');
$publicPath = untrailingslashit('/srv/www/'.$publicDir);
Expand Down
13 changes: 13 additions & 0 deletions classes/Commands/InitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ protected function execute(InputInterface $input, OutputInterface $output) {
}
}


$io->section("Cron");
if ($io->confirm("Do you want to enable cron?")) {
$services['cron'] = [
'jobs' => []
];
}

$io->section("PHP Service");
if ($io->confirm("Do you want to enable PHP-FPM?")) {
$phpVer = $io->choice("PHP Version", ["7.4", "8.0", "8.1"]);
Expand All @@ -212,6 +220,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
$xdebug = $io->confirm("Do you want to enable XDebug?");
$composer = $io->confirm("Do you want to install Composer?");
$wpcli = $io->confirm("Do you want to install WP-CLI?");
$mysqlClient = $io->confirm("Do you want to install MySQL Client?");
$extensions = [];

if ($io->confirm("Do you want to define PHP extensions?")) {
Expand All @@ -236,6 +245,8 @@ protected function execute(InputInterface $input, OutputInterface $output) {
'zip',
'gd',
'bcmath',
'exif',
'intl',
'opcache',
'imagick',
];
Expand All @@ -247,6 +258,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
'bcmath',
'opcache',
'exif',
'intl',
'imagick',
];
} else {
Expand All @@ -268,6 +280,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
'composer' => $composer,
'wpcli' => $wpcli,
'extensions' => $extensions,
'mysql_client' => $mysqlClient,
'ini' => [
'flags' => [],
'values' => [],
Expand Down
38 changes: 38 additions & 0 deletions classes/Commands/Recipes/AddRecipeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace ILAB\Greedo\Commands\Recipes;

use duncan3dc\Laravel\BladeInstance;
use ILAB\Greedo\Commands\GreedoCommand;
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\Console\Style\SymfonyStyle;

class AddRecipeCommand extends GreedoCommand {
protected static $defaultName = 'recipes:add';

protected function configure() {
$this->setDescription("Saves the current greedo.yml file as a recipe that cen be used later.");
$this->addArgument('recipe', InputArgument::REQUIRED, "The name of the recipe to save.");
}

protected function execute(InputInterface $input, OutputInterface $output) {
$result = $this->loadConfig($output, false);
if ($result !== Command::SUCCESS) {
return $result;
}

$recipe = $input->getArgument('recipe');
$recipesDir = trailingslashit(trailingslashit($_SERVER['HOME']).'/.greedo/recipes/');
if (!file_exists($recipesDir)) {
mkdir($recipesDir, 0755, true);
}

copy($this->rootDir.'/greedo.yml', $recipesDir.$recipe.'.yml');

return Command::SUCCESS;
}
}
61 changes: 61 additions & 0 deletions classes/Commands/Recipes/UseRecipeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace ILAB\Greedo\Commands\Recipes;

use duncan3dc\Laravel\BladeInstance;
use ILAB\Greedo\Commands\GreedoCommand;
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\Console\Style\SymfonyStyle;
use Symfony\Component\Yaml\Yaml;

class UseRecipeCommand extends GreedoCommand {
protected static $defaultName = 'recipes:use';

protected function configure() {
$this->setDescription("Applies a recipe in the current directory.");
$this->addArgument('recipe', InputArgument::REQUIRED, "The name of the recipe to use.");
}

protected function execute(InputInterface $input, OutputInterface $output) {
$recipe = $input->getArgument('recipe');

$recipesDir = trailingslashit(trailingslashit($_SERVER['HOME']).'/.greedo/recipes/');
if (!file_exists($recipesDir)) {
$output->writeln("<error>No recipes directory found.</error>");
return Command::FAILURE;
}

$recipePath = $recipesDir.$recipe.'.yml';
if (!file_exists($recipePath)) {
$output->writeln("<error>Recipe not found.</error>");
return Command::FAILURE;
}

$config = Yaml::parseFile($recipePath);

$io = new SymfonyStyle($input, $output);

$io->section("Project Info");
$config['name'] = $io->ask("Project name");
$config['domains'] = [$io->ask("Project domain")];

foreach($config['services'] as $key => $service) {
$port = arrayPath($service, 'port');
if (!empty($port)) {
$serviceName = (in_array($key, ['db', 'php'])) ? strtoupper($key) : ucfirst($key);
$config['services'][$key]['port'] = $io->ask("$serviceName public port", $port);
}
}

$output->write("<info>Saving greedo file ... <info>");
file_put_contents($this->rootDir.'greedo.yml', Yaml::dump($config, PHP_INT_MAX));
$output->writeln("<info>Done</info>");
$output->writeln("<options=bold>Done</>");

return Command::SUCCESS;
}
}
7 changes: 0 additions & 7 deletions classes/Commands/SSHCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@ protected function execute(InputInterface $input, OutputInterface $output) {

$name = arrayPath($this->config, 'name');

$buildDir = trailingslashit($this->rootDir).'docker/'.$name.'/';
if (!file_exists($buildDir)) {
$output->writeln("<error>Docker directory does not exist.</error>");
return Command::FAILURE;
}
chdir($buildDir);

$dockerPs = `docker ps --all --no-trunc --format='{{json .}}'`;
$dockerPsLines = explode("\n", $dockerPs);
$instanceID = null;
Expand Down
13 changes: 2 additions & 11 deletions classes/Commands/StartCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,15 @@ protected function execute(InputInterface $input, OutputInterface $output) {
return $result;
}

$name = arrayPath($this->config, 'name');
$buildDir = trailingslashit($this->rootDir).'docker/'.$name.'/';
if (!file_exists($buildDir)) {
$output->writeln("<error>Docker directory does not exist.</error>");
return Command::FAILURE;
}
chdir($buildDir);


$dockerFile = $buildDir.'docker-compose.yml';
$dockerFile = $this->rootDir.'docker-compose.yml';
if (!file_exists($dockerFile)) {
$output->writeln("<error>Could not find docker compose file. Try running 'greedo build' first.</error>");
return Command::FAILURE;
}

$this->updateHosts();

$caddyFile = $buildDir.'Caddyfile';
$caddyFile = $this->rootDir.'Caddyfile';
if (file_exists($caddyFile)) {
switch(pcntl_fork()) {
case 0:
Expand Down
Loading

0 comments on commit 1a509c6

Please sign in to comment.