diff --git a/.ahoy.yml b/.ahoy.yml new file mode 100644 index 0000000000000000000000000000000000000000..a763df4db04552dff37f1f9b78d31331f86efa7a --- /dev/null +++ b/.ahoy.yml @@ -0,0 +1,14 @@ +ahoyapi: v2 +commands: + d4d: + imports: + - ahoy.yml + usage: Docker for Drupal + live: + imports: + - ahoy.live.yml + usage: Interact with the live site + debug: + imports: + - ahoy.debug.yml + usage: PHP debugging diff --git a/composer.json b/composer.json index f06714d52e487f9a48de3b8dcb21128d3bb0e497..362df9b486428c61f478be4f3ab94b4a296f79be 100644 --- a/composer.json +++ b/composer.json @@ -27,10 +27,8 @@ "ext-json": "*", "php": ">=7.2", "composer-plugin-api": "^1||^2", - "lakedrops/composer-json-utils": "^1.5.0", - "lakedrops/docker-traefik": "^1.2.0", - "lakedrops/dotenv": "^1.2.2", - "twig/twig": "^1.23.1" + "lakedrops/composer-json-utils": "^1.7||dev-master", + "lakedrops/docker-traefik": "^1.3||dev-master" }, "require-dev": { "composer/composer": "^1||^2", @@ -44,22 +42,6 @@ } }, "extra": { - "class": "LakeDrops\\Docker4Drupal\\Plugin", - "lakedrops": { - "ahoy": { - "d4d": { - "usage": "Docker for Drupal", - "imports": ["ahoy.yml"] - }, - "live": { - "usage": "Interact with the live site", - "imports": ["ahoy.live.yml"] - }, - "debug": { - "usage": "PHP debugging", - "imports": ["ahoy.debug.yml"] - } - } - } + "class": "LakeDrops\\Docker4Drupal\\Plugin" } } diff --git a/src/Handler.php b/src/Handler.php index 5709ec4426304782d5ac0047c09c10d5e4e8b4a4..43278c3eecd2e9553eeda0c1f17959ac40b3ff51 100644 --- a/src/Handler.php +++ b/src/Handler.php @@ -4,12 +4,9 @@ namespace LakeDrops\Docker4Drupal; use Exception; use LakeDrops\Component\Composer\BaseHandler; -use LakeDrops\Component\Dotenv\Dotenv; use LakeDrops\DockerTraefik\Traefik; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Yaml\Yaml; -use Twig_Environment; -use Twig_Loader_Array; /** * Class Handler. @@ -19,36 +16,154 @@ use Twig_Loader_Array; class Handler extends BaseHandler { /** - * @var array + * {@inheritdoc} */ - protected $options; + public function configId(): string { + return 'docker4drupal'; + } + + /** + * {@inheritdoc} + */ + protected function configDefault(): array { + $projectname = getenv('COMPOSE_PROJECT_NAME'); + if (empty($projectname)) {$projectname = str_replace([' ', '-', '_', '.'], '', basename(getcwd())); + $this->env->put('COMPOSE_PROJECT_NAME', $projectname); + } + + $options = [ + 'projectname' => $projectname, + 'ci_home' => '/home/gitlab-runner', + 'docker0' => [ + 'ip' => ($this->isCiContext() || $this->isLocalDevMode()) ? + $this->getDockerGateway() : + $this->getLocalIpv4('docker0'), + ], + 'live' => [ + 'root' => '', + 'uri' => '', + 'host' => '', + 'user' => $this->env->receive('live_host_username', 'Remote username for host of the live site', getenv('USER')), + ], + 'drush' => [ + 'sql' => [ + 'tables' => [ + 'structure' => [ + 'cache', + 'cachetags', + 'cache_*', + 'history', + 'search_*', + 'sessions', + 'watchdog', + ], + 'skip' => [ + 'migration_*', + ], + ], + ], + ], + 'drupal' => [ + 'version' => '8', + ], + 'php' => [ + 'version' => $this->env->receiveGlobal('PHP_VERSION', 'PHP version', '7.3'), + 'xdebug' => $this->env->receiveGlobal('PHP_DEBUG', 'PHP debug', '0'), + ], + 'webserver' => [ + 'type' => 'apache', + 'overwriteconfig' => FALSE, + ], + 'varnish' => [ + 'enable' => 0, + ], + 'redis' => [ + 'version' => '4.0', + ], + 'dbbrowser' => [ + 'type' => 'pma', + ], + 'solr' => [ + 'enable' => 0, + 'version' => '6.6', + ], + 'node' => [ + 'enable' => 0, + 'key' => '', + 'path' => '', + ], + 'memcached' => [ + 'enable' => 0, + ], + 'rsyslog' => [ + 'enable' => 0, + ], + 'athenapdf' => [ + 'enable' => 0, + 'key' => '', + ], + 'blackfire' => [ + 'enable' => 0, + 'id' => '', + 'token' => '', + ], + 'webgrind' => [ + 'enable' => 0, + ], + 'wkhtmltox' => [ + 'enable' => 0, + ], + ]; + + if ($this->isCiContext() || $this->isLocalDevMode()) { + $projectRoot = $this->getDockerMountSource(getenv('CI_PROJECT_DIR')); + } + else { + $projectRoot = getcwd(); + } + + // Check if SSH auth sockets are supported. + $ssh_auth_sock = getenv('SSH_AUTH_SOCK'); + $options['php']['ssh'] = !empty($ssh_auth_sock); + if ($options['php']['ssh']) { + $options['php']['ssh_auth_sock'] = ($this->isCiContext() || $this->isLocalDevMode()) ? + $this->getDockerMountSource('/ssh-agent') : + '$SSH_AUTH_SOCK'; + } + + $options['projectroot'] = $projectRoot; + return $options; + } + + /** + * {@inheritdoc} + */ + protected function postInit(): void { + $this->env->put('PHP_VERSION', $this->config->readValue('php/version'), TRUE); + } + /** * Configure Drupal Project for Docker. * * @param bool $overwrite * Whether to overwrite existing config files. - * - * @throws \Twig\Error\LoaderError - * @throws \Twig\Error\RuntimeError - * @throws \Twig\Error\SyntaxError */ - public function configureProject($overwrite = FALSE) { + public function configureProject($overwrite = FALSE): void { // We only do the fancy stuff for developers. if (!$this->isDevMode()) { return; } - $options = $this->getOptions(); $fs = new Filesystem(); $installationManager = $this->composer->getInstallationManager(); - if (isset($options['webroot'])) { - if (!$fs->exists($options['webroot'])) { + $webRoot = $this->config->readValue('webroot'); + if ($webRoot !== NULL) { + if (!$fs->exists($webRoot)) { return; } - $webRoot = $options['webroot']; } else { $drupalCorePackage = $this->getDrupalCorePackage(); @@ -78,33 +193,27 @@ class Handler extends BaseHandler { } // Provide all the required files. - $twig_loader = new Twig_Loader_Array([]); - $twig = new Twig_Environment($twig_loader); - $options['webRoot'] = $webRoot . '/'; $orig_ignored = FALSE; - foreach ($this->getFiles($projectRoot, $webRoot, $settingsPath, $options) as $template => $def) { + foreach ($this->getFiles($projectRoot, $webRoot, $settingsPath) as $template => $def) { if (isset($def['condition']) && !$def['condition']) { continue; } if (!$fs->exists($def['dest'])) { $fs->mkdir($def['dest']); } - $twig_loader->setTemplate($template, $template); - $filename = $twig->render($template, $options); + $filename = $this->config->render($template, $template); $file = $def['dest'] . '/' . $filename; if (($overwrite && empty($def['add2git'])) || !$fs->exists($file)) { - $twig_loader->setTemplate($filename, file_get_contents($pluginRoot . '/templates/' . ($def['source'] ?? '') . $template . '.twig')); - $rendered = $twig->render($filename, $options); - if (!empty($def['add2yaml']) && isset($options[$filename])) { + $rendered = $this->config->render($filename, file_get_contents($pluginRoot . '/templates/' . ($def['source'] ?? '') . $template . '.twig')); + $extraOptions = $this->config->readValue($filename); + if (!empty($def['add2yaml']) && $extraOptions !== NULL) { $yaml = Yaml::parse($rendered); /** @noinspection SlowArrayOperationsInLoopInspection */ - $yaml = array_merge_recursive($yaml, $options[$filename]); + $yaml = array_merge_recursive($yaml, $extraOptions); $rendered = Yaml::dump($yaml, 9, 2); // Render the string again so that custom content can also use variables - $twig_loader->setTemplate($filename, $rendered); - $rendered = $twig->render($filename, $options); - + $rendered = $this->config->render($filename, $rendered); } if ($fs->exists($file)) { if (md5_file($file) === md5($rendered)) { @@ -150,7 +259,7 @@ class Handler extends BaseHandler { $this->gitIgnore('tests/backstop/backstop_data/html_report'); $this->gitLFS('tests/backstop/**/*.png'); - $traefik = new Traefik($options['projectname']); + $traefik = new Traefik($this->config->readValue('projectname')); $traefik->update(); // Set permissions, see https://wodby.com/stacks/drupal/docs/local/permissions @@ -167,13 +276,11 @@ class Handler extends BaseHandler { * Name of the web's root directory. * @param string $settingsPath * Name of the settings directory. - * @param array $options - * Keyed array with all current options. * * @return array * List of files. */ - protected function getFiles($projectRoot, $webRoot, $settingsPath, $options): array { + protected function getFiles(string $projectRoot, string $webRoot, string $settingsPath): array { return [ 'settings.docker.php' => [ 'dest' => $projectRoot . '/' . $settingsPath, @@ -205,139 +312,11 @@ class Handler extends BaseHandler { ], 'vhost.conf' => [ 'dest' => $projectRoot . '/apache', - 'condition' => $options['webserver']['overwriteconfig'], + 'condition' => $this->config->readValue('webserver/overwriteconfig'), ], ]; } - /** - * Retrieve options from composer.json "extra" configuration. - * - * @param null $key - * Optional name of an option to be received instead of the full set of options. - * - * @return array|string - * The options. - */ - public function getOptions($key = NULL) { - if ($this->options === NULL) { - $env = new Dotenv('docker4drupal', $this->io); - $projectname = getenv('COMPOSE_PROJECT_NAME'); - if (empty($projectname)) {$projectname = str_replace([' ', '-', '_', '.'], '', basename(getcwd())); - $env->put('COMPOSE_PROJECT_NAME', $projectname); - } - $extra = $this->composer->getPackage()->getExtra() + ['docker4drupal' => []]; - $options = NestedArray::mergeDeep([ - 'projectname' => $projectname, - 'ci_home' => '/home/gitlab-runner', - 'docker0' => [ - 'ip' => ($this->isCiContext() || $this->isLocalDevMode()) ? - $this->getDockerGateway() : - $this->getLocalIpv4('docker0'), - ], - 'live' => [ - 'root' => '', - 'uri' => '', - 'host' => '', - 'user' => $env->receive('live_host_username', 'Remote username for host of the live site', getenv('USER')), - ], - 'drush' => [ - 'sql' => [ - 'tables' => [ - 'structure' => [ - 'cache', - 'cachetags', - 'cache_*', - 'history', - 'search_*', - 'sessions', - 'watchdog', - ], - 'skip' => [ - 'migration_*', - ], - ], - ], - ], - 'drupal' => [ - 'version' => '8', - ], - 'php' => [ - 'version' => $env->receiveGlobal('PHP_VERSION', 'PHP version', '7.3'), - 'xdebug' => $env->receiveGlobal('PHP_DEBUG', 'PHP debug', '0'), - ], - 'webserver' => [ - 'type' => 'apache', - 'overwriteconfig' => FALSE, - ], - 'varnish' => [ - 'enable' => 0, - ], - 'redis' => [ - 'version' => '4.0', - ], - 'dbbrowser' => [ - 'type' => 'pma', - ], - 'solr' => [ - 'enable' => 0, - 'version' => '6.6', - ], - 'node' => [ - 'enable' => 0, - 'key' => '', - 'path' => '', - ], - 'memcached' => [ - 'enable' => 0, - ], - 'rsyslog' => [ - 'enable' => 0, - ], - 'athenapdf' => [ - 'enable' => 0, - 'key' => '', - ], - 'blackfire' => [ - 'enable' => 0, - 'id' => '', - 'token' => '', - ], - 'webgrind' => [ - 'enable' => 0, - ], - 'wkhtmltox' => [ - 'enable' => 0, - ], - ], $extra['docker4drupal']); - - if ($this->isCiContext() || $this->isLocalDevMode()) { - $projectRoot = $this->getDockerMountSource(getenv('CI_PROJECT_DIR')); - } - else { - $projectRoot = getcwd(); - } - - // Check if SSH auth sockets are supported. - $ssh_auth_sock = getenv('SSH_AUTH_SOCK'); - $options['php']['ssh'] = !empty($ssh_auth_sock); - if ($options['php']['ssh']) { - $options['php']['ssh_auth_sock'] = ($this->isCiContext() || $this->isLocalDevMode()) ? - $this->getDockerMountSource('/ssh-agent') : - '$SSH_AUTH_SOCK'; - } - - $options['projectroot'] = $projectRoot; - - $this->options = $env->replaceEnvironmentVariables($options); - $env->put('PHP_VERSION', $this->options['php']['version'], TRUE); - } - if ($key !== NULL) { - return $this->options[$key]; - } - return $this->options; - } - /** * Determine local ipv4 address. * @@ -399,7 +378,10 @@ class Handler extends BaseHandler { return getcwd(); } - private function readContainerConfig() { + /** + * @return array + */ + private function readContainerConfig(): array { try { $output = []; exec('basename "$(cat /proc/1/cpuset)"', $output); diff --git a/src/NestedArray.php b/src/NestedArray.php deleted file mode 100644 index b1be92357c732721d80a428be7f3161ffb418afb..0000000000000000000000000000000000000000 --- a/src/NestedArray.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -namespace LakeDrops\Docker4Drupal; - -/** - * Class NestedArray. - * - * @package LakeDrops\Docker4Drupal - */ -class NestedArray { - - /** - * Deeply merges arrays. Borrowed from drupal.org/project/core. - * - * @return array - * The merged array. - */ - public static function mergeDeep(): array { - return self::mergeDeepArray(func_get_args()); - } - - /** - * Deeply merges arrays. Borrowed from drupal.org/project/core. - * - * @param array $arrays - * An array of array that will be merged. - * @param bool $preserve_integer_keys - * Whether to preserve integer keys. - * - * @return array - * The merged array. - */ - public static function mergeDeepArray(array $arrays, $preserve_integer_keys = FALSE): array { - $result = []; - foreach ($arrays as $array) { - foreach ($array as $key => $value) { - if (is_int($key) && !$preserve_integer_keys) { - $result[] = $value; - } - /** @noinspection NotOptimalIfConditionsInspection */ - elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) { - $result[$key] = self::mergeDeepArray([$result[$key], $value], $preserve_integer_keys); - } - else { - $result[$key] = $value; - } - } - } - return $result; - } - -} diff --git a/src/Plugin.php b/src/Plugin.php index 74e33259afd0f5453510e946423a4a66fa218b3b..2dc896cf9f103019b345f43b2ce192582255d8fe 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -4,6 +4,7 @@ namespace LakeDrops\Docker4Drupal; use Composer\Script\Event; use Composer\Script\ScriptEvents; +use LakeDrops\Component\Composer\BaseHandlerInterface; use LakeDrops\Component\Composer\BasePlugin; /** @@ -14,7 +15,7 @@ class Plugin extends BasePlugin { /** * {@inheritdoc} */ - public function getHandlerClass() { + public function getHandlerClass(): BaseHandlerInterface { return Handler::class; } diff --git a/src/UpdateCommand.php b/src/UpdateCommand.php index 0f2664b5f963e5ab93e90635db2349830c354d35..c5d0e94d096c9836f40ce3669255a7a75d200124 100644 --- a/src/UpdateCommand.php +++ b/src/UpdateCommand.php @@ -3,6 +3,7 @@ namespace LakeDrops\Docker4Drupal; use LakeDrops\Component\Composer\BaseCommand; +use LakeDrops\Component\Composer\BaseHandlerInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -19,7 +20,7 @@ class UpdateCommand extends BaseCommand { /** * {@inheritdoc} */ - public function getHandlerClass() { + public function getHandlerClass(): BaseHandlerInterface { return Handler::class; } @@ -30,11 +31,12 @@ class UpdateCommand extends BaseCommand { * @throws \Twig\Error\RuntimeError * @throws \Twig\Error\SyntaxError */ - protected function execute(InputInterface $input, OutputInterface $output) { + protected function execute(InputInterface $input, OutputInterface $output): int { parent::execute($input, $output); /** @var Handler $handler */ $handler = $this->handler; $handler->configureProject(TRUE); + return 0; } } diff --git a/templates/default.site.yml.twig b/templates/default.site.yml.twig index 9c01c306042c183d117b0388b3218f4aeda63b6e..d6165651d9ad362fe7b639b970ebab52ce394e1b 100644 --- a/templates/default.site.yml.twig +++ b/templates/default.site.yml.twig @@ -1,8 +1,8 @@ dev: - root: '/var/www/html/{{ webRoot }}' + root: '/var/www/html/{{ webRoot }}/' uri: '{{ projectname }}.docker.localhost:8000' behat: - root: '/var/www/html/{{ webRoot }}' + root: '/var/www/html/{{ webRoot }}/' uri: '{{ webserver.type }}' live: root: '{{ live.root }}' diff --git a/templates/docker-compose.yml.twig b/templates/docker-compose.yml.twig index 9848332c6cff8e0ed191de6b6fbf8b07c4ee8d6b..ed79cb16b294e9f66439ec3b8ba26b4c6b2c4e90 100644 --- a/templates/docker-compose.yml.twig +++ b/templates/docker-compose.yml.twig @@ -76,7 +76,7 @@ services: {% endif %} {% endif %} {{ webserver.type|upper }}_BACKEND_HOST: php - {{ webserver.type|upper }}_SERVER_ROOT: /var/www/html/{{ webRoot }} + {{ webserver.type|upper }}_SERVER_ROOT: /var/www/html/{{ webRoot }}/ volumes: - {{ projectroot }}:/var/www/html labels: diff --git a/templates/vhost.conf.twig b/templates/vhost.conf.twig index 43460c420c4308755e9138ceca285a3e6d4e3b4c..07750ae83f2b3290b972c83e34191428596c8609 100644 --- a/templates/vhost.conf.twig +++ b/templates/vhost.conf.twig @@ -1,5 +1,5 @@ <VirtualHost *:80> - DocumentRoot "/var/www/html/{{ webRoot }}" + DocumentRoot "/var/www/html/{{ webRoot }}/" ServerName default Include conf/preset.conf <Location />