Browse Source

BuildSettingsCommand generates web/<site>(build|run).settings.local.php.

Frederic G. MARAND 4 years ago
parent
commit
7eff4c209d

+ 1 - 1
composer.json

@@ -26,6 +26,6 @@
     "squizlabs/php_codesniffer": "^3.0@dev"
   },
   "scripts": {
-    "cs": "phpcs --standard=PSR12 -v src"
+    "cs": "phpcs --standard=PSR1,PSR2 -v src"
   }
 }

+ 7 - 2
src/BaseBuilderCommand.php

@@ -1,9 +1,8 @@
 <?php
-
+declare(strict_types = 1);
 
 namespace Fgm\Drupal\Composer;
 
-
 use Composer\Command\BaseCommand;
 
 abstract class BaseBuilderCommand extends BaseCommand
@@ -14,4 +13,10 @@ abstract class BaseBuilderCommand extends BaseCommand
         $conf = $this->getComposer()->getPackage()->getExtra()[Builder::NAME] ?? [];
         return $conf;
     }
+
+    protected function getSettingsPath(): string
+    {
+        $settingsPath = getcwd() . "/settings";
+        return $settingsPath;
+    }
 }

+ 102 - 6
src/BuildSettingsCommand.php

@@ -1,14 +1,27 @@
 <?php
+declare(strict_types = 1);
 
 namespace Fgm\Drupal\Composer;
 
-use Composer\Command\BaseCommand;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputDefinition;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+use Twig\Environment;
+use Twig\Extension\DebugExtension;
+use Twig\Loader\FilesystemLoader;
+use Twig\TemplateWrapper;
 
 class BuildSettingsCommand extends BaseBuilderCommand
 {
 
+    /**
+     * The name of the argument defining the file to generate.
+     */
+    const ARG_FILE = 'file';
+
     /**
      * @var string
      */
@@ -24,7 +37,11 @@ class BuildSettingsCommand extends BaseBuilderCommand
         $this
             ->setName('build:settings')
             ->setDescription('Builds the *.settings.local.php files.')
-            ->setDefinition([])
+            ->setDefinition(
+                new InputDefinition([
+                new InputArgument(static::ARG_FILE, InputArgument::OPTIONAL),
+                ])
+            )
             ->setHelp(
                 <<<EOT
 The build:settings command combines shared and per-environment parameters and passes
@@ -39,9 +56,88 @@ EOT
      */
     public function execute(InputInterface $input, OutputInterface $output)
     {
-        $messageFormat = empty($this->eventName)
-        ? "BuildSettingsCommand Executed on its own"
-        : "BuildSettingsCommand Executed on \"%s\" event";
-        $output->write(sprintf($messageFormat, $this->eventName), true);
+        $file = $input->getArgument(static::ARG_FILE);
+        $conf = $this->getBuilderConfig();
+        $templateName = $conf['templates'][$file] ?? '';
+        if (empty($templateName)) {
+            $output->writeln(sprintf(
+                'Could not build file %s: no such template in composer.json extra section',
+                $file
+            ));
+            return 1;
+        }
+
+        $settingsPath = $this->getSettingsPath();
+        $templatePath = "${settingsPath}/${templateName}";
+        $realTemplatePath = realpath($templatePath);
+        if (empty($realTemplatePath)) {
+            $output->writeln(sprintf("Could not load template %s: no such file", $templateName));
+            return 2;
+        }
+
+        $paramsPath = "${settingsPath}/merged.params.local.yml";
+        $realParamsPath = realpath($paramsPath);
+        if (empty($realTemplatePath)) {
+            $output->writeln(sprintf("Could not load parameters %s: no such file", $paramsPath));
+            return 3;
+        }
+
+        $yaml = new Yaml();
+        try {
+            $params = $yaml->parseFile($realParamsPath);
+        } catch (ParseException $e) {
+            $output->writeln(sprintf("Could not parse %s: %s", $realParamsPath, $e->getMessage()));
+            return 4;
+        }
+
+        $loader = new FilesystemLoader($settingsPath, $settingsPath);
+        $twig = new Environment($loader, [
+          'auto_reload' => true,
+          'cache' => false,
+          'debug' => true,
+          'strict_variables' => true,
+        ]);
+        $twig->addExtension(new DebugExtension());
+
+        $wrapper = $twig->load($templateName);
+        foreach ($params['sites'] as $name => $siteParams) {
+            foreach (['build', 'run'] as $stage) {
+                $context = [
+                  'instance' => $params['instance'],
+                  'name' => $name,
+                  'stage' => $stage,
+                  'site' => $siteParams,
+                ];
+                $error = $this->render($wrapper, $context, $output);
+                if ($error) {
+                    $output->writeln(sprintf("Failed rendering %s settings for site %s", $stage, $name));
+                    return 5;
+                }
+            }
+        }
+    }
+
+    protected function render(TemplateWrapper $wrapper, array $context, OutputInterface $output): int
+    {
+        $settingsPath = "web/sites/${context['name']}/${context['stage']}.settings.local.php";
+        if (file_exists($settingsPath)) {
+            $ok = unlink($settingsPath);
+            if (!$ok) {
+                $output->writeln(sprintf(
+                    "Could not remove old %s file",
+                    $settingsPath
+                ));
+                return 1;
+            }
+        }
+
+        $rendered = $wrapper->render($context);
+        $ok = file_put_contents($settingsPath, $rendered, LOCK_EX);
+        if (!$ok) {
+            $output->writeln(sprintf('Could not write new %s file', $settingsPath));
+            return 2;
+        }
+
+        return 0;
     }
 }

+ 4 - 2
src/Builder.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types = 1);
 
 namespace Fgm\Drupal\Composer;
 
@@ -90,8 +91,9 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
             ]
         )
         ) {
-            $buildCommand = new BuildSettingsCommand($event->getName());
-            $buildCommand->run(new ArgvInput([]), new ConsoleOutput());
+          // FIXME add behavior where, without an argument, the command will build all templates.
+          // $buildCommand = new BuildSettingsCommand($event->getName());
+          // $buildCommand->run(new ArgvInput([]), new ConsoleOutput());
         }
     }
 }

+ 1 - 1
src/BuilderCommandProvider.php

@@ -1,8 +1,8 @@
 <?php
+declare(strict_types = 1);
 
 namespace Fgm\Drupal\Composer;
 
-
 use Composer\Plugin\Capability\CommandProvider;
 
 class BuilderCommandProvider implements CommandProvider

+ 2 - 1
src/MergeParamsCommand.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types = 1);
 
 namespace Fgm\Drupal\Composer;
 
@@ -60,7 +61,7 @@ EOT
    */
     public function execute(InputInterface $input, OutputInterface $output)
     {
-        $settingsPath = getcwd() . "/settings/";
+        $settingsPath = $this->getSettingsPath();
         $yaml = new Yaml();
 
         // Load defaults.