BuildSettingsCommand.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?php
  2. declare(strict_types = 1);
  3. namespace Fgm\Drupal\Composer;
  4. use Drupal\Component\Utility\NestedArray;
  5. use Symfony\Component\Console\Input\InputArgument;
  6. use Symfony\Component\Console\Input\InputDefinition;
  7. use Symfony\Component\Console\Input\InputInterface;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use Symfony\Component\Yaml\Exception\ParseException;
  10. use Symfony\Component\Yaml\Yaml;
  11. use Twig\Environment;
  12. use Twig\Extension\DebugExtension;
  13. use Twig\Loader\FilesystemLoader;
  14. use Twig\TemplateWrapper;
  15. class BuildSettingsCommand extends BaseBuilderCommand
  16. {
  17. /**
  18. * @var string
  19. */
  20. protected $eventName;
  21. /**
  22. * {@inheritDoc}
  23. */
  24. public function configure()
  25. {
  26. parent::configure();
  27. $this->eventName = $this->getName();
  28. $this
  29. ->setName('build:settings')
  30. ->setDescription('Step 4: build the *.settings.local.php files.')
  31. ->setDefinition(
  32. new InputDefinition([
  33. new InputArgument(static::ARG_FILE, InputArgument::OPTIONAL),
  34. ])
  35. )
  36. ->setHelp(
  37. <<<EOT
  38. The build:settings command combines shared and per-environment parameters and passes
  39. them to the settings.local.php.twig template to build the settings/(build|run).settings.local.php files.
  40. EOT
  41. );
  42. }
  43. /**
  44. * {@inheritDoc}
  45. */
  46. public function execute(InputInterface $input, OutputInterface $output)
  47. {
  48. [$templateName, $err] = $this->validateTemplateName($input, $output);
  49. if ($err) {
  50. return 1;
  51. };
  52. $settingsPath = $this->getSettingsPath();
  53. $templatePath = "${settingsPath}/${templateName}";
  54. $realTemplatePath = realpath($templatePath);
  55. if (empty($realTemplatePath)) {
  56. $output->writeln(sprintf("Could not load template %s: no such file", $templateName));
  57. return 2;
  58. }
  59. $paramsPath = "${settingsPath}/merged.params.local.yml";
  60. $realParamsPath = realpath($paramsPath);
  61. if (empty($realParamsPath)) {
  62. $output->writeln(sprintf("Could not load parameters %s: no such file", $paramsPath));
  63. return 3;
  64. }
  65. $yaml = new Yaml();
  66. try {
  67. $params = $yaml->parseFile($realParamsPath);
  68. } catch (ParseException $e) {
  69. $output->writeln(sprintf("Could not parse %s: %s", $realParamsPath, $e->getMessage()));
  70. return 4;
  71. }
  72. $loader = new FilesystemLoader($settingsPath, $settingsPath);
  73. $twig = new Environment($loader, [
  74. 'auto_reload' => true,
  75. 'cache' => false,
  76. 'debug' => true,
  77. 'strict_variables' => true,
  78. ]);
  79. $twig->addExtension(new DebugExtension());
  80. $wrapper = $twig->load($templateName);
  81. foreach ($params['sites'] as $name => $siteParams) {
  82. foreach (['build', 'run'] as $stage) {
  83. $stageSettings = NestedArray::mergeDeepArray([
  84. $siteParams['settings']['both'] ?? [],
  85. $siteParams['settings'][$stage] ?? []
  86. ], true);
  87. $stageParams = $siteParams;
  88. $stageParams['settings'] = $stageSettings;
  89. $context = [
  90. 'instance' => $params['instance'],
  91. 'name' => $name,
  92. 'stage' => $stage,
  93. 'site' => $stageParams,
  94. ];
  95. $error = $this->render($wrapper, $context, $output);
  96. if ($error) {
  97. $output->writeln(sprintf("Failed rendering %s settings for site %s", $stage, $name));
  98. return 5;
  99. }
  100. }
  101. }
  102. }
  103. protected function render(TemplateWrapper $wrapper, array $context, OutputInterface $output): int
  104. {
  105. $settingsPath = "web/sites/${context['name']}/${context['stage']}.settings.local.php";
  106. if (file_exists($settingsPath)) {
  107. $ok = unlink($settingsPath);
  108. if (!$ok) {
  109. $output->writeln(sprintf(
  110. "Could not remove old %s file",
  111. $settingsPath
  112. ));
  113. return 1;
  114. }
  115. }
  116. $rendered = $wrapper->render($context);
  117. $ok = file_put_contents($settingsPath, $rendered, LOCK_EX);
  118. if (!$ok) {
  119. $output->writeln(sprintf('Could not write new %s file', $settingsPath));
  120. return 2;
  121. }
  122. return 0;
  123. }
  124. }